From 18d4eb3eda54ee4addb42d4e68039f2016305233 Mon Sep 17 00:00:00 2001 From: daurnimator Date: Sun, 21 May 2017 21:58:58 +1000 Subject: tests/test-suite/goto.js: Now passes --- README.md | 2 +- tests/test-suite/goto.js | 366 ++++++++++++++++++++++++++++++++++++ tests/test-suite/inprogress/goto.js | 366 ------------------------------------ 3 files changed, 367 insertions(+), 367 deletions(-) create mode 100644 tests/test-suite/goto.js delete mode 100644 tests/test-suite/inprogress/goto.js diff --git a/README.md b/README.md index e0e4686..f29642f 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,7 @@ IRC: #fengari on freenode - [x] `closure.lua` (16/16) - [x] `constructs.lua` (`_soft`) (10/10) - [x] `events.lua` (26/26) + - [x] `goto.lua` (18/18) - [x] `literals.lua` (30/30) - [x] `locals.lua` (10/10) - [x] `nextvar.lua` (44/44) @@ -66,7 +67,6 @@ IRC: #fengari on freenode - [x] `vararg.lua` (8/8) - [ ] `coroutine.lua` (32/40) - [ ] `errors.lua` (46/64) - - [ ] `goto.lua` (16/18) - [ ] `math.lua` (44/68) - [ ] `pm.lua` (27/38) - [ ] `sort.lua` (21/24) diff --git a/tests/test-suite/goto.js b/tests/test-suite/goto.js new file mode 100644 index 0000000..c07541e --- /dev/null +++ b/tests/test-suite/goto.js @@ -0,0 +1,366 @@ +"use strict"; + +const test = require('tape'); + +global.WEB = false; + +const lua = require('../../src/lua.js'); +const lauxlib = require('../../src/lauxlib.js'); +const lualib = require('../../src/lualib.js'); + + +test("[test-suite] goto: error messages", function (t) { + let luaCode = ` + local function errmsg (code, m) + local st, msg = load(code) + assert(not st and string.find(msg, m)) + end + + -- cannot see label inside block + errmsg([[ goto l1; do ::l1:: end ]], "label 'l1'") + errmsg([[ do ::l1:: end goto l1; ]], "label 'l1'") + + -- repeated label + errmsg([[ ::l1:: ::l1:: ]], "label 'l1'") + + + -- undefined label + errmsg([[ goto l1; local aa ::l1:: ::l2:: print(3) ]], "local 'aa'") + + -- jumping over variable definition + errmsg([[ + do local bb, cc; goto l1; end + local aa + ::l1:: print(3) + ]], "local 'aa'") + + -- jumping into a block + errmsg([[ do ::l1:: end goto l1 ]], "label 'l1'") + errmsg([[ goto l1 do ::l1:: end ]], "label 'l1'") + + -- cannot continue a repeat-until with variables + errmsg([[ + repeat + if x then goto cont end + local xuxu = 10 + ::cont:: + until xuxu < x + ]], "local 'xuxu'") + `, L; + + t.plan(2); + + t.doesNotThrow(function () { + + L = lauxlib.luaL_newstate(); + + lualib.luaL_openlibs(L); + + lauxlib.luaL_loadstring(L, lua.to_luastring(luaCode)); + + }, "Lua program loaded without error"); + + t.doesNotThrow(function () { + + lua.lua_call(L, 0, -1); + + }, "Lua program ran without error"); + +}); + + +test("[test-suite] goto", function (t) { + let luaCode = ` + -- simple gotos + local x + do + local y = 12 + goto l1 + ::l2:: x = x + 1; goto l3 + ::l1:: x = y; goto l2 + end + ::l3:: ::l3_1:: assert(x == 13) + + -- long labels + do + local prog = [[ + do + local a = 1 + goto l%sa; a = a + 1 + ::l%sa:: a = a + 10 + goto l%sb; a = a + 2 + ::l%sb:: a = a + 20 + return a + end + ]] + local label = string.rep("0123456789", 40) + prog = string.format(prog, label, label, label, label) + assert(assert(load(prog))() == 31) + end + + -- goto to correct label when nested + do goto l3; ::l3:: end -- does not loop jumping to previous label 'l3' + + -- ok to jump over local dec. to end of block + do + goto l1 + local a = 23 + x = a + ::l1::; + end + + while true do + goto l4 + goto l1 -- ok to jump over local dec. to end of block + goto l1 -- multiple uses of same label + local x = 45 + ::l1:: ;;; + end + ::l4:: assert(x == 13) + + if print then + goto l1 -- ok to jump over local dec. to end of block + error("should not be here") + goto l2 -- ok to jump over local dec. to end of block + local x + ::l1:: ; ::l2:: ;; + else end + `, L; + + t.plan(2); + + t.doesNotThrow(function () { + + L = lauxlib.luaL_newstate(); + + lualib.luaL_openlibs(L); + + lauxlib.luaL_loadstring(L, lua.to_luastring(luaCode)); + + }, "Lua program loaded without error"); + + t.doesNotThrow(function () { + + lua.lua_call(L, 0, -1); + + }, "Lua program ran without error"); + +}); + + +test("[test-suite] goto: to repeat a label in a different function is OK", function (t) { + let luaCode = ` + local function foo () + local a = {} + goto l3 + ::l1:: a[#a + 1] = 1; goto l2; + ::l2:: a[#a + 1] = 2; goto l5; + ::l3:: + ::l3a:: a[#a + 1] = 3; goto l1; + ::l4:: a[#a + 1] = 4; goto l6; + ::l5:: a[#a + 1] = 5; goto l4; + ::l6:: assert(a[1] == 3 and a[2] == 1 and a[3] == 2 and + a[4] == 5 and a[5] == 4) + if not a[6] then a[6] = true; goto l3a end -- do it twice + end + + ::l6:: foo() + `, L; + + t.plan(2); + + t.doesNotThrow(function () { + + L = lauxlib.luaL_newstate(); + + lualib.luaL_openlibs(L); + + lauxlib.luaL_loadstring(L, lua.to_luastring(luaCode)); + + }, "Lua program loaded without error"); + + t.doesNotThrow(function () { + + lua.lua_call(L, 0, -1); + + }, "Lua program ran without error"); + +}); + + +test("[test-suite] goto: bug in 5.2 -> 5.3.2", function (t) { + let luaCode = ` + do -- bug in 5.2 -> 5.3.2 + local x + ::L1:: + local y -- cannot join this SETNIL with previous one + assert(y == nil) + y = true + if x == nil then + x = 1 + goto L1 + else + x = x + 1 + end + assert(x == 2 and y == true) + end + `, L; + + t.plan(2); + + t.doesNotThrow(function () { + + L = lauxlib.luaL_newstate(); + + lualib.luaL_openlibs(L); + + lauxlib.luaL_loadstring(L, lua.to_luastring(luaCode)); + + }, "Lua program loaded without error"); + + t.doesNotThrow(function () { + + lua.lua_call(L, 0, -1); + + }, "Lua program ran without error"); + +}); + + +test("[test-suite] goto: testing closing of upvalues", function (t) { + let luaCode = ` + local function foo () + local t = {} + do + local i = 1 + local a, b, c, d + t[1] = function () return a, b, c, d end + ::l1:: + local b + do + local c + t[#t + 1] = function () return a, b, c, d end -- t[2], t[4], t[6] + if i > 2 then goto l2 end + do + local d + t[#t + 1] = function () return a, b, c, d end -- t[3], t[5] + i = i + 1 + local a + goto l1 + end + end + end + ::l2:: return t + end + + local a = foo() + assert(#a == 6) + + -- all functions share same 'a' + for i = 2, 6 do + assert(debug.upvalueid(a[1], 1) == debug.upvalueid(a[i], 1)) + end + + -- 'b' and 'c' are shared among some of them + for i = 2, 6 do + -- only a[1] uses external 'b'/'b' + assert(debug.upvalueid(a[1], 2) ~= debug.upvalueid(a[i], 2)) + assert(debug.upvalueid(a[1], 3) ~= debug.upvalueid(a[i], 3)) + end + + for i = 3, 5, 2 do + -- inner functions share 'b'/'c' with previous ones + assert(debug.upvalueid(a[i], 2) == debug.upvalueid(a[i - 1], 2)) + assert(debug.upvalueid(a[i], 3) == debug.upvalueid(a[i - 1], 3)) + -- but not with next ones + assert(debug.upvalueid(a[i], 2) ~= debug.upvalueid(a[i + 1], 2)) + assert(debug.upvalueid(a[i], 3) ~= debug.upvalueid(a[i + 1], 3)) + end + + -- only external 'd' is shared + for i = 2, 6, 2 do + assert(debug.upvalueid(a[1], 4) == debug.upvalueid(a[i], 4)) + end + + -- internal 'd's are all different + for i = 3, 5, 2 do + for j = 1, 6 do + assert((debug.upvalueid(a[i], 4) == debug.upvalueid(a[j], 4)) + == (i == j)) + end + end + `, L; + + t.plan(2); + + t.doesNotThrow(function () { + + L = lauxlib.luaL_newstate(); + + lualib.luaL_openlibs(L); + + lauxlib.luaL_loadstring(L, lua.to_luastring(luaCode)); + + }, "Lua program loaded without error"); + + t.doesNotThrow(function () { + + lua.lua_call(L, 0, -1); + + }, "Lua program ran without error"); + +}); + + +test("[test-suite] goto: testing if x goto optimizations", function (t) { + let luaCode = ` + local function testG (a) + if a == 1 then + goto l1 + error("should never be here!") + elseif a == 2 then goto l2 + elseif a == 3 then goto l3 + elseif a == 4 then + goto l1 -- go to inside the block + error("should never be here!") + ::l1:: a = a + 1 -- must go to 'if' end + else + goto l4 + ::l4a:: a = a * 2; goto l4b + error("should never be here!") + ::l4:: goto l4a + error("should never be here!") + ::l4b:: + end + do return a end + ::l2:: do return "2" end + ::l3:: do return "3" end + ::l1:: return "1" + end + + assert(testG(1) == "1") + assert(testG(2) == "2") + assert(testG(3) == "3") + assert(testG(4) == 5) + assert(testG(5) == 10) + `, L; + + t.plan(2); + + t.doesNotThrow(function () { + + L = lauxlib.luaL_newstate(); + + lualib.luaL_openlibs(L); + + lauxlib.luaL_loadstring(L, lua.to_luastring(luaCode)); + + }, "Lua program loaded without error"); + + t.doesNotThrow(function () { + + lua.lua_call(L, 0, -1); + + }, "Lua program ran without error"); + +}); diff --git a/tests/test-suite/inprogress/goto.js b/tests/test-suite/inprogress/goto.js deleted file mode 100644 index c392264..0000000 --- a/tests/test-suite/inprogress/goto.js +++ /dev/null @@ -1,366 +0,0 @@ -"use strict"; - -const test = require('tape'); - -global.WEB = false; - -const lua = require('../../../src/lua.js'); -const lauxlib = require('../../../src/lauxlib.js'); -const lualib = require('../../../src/lualib.js'); - - -test("[test-suite] goto: error messages", function (t) { - let luaCode = ` - local function errmsg (code, m) - local st, msg = load(code) - assert(not st and string.find(msg, m)) - end - - -- cannot see label inside block - errmsg([[ goto l1; do ::l1:: end ]], "label 'l1'") - errmsg([[ do ::l1:: end goto l1; ]], "label 'l1'") - - -- repeated label - errmsg([[ ::l1:: ::l1:: ]], "label 'l1'") - - - -- undefined label - errmsg([[ goto l1; local aa ::l1:: ::l2:: print(3) ]], "local 'aa'") - - -- jumping over variable definition - errmsg([[ - do local bb, cc; goto l1; end - local aa - ::l1:: print(3) - ]], "local 'aa'") - - -- jumping into a block - errmsg([[ do ::l1:: end goto l1 ]], "label 'l1'") - errmsg([[ goto l1 do ::l1:: end ]], "label 'l1'") - - -- cannot continue a repeat-until with variables - errmsg([[ - repeat - if x then goto cont end - local xuxu = 10 - ::cont:: - until xuxu < x - ]], "local 'xuxu'") - `, L; - - t.plan(2); - - t.doesNotThrow(function () { - - L = lauxlib.luaL_newstate(); - - lualib.luaL_openlibs(L); - - lauxlib.luaL_loadstring(L, lua.to_luastring(luaCode)); - - }, "Lua program loaded without error"); - - t.doesNotThrow(function () { - - lua.lua_call(L, 0, -1); - - }, "Lua program ran without error"); - -}); - - -test("[test-suite] goto", function (t) { - let luaCode = ` - -- simple gotos - local x - do - local y = 12 - goto l1 - ::l2:: x = x + 1; goto l3 - ::l1:: x = y; goto l2 - end - ::l3:: ::l3_1:: assert(x == 13) - - -- long labels - do - local prog = [[ - do - local a = 1 - goto l%sa; a = a + 1 - ::l%sa:: a = a + 10 - goto l%sb; a = a + 2 - ::l%sb:: a = a + 20 - return a - end - ]] - local label = string.rep("0123456789", 40) - prog = string.format(prog, label, label, label, label) - assert(assert(load(prog))() == 31) - end - - -- goto to correct label when nested - do goto l3; ::l3:: end -- does not loop jumping to previous label 'l3' - - -- ok to jump over local dec. to end of block - do - goto l1 - local a = 23 - x = a - ::l1::; - end - - while true do - goto l4 - goto l1 -- ok to jump over local dec. to end of block - goto l1 -- multiple uses of same label - local x = 45 - ::l1:: ;;; - end - ::l4:: assert(x == 13) - - if print then - goto l1 -- ok to jump over local dec. to end of block - error("should not be here") - goto l2 -- ok to jump over local dec. to end of block - local x - ::l1:: ; ::l2:: ;; - else end - `, L; - - t.plan(2); - - t.doesNotThrow(function () { - - L = lauxlib.luaL_newstate(); - - lualib.luaL_openlibs(L); - - lauxlib.luaL_loadstring(L, lua.to_luastring(luaCode)); - - }, "Lua program loaded without error"); - - t.doesNotThrow(function () { - - lua.lua_call(L, 0, -1); - - }, "Lua program ran without error"); - -}); - - -test("[test-suite] goto: to repeat a label in a different function is OK", function (t) { - let luaCode = ` - local function foo () - local a = {} - goto l3 - ::l1:: a[#a + 1] = 1; goto l2; - ::l2:: a[#a + 1] = 2; goto l5; - ::l3:: - ::l3a:: a[#a + 1] = 3; goto l1; - ::l4:: a[#a + 1] = 4; goto l6; - ::l5:: a[#a + 1] = 5; goto l4; - ::l6:: assert(a[1] == 3 and a[2] == 1 and a[3] == 2 and - a[4] == 5 and a[5] == 4) - if not a[6] then a[6] = true; goto l3a end -- do it twice - end - - ::l6:: foo() - `, L; - - t.plan(2); - - t.doesNotThrow(function () { - - L = lauxlib.luaL_newstate(); - - lualib.luaL_openlibs(L); - - lauxlib.luaL_loadstring(L, lua.to_luastring(luaCode)); - - }, "Lua program loaded without error"); - - t.doesNotThrow(function () { - - lua.lua_call(L, 0, -1); - - }, "Lua program ran without error"); - -}); - - -test("[test-suite] goto: bug in 5.2 -> 5.3.2", function (t) { - let luaCode = ` - do -- bug in 5.2 -> 5.3.2 - local x - ::L1:: - local y -- cannot join this SETNIL with previous one - assert(y == nil) - y = true - if x == nil then - x = 1 - goto L1 - else - x = x + 1 - end - assert(x == 2 and y == true) - end - `, L; - - t.plan(2); - - t.doesNotThrow(function () { - - L = lauxlib.luaL_newstate(); - - lualib.luaL_openlibs(L); - - lauxlib.luaL_loadstring(L, lua.to_luastring(luaCode)); - - }, "Lua program loaded without error"); - - t.doesNotThrow(function () { - - lua.lua_call(L, 0, -1); - - }, "Lua program ran without error"); - -}); - - -test("[test-suite] goto: testing closing of upvalues", function (t) { - let luaCode = ` - local function foo () - local t = {} - do - local i = 1 - local a, b, c, d - t[1] = function () return a, b, c, d end - ::l1:: - local b - do - local c - t[#t + 1] = function () return a, b, c, d end -- t[2], t[4], t[6] - if i > 2 then goto l2 end - do - local d - t[#t + 1] = function () return a, b, c, d end -- t[3], t[5] - i = i + 1 - local a - goto l1 - end - end - end - ::l2:: return t - end - - local a = foo() - assert(#a == 6) - - -- all functions share same 'a' - for i = 2, 6 do - assert(debug.upvalueid(a[1], 1) == debug.upvalueid(a[i], 1)) - end - - -- 'b' and 'c' are shared among some of them - for i = 2, 6 do - -- only a[1] uses external 'b'/'b' - assert(debug.upvalueid(a[1], 2) ~= debug.upvalueid(a[i], 2)) - assert(debug.upvalueid(a[1], 3) ~= debug.upvalueid(a[i], 3)) - end - - for i = 3, 5, 2 do - -- inner functions share 'b'/'c' with previous ones - assert(debug.upvalueid(a[i], 2) == debug.upvalueid(a[i - 1], 2)) - assert(debug.upvalueid(a[i], 3) == debug.upvalueid(a[i - 1], 3)) - -- but not with next ones - assert(debug.upvalueid(a[i], 2) ~= debug.upvalueid(a[i + 1], 2)) - assert(debug.upvalueid(a[i], 3) ~= debug.upvalueid(a[i + 1], 3)) - end - - -- only external 'd' is shared - for i = 2, 6, 2 do - assert(debug.upvalueid(a[1], 4) == debug.upvalueid(a[i], 4)) - end - - -- internal 'd's are all different - for i = 3, 5, 2 do - for j = 1, 6 do - assert((debug.upvalueid(a[i], 4) == debug.upvalueid(a[j], 4)) - == (i == j)) - end - end - `, L; - - t.plan(2); - - t.doesNotThrow(function () { - - L = lauxlib.luaL_newstate(); - - lualib.luaL_openlibs(L); - - lauxlib.luaL_loadstring(L, lua.to_luastring(luaCode)); - - }, "Lua program loaded without error"); - - t.doesNotThrow(function () { - - lua.lua_call(L, 0, -1); - - }, "Lua program ran without error"); - -}); - - -test("[test-suite] goto: testing if x goto optimizations", function (t) { - let luaCode = ` - local function testG (a) - if a == 1 then - goto l1 - error("should never be here!") - elseif a == 2 then goto l2 - elseif a == 3 then goto l3 - elseif a == 4 then - goto l1 -- go to inside the block - error("should never be here!") - ::l1:: a = a + 1 -- must go to 'if' end - else - goto l4 - ::l4a:: a = a * 2; goto l4b - error("should never be here!") - ::l4:: goto l4a - error("should never be here!") - ::l4b:: - end - do return a end - ::l2:: do return "2" end - ::l3:: do return "3" end - ::l1:: return "1" - end - - assert(testG(1) == "1") - assert(testG(2) == "2") - assert(testG(3) == "3") - assert(testG(4) == 5) - assert(testG(5) == 10) - `, L; - - t.plan(2); - - t.doesNotThrow(function () { - - L = lauxlib.luaL_newstate(); - - lualib.luaL_openlibs(L); - - lauxlib.luaL_loadstring(L, lua.to_luastring(luaCode)); - - }, "Lua program loaded without error"); - - t.doesNotThrow(function () { - - lua.lua_call(L, 0, -1); - - }, "Lua program ran without error"); - -}); -- cgit v1.2.3-70-g09d2