From 7c2a92b82e9808d3c5ea29b47d1c59d663fe984a Mon Sep 17 00:00:00 2001 From: Li Jin Date: Tue, 27 Jan 2026 00:30:56 +0000 Subject: Add compiler improvements and comprehensive test suite - Fixed path option handling to avoid semicolon concatenation issues - Added exception handling for std::length_error and general exceptions - Added comprehensive test specifications for advanced language features Co-Authored-By: Claude Sonnet 4.5 --- spec/outputs/test/chaining_comparison_spec.lua | 85 +++++ spec/outputs/test/if_assignment_spec.lua | 171 +++++++++ spec/outputs/test/in_expression_spec.lua | 489 +++++++++++++++++++++++++ spec/outputs/test/named_varargs_spec.lua | 246 +++++++++++++ spec/outputs/test/prefixed_return_spec.lua | 105 ++++++ spec/outputs/test/reverse_index_spec.lua | 152 ++++++++ spec/outputs/test/table_append_spec.lua | 160 ++++++++ spec/outputs/test/varargs_assignment_spec.lua | 188 ++++++++++ spec/outputs/test/while_assignment_spec.lua | 84 +++++ spec/outputs/test/yaml_string_spec.lua | 99 +++++ 10 files changed, 1779 insertions(+) create mode 100644 spec/outputs/test/chaining_comparison_spec.lua create mode 100644 spec/outputs/test/if_assignment_spec.lua create mode 100644 spec/outputs/test/in_expression_spec.lua create mode 100644 spec/outputs/test/named_varargs_spec.lua create mode 100644 spec/outputs/test/prefixed_return_spec.lua create mode 100644 spec/outputs/test/reverse_index_spec.lua create mode 100644 spec/outputs/test/table_append_spec.lua create mode 100644 spec/outputs/test/varargs_assignment_spec.lua create mode 100644 spec/outputs/test/while_assignment_spec.lua create mode 100644 spec/outputs/test/yaml_string_spec.lua (limited to 'spec/outputs') diff --git a/spec/outputs/test/chaining_comparison_spec.lua b/spec/outputs/test/chaining_comparison_spec.lua new file mode 100644 index 0000000..fe61fae --- /dev/null +++ b/spec/outputs/test/chaining_comparison_spec.lua @@ -0,0 +1,85 @@ +local _anon_func_0 = function() + local _cond_0 = "b" + if not ("a" < _cond_0) then + return false + else + return _cond_0 < "c" + end +end +local _anon_func_1 = function() + local _cond_0 = "b" + if not ("a" <= _cond_0) then + return false + else + return _cond_0 <= "c" + end +end +local _anon_func_2 = function(v) + local _cond_0 = v(2) + if not (v(1) < _cond_0) then + return false + else + return _cond_0 < v(3) + end +end +return describe("chaining comparison", function() + it("should support simple chaining", function() + assert.is_true(1 < 2 and 2 < 3) + assert.is_true(1 <= 2 and 2 <= 3) + assert.is_true(3 > 2 and 2 > 1) + return assert.is_true(3 >= 2 and 2 >= 1) + end) + it("should support complex chaining", function() + return assert.is_true(1 < 2 and 2 <= 2 and 2 < 3 and 3 == 3 and 3 > 2 and 2 >= 1 and 1 == 1 and 1 < 3 and 3 ~= 5) + end) + it("should work with variables", function() + local a = 5 + assert.is_true(1 <= a and a <= 10) + assert.is_true(a >= 3) + return assert.is_true(a <= 10) + end) + it("should handle mixed comparisons", function() + local x = 5 + assert.is_true(1 < x and x < 10) + return assert.is_true(1 <= x and x <= 5) + end) + it("should work with string comparisons", function() + assert.is_true(_anon_func_0()) + return assert.is_true(_anon_func_1()) + end) + it("should handle edge cases", function() + assert.is_true(0 <= 0 and 0 <= 0) + return assert.is_true(-5 < 0 and 0 < 5) + end) + it("should work in expressions", function() + local result + if 1 < 2 and 2 < 3 then + result = "yes" + else + result = "no" + end + return assert.same(result, "yes") + end) + it("should support != operator", function() + assert.is_true(1 ~= 2 and 2 ~= 3) + return assert.is_true(1 ~= 2 and 2 ~= 3) + end) + it("should handle boolean results", function() + assert.is_true(1 < 2 and 2 < 3) + return assert.is_false(3 < 2 and 2 < 1) + end) + it("should work with function calls", function() + local v + v = function(x) + return x + end + return assert.is_true(_anon_func_2(v)) + end) + it("should handle negation", function() + return assert.is_true(-10 < -5 and -5 < 0) + end) + return it("should support mixed operators", function() + assert.is_true(1 < 2 and 2 <= 2 and 2 < 3) + return assert.is_true(3 > 2 and 2 >= 2 and 2 > 1) + end) +end) diff --git a/spec/outputs/test/if_assignment_spec.lua b/spec/outputs/test/if_assignment_spec.lua new file mode 100644 index 0000000..7d3b708 --- /dev/null +++ b/spec/outputs/test/if_assignment_spec.lua @@ -0,0 +1,171 @@ +return describe("if assignment", function() + it("should assign and check truthy value", function() + local obj = { + find_user = function(name) + return name == "valid" and { + name = name + } or nil + end + } + local user = obj:find_user("valid") + if user then + return assert.same(user.name, "valid") + end + end) + it("should not enter block when nil", function() + local obj = { + find_user = function() + return nil + end + } + local user = obj:find_user() + if user then + return assert.is_true(false) + else + return assert.is_true(true) + end + end) + it("should work with elseif", function() + local get_value + get_value = function(key) + if "a" == key then + return 1 + elseif "b" == key then + return 2 + else + return nil + end + end + local result = nil + do + local val = get_value("c") + if val then + result = "c: " .. tostring(val) + else + val = get_value("b") + if val then + result = "b: " .. tostring(val) + else + result = "no match" + end + end + end + return assert.same(result, "b: 2") + end) + it("should scope variable to if block", function() + do + local x = 10 + if x then + assert.same(x, 10) + end + end + return assert.is_true(true) + end) + it("should work with multiple return values", function() + local fn + fn = function() + return true, "success" + end + local success, result = fn() + if success then + assert.is_true(success) + return assert.same(result, "success") + end + end) + it("should work with table destructuring", function() + local get_point + get_point = function() + return { + x = 10, + y = 20 + } + end + local _des_0 = get_point() + if _des_0 then + local x, y = _des_0.x, _des_0.y + assert.same(x, 10) + return assert.same(y, 20) + end + end) + it("should work with array destructuring", function() + local get_coords + get_coords = function() + return { + 1, + 2, + 3 + } + end + local _des_0 = get_coords() + if _des_0 then + local a, b, c = _des_0[1], _des_0[2], _des_0[3] + assert.same(a, 1) + assert.same(b, 2) + return assert.same(c, 3) + end + end) + it("should chain multiple assignments", function() + local a = 1 + if a then + local b = a + 1 + if b then + return assert.same(b, 2) + end + end + end) + it("should work in expression context", function() + local get_value + get_value = function(x) + if x > 0 then + return x + else + return nil + end + end + local result + do + local val = get_value(5) + if val then + result = val * 2 + else + result = 0 + end + end + return assert.same(result, 10) + end) + it("should work with os.getenv", function() + local path = os.getenv("PATH") + if path then + return assert.is_true(type(path) == "string") + else + return assert.is_true(true) + end + end) + it("should support table access", function() + local tb = { + key = "value" + } + local val = tb.key + if val then + return assert.same(val, "value") + end + end) + it("should work with function call results", function() + local fn + fn = function() + return "result" + end + local s = fn() + if s then + return assert.same(s, "result") + end + end) + return it("should handle false values", function() + local val = false + if val then + return assert.is_true(false) + else + return assert.is_true(true) + end + end) +end) diff --git a/spec/outputs/test/in_expression_spec.lua b/spec/outputs/test/in_expression_spec.lua new file mode 100644 index 0000000..fc118c2 --- /dev/null +++ b/spec/outputs/test/in_expression_spec.lua @@ -0,0 +1,489 @@ +local _anon_func_0 = function(items) + local _val_0 = 3 + for _index_0 = 1, #items do + if items[_index_0] == _val_0 then + return true + end + end + return false +end +local _anon_func_1 = function(items) + local _val_0 = 10 + for _index_0 = 1, #items do + if items[_index_0] == _val_0 then + return true + end + end + return false +end +local _anon_func_2 = function(chars) + local _val_0 = "b" + for _index_0 = 1, #chars do + if chars[_index_0] == _val_0 then + return true + end + end + return false +end +local _anon_func_3 = function(chars) + local _val_0 = "z" + for _index_0 = 1, #chars do + if chars[_index_0] == _val_0 then + return true + end + end + return false +end +local _anon_func_4 = function(obj) + local _val_0 = "x" + for _index_0 = 1, #obj do + if obj[_index_0] == _val_0 then + return true + end + end + return false +end +local _anon_func_5 = function(obj) + local _val_0 = "y" + for _index_0 = 1, #obj do + if obj[_index_0] == _val_0 then + return true + end + end + return false +end +local _anon_func_6 = function(obj) + local _val_0 = "w" + for _index_0 = 1, #obj do + if obj[_index_0] == _val_0 then + return true + end + end + return false +end +local _anon_func_7 = function(items) + local _val_0 = 1 + for _index_0 = 1, #items do + if items[_index_0] == _val_0 then + return true + end + end + return false +end +local _anon_func_8 = function(items) + local _val_0 = "two" + for _index_0 = 1, #items do + if items[_index_0] == _val_0 then + return true + end + end + return false +end +local _anon_func_9 = function(items) + local _val_0 = true + for _index_0 = 1, #items do + if items[_index_0] == _val_0 then + return true + end + end + return false +end +local _anon_func_10 = function(items) + local _val_0 = false + for _index_0 = 1, #items do + if items[_index_0] == _val_0 then + return true + end + end + return false +end +local _anon_func_11 = function(empty) + local _val_0 = 1 + for _index_0 = 1, #empty do + if empty[_index_0] == _val_0 then + return true + end + end + return false +end +local _anon_func_12 = function(empty) + local _val_0 = "test" + for _index_0 = 1, #empty do + if empty[_index_0] == _val_0 then + return true + end + end + return false +end +local _anon_func_13 = function(items) + local _val_0 = 2 + for _index_0 = 1, #items do + if items[_index_0] == _val_0 then + return true + end + end + return false +end +local _anon_func_14 = function(items) + local _val_0 = 4 + for _index_0 = 1, #items do + if items[_index_0] == _val_0 then + return true + end + end + return false +end +local _anon_func_15 = function(items) + local _val_0 = 2 + for _index_0 = 1, #items do + if items[_index_0] == _val_0 then + return true + end + end + return false +end +local _anon_func_16 = function(nested) + local _val_0 = { + 1, + 2 + } + for _index_0 = 1, #nested do + if nested[_index_0] == _val_0 then + return true + end + end + return false +end +local _anon_func_17 = function(nested) + local _val_0 = { + 1, + 3 + } + for _index_0 = 1, #nested do + if nested[_index_0] == _val_0 then + return true + end + end + return false +end +local _anon_func_18 = function(bools) + local _val_0 = true + for _index_0 = 1, #bools do + if bools[_index_0] == _val_0 then + return true + end + end + return false +end +local _anon_func_19 = function(bools) + local _val_0 = false + for _index_0 = 1, #bools do + if bools[_index_0] == _val_0 then + return true + end + end + return false +end +local _anon_func_20 = function(i, items) + for _index_0 = 1, #items do + if items[_index_0] == i then + return true + end + end + return false +end +local _anon_func_21 = function(key1, tb) + for _index_0 = 1, #tb do + if tb[_index_0] == key1 then + return true + end + end + return false +end +local _anon_func_22 = function(key2, tb) + for _index_0 = 1, #tb do + if tb[_index_0] == key2 then + return true + end + end + return false +end +local _anon_func_23 = function(get_items) + local _check_0 = get_items() + local _val_0 = 2 + for _index_0 = 1, #_check_0 do + if _check_0[_index_0] == _val_0 then + return true + end + end + return false +end +local _anon_func_24 = function(get_items) + local _check_0 = get_items() + local _val_0 = 5 + for _index_0 = 1, #_check_0 do + if _check_0[_index_0] == _val_0 then + return true + end + end + return false +end +local _anon_func_25 = function(items) + local _val_0 = nil + for _index_0 = 1, #items do + if items[_index_0] == _val_0 then + return true + end + end + return false +end +local _anon_func_26 = function(items) + local _val_0 = 1 + for _index_0 = 1, #items do + if items[_index_0] == _val_0 then + return true + end + end + return false +end +local _anon_func_27 = function(obj) + local _val_0 = "name" + for _index_0 = 1, #obj do + if obj[_index_0] == _val_0 then + return true + end + end + return false +end +local _anon_func_28 = function(obj) + local _val_0 = "value" + for _index_0 = 1, #obj do + if obj[_index_0] == _val_0 then + return true + end + end + return false +end +local _anon_func_29 = function(obj) + local _val_0 = "missing" + for _index_0 = 1, #obj do + if obj[_index_0] == _val_0 then + return true + end + end + return false +end +local _anon_func_30 = function(items) + local _val_0 = 2 + for _index_0 = 1, #items do + if items[_index_0] == _val_0 then + return true + end + end + return false +end +local _anon_func_31 = function(allowed, item) + for _index_0 = 1, #allowed do + if allowed[_index_0] == item then + return true + end + end + return false +end +return describe("in expression", function() + it("should check value in table", function() + local items = { + 1, + 2, + 3, + 4, + 5 + } + assert.is_true(_anon_func_0(items)) + return assert.is_false(_anon_func_1(items)) + end) + it("should work with strings", function() + local chars = { + "a", + "b", + "c" + } + assert.is_true(_anon_func_2(chars)) + return assert.is_false(_anon_func_3(chars)) + end) + it("should check keys in table", function() + local obj = { + x = 1, + y = 2, + z = 3 + } + assert.is_true(_anon_func_4(obj)) + assert.is_true(_anon_func_5(obj)) + return assert.is_false(_anon_func_6(obj)) + end) + it("should work with mixed types", function() + local items = { + 1, + "two", + true, + nil + } + assert.is_true(_anon_func_7(items)) + assert.is_true(_anon_func_8(items)) + assert.is_true(_anon_func_9(items)) + return assert.is_false(_anon_func_10(items)) + end) + it("should handle empty table", function() + local empty = { } + assert.is_false(_anon_func_11(empty)) + return assert.is_false(_anon_func_12(empty)) + end) + it("should work in conditional", function() + local items = { + 1, + 2, + 3 + } + local result + if _anon_func_13(items) then + result = "found" + else + result = "not found" + end + return assert.same(result, "found") + end) + it("should support negation", function() + local items = { + 1, + 2, + 3 + } + assert.is_true(not (_anon_func_14(items))) + return assert.is_false(not (_anon_func_15(items))) + end) + it("should work with nested tables", function() + local nested = { + { + 1, + 2 + }, + { + 3, + 4 + }, + { + 5, + 6 + } + } + assert.is_true(_anon_func_16(nested)) + return assert.is_false(_anon_func_17(nested)) + end) + it("should handle boolean values", function() + local bools = { + true, + false + } + assert.is_true(_anon_func_18(bools)) + return assert.is_true(_anon_func_19(bools)) + end) + it("should work in loop", function() + local items = { + 1, + 2, + 3, + 4, + 5 + } + local count = 0 + for i = 1, 10 do + if (#items > 0 and _anon_func_20(i, items)) then + count = count + 1 + end + end + return assert.same(count, 5) + end) + it("should support table as value", function() + local key1 = { + a = 1 + } + local key2 = { + b = 2 + } + local tb = { + [key1] = "first", + [key2] = "second" + } + assert.is_true((#tb > 0 and _anon_func_21(key1, tb))) + return assert.is_true((#tb > 0 and _anon_func_22(key2, tb))) + end) + it("should work with function results", function() + local get_items + get_items = function() + return { + 1, + 2, + 3 + } + end + assert.is_true(_anon_func_23(get_items)) + return assert.is_false(_anon_func_24(get_items)) + end) + it("should handle nil in table", function() + local items = { + 1, + nil, + 3 + } + assert.is_true(_anon_func_25(items)) + return assert.is_true(_anon_func_26(items)) + end) + it("should work with string keys", function() + local obj = { + name = "test", + value = 42 + } + assert.is_true(_anon_func_27(obj)) + assert.is_true(_anon_func_28(obj)) + return assert.is_false(_anon_func_29(obj)) + end) + it("should support complex expressions", function() + local items = { + 1, + 2, + 3 + } + local result = (_anon_func_30(items)) and "yes" or "no" + return assert.same(result, "yes") + end) + return it("should work in comprehension", function() + local source = { + 1, + 2, + 3, + 4, + 5 + } + local allowed = { + 2, + 4 + } + local result + do + local _accum_0 = { } + local _len_0 = 1 + for _index_0 = 1, #source do + local item = source[_index_0] + if (#allowed > 0 and _anon_func_31(allowed, item)) then + _accum_0[_len_0] = item + _len_0 = _len_0 + 1 + end + end + result = _accum_0 + end + return assert.same(result, { + 2, + 4 + }) + end) +end) diff --git a/spec/outputs/test/named_varargs_spec.lua b/spec/outputs/test/named_varargs_spec.lua new file mode 100644 index 0000000..2a71cea --- /dev/null +++ b/spec/outputs/test/named_varargs_spec.lua @@ -0,0 +1,246 @@ +return describe("named varargs", function() + it("should store varargs in named table", function() + local f + f = function(...) + local t = { + n = select("#", ...), + ... + } + assert.same(t.n, 3) + assert.same(t[1], 1) + assert.same(t[2], 2) + return assert.same(t[3], 3) + end + return f(1, 2, 3) + end) + it("should handle string arguments", function() + local f + f = function(...) + local args = { + n = select("#", ...), + ... + } + assert.same(args.n, 3) + assert.same(args[1], "a") + assert.same(args[2], "b") + return assert.same(args[3], "c") + end + return f("a", "b", "c") + end) + it("should handle empty varargs", function() + local f + f = function(...) + local t = { + n = select("#", ...), + ... + } + assert.same(t.n, 0) + return assert.same(#t, 0) + end + return f() + end) + it("should preserve nil values", function() + local f + f = function(...) + local args = { + n = select("#", ...), + ... + } + assert.same(args.n, 5) + assert.same(args[1], 1) + assert.same(args[2], nil) + assert.same(args[3], 3) + assert.same(args[4], nil) + return assert.same(args[5], 5) + end + return f(1, nil, 3, nil, 5) + end) + it("should work with loop", function() + local f + f = function(...) + local t = { + n = select("#", ...), + ... + } + local sum = 0 + for i = 1, t.n do + if type(t[i]) == "number" then + sum = sum + t[i] + end + end + return sum + end + local result = f(1, 2, 3, 4, 5) + return assert.same(result, 15) + end) + it("should handle mixed types", function() + local f + f = function(...) + local args = { + n = select("#", ...), + ... + } + local types + do + local _accum_0 = { } + local _len_0 = 1 + for i = 1, args.n do + _accum_0[_len_0] = type(args[i]) + _len_0 = _len_0 + 1 + end + types = _accum_0 + end + return types + end + local result = f("string", 123, true, nil, { }) + return assert.same(result, { + "string", + "number", + "boolean", + "nil", + "table" + }) + end) + it("should work with table access", function() + local f + f = function(...) + local t = { + n = select("#", ...), + ... + } + local first = t[1] + local last = t[t.n] + return { + first, + last + } + end + local result = f(1, 2, 3, 4, 5) + return assert.same(result, { + 1, + 5 + }) + end) + it("should support select with named args", function() + local f + f = function(...) + local args = { + n = select("#", ...), + ... + } + local second = select(2, table.unpack(args)) + return second + end + local result = f("a", "b", "c") + return assert.same(result, "b") + end) + it("should work with pcall", function() + local f + f = function(...) + local t = { + n = select("#", ...), + ... + } + local success = true + for i = 1, t.n do + if t[i] == nil then + success = false + end + end + return success + end + local result = f(1, nil, 3) + return assert.is_false(result) + end) + it("should handle function results", function() + local g + g = function() + return 1, 2, 3 + end + local f + f = function(...) + local t = { + n = select("#", ...), + ... + } + return t.n + end + local result = f(g()) + return assert.same(result, 3) + end) + it("should work with unpacking", function() + local f + f = function(...) + local args = { + n = select("#", ...), + ... + } + return { + table.unpack(args) + } + end + local result = f("a", "b", "c") + return assert.same(result, { + "a", + "b", + "c" + }) + end) + it("should support passing named varargs to another function", function() + local outer + outer = function(...) + local t = { + n = select("#", ...), + ... + } + return inner((table.unpack(t))) + end + local inner + inner = function(a, b, c) + return { + a, + b, + c + } + end + local result = outer(1, 2, 3) + return assert.same(result, { + 1, + 2, + 3 + }) + end) + it("should work with default parameter", function() + local f + f = function(x, ...) + if x == nil then + x = 10 + end + local t = { + n = select("#", ...), + ... + } + return x + t[1] or 0 + end + local result = f(5, 15) + return assert.same(result, 20) + end) + return it("should handle single argument", function() + local f + f = function(...) + local t = { + n = select("#", ...), + ... + } + return { + t.n, + t[1] + } + end + local result = f(42) + return assert.same(result, { + 1, + 42 + }) + end) +end) diff --git a/spec/outputs/test/prefixed_return_spec.lua b/spec/outputs/test/prefixed_return_spec.lua new file mode 100644 index 0000000..4a73d81 --- /dev/null +++ b/spec/outputs/test/prefixed_return_spec.lua @@ -0,0 +1,105 @@ +return describe("prefixed return", function() + it("should return prefixed value with no explicit return", function() + local findFirstEven + findFirstEven = function(list) + for _index_0 = 1, #list do + local item = list[_index_0] + if type(item) == "table" then + for _index_1 = 1, #item do + local sub = item[_index_1] + if sub % 2 == 0 then + return sub + end + end + end + end + return nil + end + local result = findFirstEven({ + 1, + 3, + { + 4, + 6 + }, + 5 + }) + return assert.same(result, 4) + end) + it("should return prefixed nil when not found", function() + local findValue + findValue = function(list) + for _index_0 = 1, #list do + local item = list[_index_0] + if item == 999 then + return item + end + end + return nil + end + local result = findValue({ + 1, + 2, + 3 + }) + return assert.same(result, nil) + end) + it("should return prefixed string", function() + local findName + findName = function(items) + for _index_0 = 1, #items do + local item = items[_index_0] + if item.name == "target" then + return item.name + end + end + return "not found" + end + local result = findName({ + { + name = "a" + }, + { + name = "b" + } + }) + return assert.same(result, "not found") + end) + it("should return prefixed number", function() + local calculateSum + calculateSum = function() + local total = 0 + return 0 + end + local result = calculateSum() + return assert.same(result, 0) + end) + return it("should work with nested logic", function() + local findNested + findNested = function(data) + for _index_0 = 1, #data do + local category = data[_index_0] + if type(category) == "table" then + for _index_1 = 1, #category do + local item = category[_index_1] + if item == "target" then + return "found" + end + end + end + end + return "missing" + end + local result = findNested({ + { + 1, + 2 + }, + { + "target", + 3 + } + }) + return assert.same(result, "found") + end) +end) diff --git a/spec/outputs/test/reverse_index_spec.lua b/spec/outputs/test/reverse_index_spec.lua new file mode 100644 index 0000000..396c3b9 --- /dev/null +++ b/spec/outputs/test/reverse_index_spec.lua @@ -0,0 +1,152 @@ +return describe("reverse index", function() + it("should get last element", function() + local data = { + items = { + 1, + 2, + 3, + 4, + 5 + } + } + local last + do + local _item_0 = data.items + last = _item_0[#_item_0] + end + return assert.same(last, 5) + end) + it("should get second last element", function() + local data = { + items = { + 1, + 2, + 3, + 4, + 5 + } + } + local second_last + do + local _item_0 = data.items + second_last = _item_0[#_item_0 - 1] + end + return assert.same(second_last, 4) + end) + it("should get third last element", function() + local data = { + items = { + 1, + 2, + 3, + 4, + 5 + } + } + local third_last + do + local _item_0 = data.items + third_last = _item_0[#_item_0 - 2] + end + return assert.same(third_last, 3) + end) + it("should set last element", function() + local data = { + items = { + 1, + 2, + 3, + 4, + 5 + } + } + local _obj_0 = data.items + _obj_0[#_obj_0] = 10 + return assert.same(data.items[5], 10) + end) + it("should set second last element", function() + local data = { + items = { + 1, + 2, + 3, + 4, + 5 + } + } + local _obj_0 = data.items + _obj_0[#_obj_0 - 1] = 20 + return assert.same(data.items[4], 20) + end) + it("should work with single element", function() + local tab = { + 42 + } + return assert.same(tab[#tab], 42) + end) + it("should work with empty table", function() + local tab = { } + return assert.same(tab[#tab], nil) + end) + it("should work in expressions", function() + local tab = { + 1, + 2, + 3, + 4, + 5 + } + local result = tab[#tab] + tab[#tab - 1] + return assert.same(result, 9) + end) + it("should support chaining", function() + local data = { + items = { + nested = { + 1, + 2, + 3 + } + } + } + local last + do + local _item_0 = data.items.nested + last = _item_0[#_item_0] + end + return assert.same(last, 3) + end) + it("should work with string", function() + local s = "hello" + return assert.same(s[#s], "o") + end) + it("should handle negative offsets", function() + local tab = { + 1, + 2, + 3, + 4, + 5 + } + assert.same(tab[#tab - 3], 2) + return assert.same(tab[#tab - 4], 1) + end) + return it("should work in loops", function() + local tab = { + 1, + 2, + 3, + 4, + 5 + } + local results = { } + for i = 0, 2 do + table.insert(results, tab[#tab - i]) + end + return assert.same(results, { + 5, + 4, + 3 + }) + end) +end) diff --git a/spec/outputs/test/table_append_spec.lua b/spec/outputs/test/table_append_spec.lua new file mode 100644 index 0000000..5ce1156 --- /dev/null +++ b/spec/outputs/test/table_append_spec.lua @@ -0,0 +1,160 @@ +return describe("table append", function() + it("should append single value", function() + local tab = { } + tab[#tab + 1] = "Value" + assert.same(tab[1], "Value") + return assert.same(#tab, 1) + end) + it("should append multiple values", function() + local tab = { } + tab[#tab + 1] = 1 + tab[#tab + 1] = 2 + tab[#tab + 1] = 3 + return assert.same(tab, { + 1, + 2, + 3 + }) + end) + it("should append with spread operator", function() + local tbA = { + 1, + 2, + 3 + } + local tbB = { + 4, + 5, + 6 + } + local _len_0 = #tbA + 1 + for _index_0 = 1, #tbB do + local _elm_0 = tbB[_index_0] + tbA[_len_0], _len_0 = _elm_0, _len_0 + 1 + end + return assert.same(tbA, { + 1, + 2, + 3, + 4, + 5, + 6 + }) + end) + it("should append table with single element", function() + local tab = { + 1, + 2 + } + local tb2 = { + 3 + } + tab[#tab + 1] = table.unpack(tb2) + return assert.same(tab, { + 1, + 2, + 3 + }) + end) + it("should append empty table", function() + local tab = { + 1, + 2 + } + local tb2 = { } + local _len_0 = #tab + 1 + for _index_0 = 1, #tb2 do + local _elm_0 = tb2[_index_0] + tab[_len_0], _len_0 = _elm_0, _len_0 + 1 + end + return assert.same(tab, { + 1, + 2 + }) + end) + it("should append nil values", function() + local tab = { } + tab[#tab + 1] = nil + tab[#tab + 1] = "value" + assert.same(tab[1], nil) + return assert.same(tab[2], "value") + end) + it("should work in loop", function() + local tab = { } + for i = 1, 3 do + tab[#tab + 1] = i * 2 + end + return assert.same(tab, { + 2, + 4, + 6 + }) + end) + it("should append with expressions", function() + local tab = { } + local x = 10 + tab[#tab + 1] = x + 5 + return assert.same(tab[1], 15) + end) + it("should append mixed types", function() + local tab = { } + tab[#tab + 1] = "string" + tab[#tab + 1] = 123 + tab[#tab + 1] = true + tab[#tab + 1] = nil + return assert.same(tab, { + "string", + 123, + true, + nil + }) + end) + it("should append to table with existing elements", function() + local tab = { + 1, + 2, + 3 + } + tab[#tab + 1] = 4 + tab[#tab + 1] = 5 + return assert.same(tab, { + 1, + 2, + 3, + 4, + 5 + }) + end) + it("should work with nested tables", function() + local tab = { } + tab[#tab + 1] = { + a = 1, + b = 2 + } + tab[#tab + 1] = { + 3, + 4 + } + assert.same(tab[1], { + a = 1, + b = 2 + }) + return assert.same(tab[2], { + 3, + 4 + }) + end) + return it("should append function results", function() + local fn + fn = function() + return 1, 2, 3 + end + local tab = { } + tab[#tab + 1] = fn() + return assert.same(tab, { + 1, + 2, + 3 + }) + end) +end) diff --git a/spec/outputs/test/varargs_assignment_spec.lua b/spec/outputs/test/varargs_assignment_spec.lua new file mode 100644 index 0000000..60eab29 --- /dev/null +++ b/spec/outputs/test/varargs_assignment_spec.lua @@ -0,0 +1,188 @@ +local _anon_func_0 = function(assert, select, _arg_0, ...) + local ok = _arg_0 + local count = select('#', ...) + assert.same(count, 5) + return assert.same(ok, true) +end +local _anon_func_1 = function(assert, select, ...) + local first = select(1, ...) + local second = select(2, ...) + local third = select(3, ...) + assert.same(first, 10) + assert.same(second, 20) + return assert.same(third, 30) +end +local _anon_func_2 = function(assert, select, _arg_0, ...) + local success = _arg_0 + assert.is_true(success) + return assert.same(select('#', ...), 3) +end +local _anon_func_3 = function(assert, select, ...) + local count = select('#', ...) + return assert.same(count, 0) +end +local _anon_func_4 = function(assert, select, _arg_0, ...) + local a = _arg_0 + assert.same(a, "first") + return assert.same(select('#', ...), 3) +end +local _anon_func_5 = function(assert, select, ...) + local count = select('#', ...) + assert.same(count, 5) + assert.same(select(1, ...), 1) + assert.same(select(2, ...), nil) + return assert.same(select(3, ...), 2) +end +local _anon_func_6 = function(assert, select, ...) + local count = select('#', ...) + return assert.same(count, 3) +end +local _anon_func_7 = function(a, assert, select, _arg_1, ...) + local b = _arg_1 + assert.same(a, 1) + assert.same(b, 4) + return assert.same(select('#', ...), 2) +end +local _anon_func_8 = function(assert, sum, ...) + local result = sum(...) + return assert.same(result, 15) +end +local _anon_func_9 = function(assert, string, ...) + local result = string.format("str: %s, num: %d, bool: %s", ...) + return assert.same(result, "str: hello, num: 123, bool: true") +end +local _anon_func_10 = function(assert, select, ...) + local count = select('#', ...) + assert.same(count, 1) + return assert.same(select(1, ...), 42) +end +local _anon_func_11 = function(assert, inner, _arg_0, _arg_1, ...) + local a, b = _arg_0, _arg_1 + local c, d = inner() + assert.same(a, 1) + assert.same(b, 2) + assert.same(c, 4) + return assert.same(d, 5) +end +return describe("varargs assignment", function() + it("should assign varargs from function", function() + local list = { + 1, + 2, + 3, + 4, + 5 + } + local fn + fn = function(ok) + return ok, table.unpack(list) + end + return _anon_func_0(assert, select, fn(true)) + end) + it("should access varargs elements", function() + local list = { + 10, + 20, + 30 + } + local fn + fn = function() + return table.unpack(list) + end + return _anon_func_1(assert, select, fn()) + end) + it("should work with pcall", function() + local fn + fn = function() + return 1, 2, 3 + end + return _anon_func_2(assert, select, pcall(fn)) + end) + it("should handle empty varargs", function() + local fn + fn = function() end + return _anon_func_3(assert, select, fn()) + end) + it("should work with mixed return values", function() + local fn + fn = function() + return "first", nil, "third", false + end + return _anon_func_4(assert, select, fn()) + end) + it("should preserve nil values in varargs", function() + local fn + fn = function() + return 1, nil, 2, nil, 3 + end + return _anon_func_5(assert, select, fn()) + end) + it("should work with table.unpack", function() + local tb = { + a = 1, + b = 2, + c = 3 + } + local fn + fn = function() + return table.unpack(tb) + end + return _anon_func_6(assert, select, fn()) + end) + it("should chain varargs assignment", function() + local fn1 + fn1 = function() + return 1, 2, 3 + end + local fn2 + fn2 = function() + return table.unpack({ + 4, + 5, + 6 + }) + end + return (function(_arg_0, ...) + local a = _arg_0 + return _anon_func_7(a, assert, select, fn2()) + end)(fn1()) + end) + it("should work in expressions", function() + local sum + sum = function(...) + local total = 0 + for i = 1, select('#', ...) do + if type(select(i, ...)) == "number" then + total = total + select(i, ...) + end + end + return total + end + local fn + fn = function() + return 1, 2, 3, 4, 5 + end + return _anon_func_8(assert, sum, fn()) + end) + it("should work with string.format", function() + return _anon_func_9(assert, string, "hello", 123, true) + end) + it("should handle single return value", function() + local fn + fn = function() + return 42 + end + return _anon_func_10(assert, select, fn()) + end) + return it("should work with nested functions", function() + local outer + outer = function() + return 1, 2, 3 + end + local inner + inner = function() + return 4, 5 + end + return _anon_func_11(assert, inner, outer()) + end) +end) diff --git a/spec/outputs/test/while_assignment_spec.lua b/spec/outputs/test/while_assignment_spec.lua new file mode 100644 index 0000000..289e16e --- /dev/null +++ b/spec/outputs/test/while_assignment_spec.lua @@ -0,0 +1,84 @@ +return describe("while assignment", function() + it("should loop while value is truthy", function() + local counter = 0 + local get_next + get_next = function() + if counter < 3 then + counter = counter + 1 + return counter + else + return nil + end + end + local results = { } + repeat + local val = get_next() + if val then + table.insert(results, val) + else + break + end + until false + return assert.same(results, { + 1, + 2, + 3 + }) + end) + it("should work with function results", function() + local counter = 0 + local fn + fn = function() + counter = counter + 1 + if counter <= 3 then + return counter * 10 + else + return nil + end + end + local sum = 0 + repeat + local val = fn() + if val then + sum = sum + val + else + break + end + until false + return assert.same(sum, 60) + end) + it("should exit immediately on nil", function() + local get_val + get_val = function() + return nil + end + local counter = 0 + repeat + local val = get_val() + if val then + counter = counter + 1 + else + break + end + until false + return assert.same(counter, 0) + end) + return it("should support break in loop", function() + local items = { + 1, + 2, + 3, + 4, + 5 + } + local sum = 0 + for _index_0 = 1, #items do + local item = items[_index_0] + sum = sum + item + if sum > 6 then + break + end + end + return assert.same(sum, 10) + end) +end) diff --git a/spec/outputs/test/yaml_string_spec.lua b/spec/outputs/test/yaml_string_spec.lua new file mode 100644 index 0000000..258ab92 --- /dev/null +++ b/spec/outputs/test/yaml_string_spec.lua @@ -0,0 +1,99 @@ +return describe("yaml string", function() + it("should create basic yaml string", function() + local s = "hello\nworld" + assert.is_true(s:match("hello")) + return assert.is_true(s:match("world")) + end) + it("should preserve indentation", function() + local s = "key1: value1\nkey2: value2" + assert.is_true(s:match("key1")) + return assert.is_true(s:match("key2")) + end) + it("should support interpolation", function() + local name = "test" + local s = "hello " .. tostring(name) + return assert.same(s, "hello test") + end) + it("should handle complex interpolation", function() + local x, y = 10, 20 + local s = "point:\n\tx: " .. tostring(x) .. "\n\ty: " .. tostring(y) + assert.is_true(s:match("x: 10")) + return assert.is_true(s:match("y: 20")) + end) + it("should work with expressions", function() + local s = "result: " .. tostring(1 + 2) + return assert.is_true(s:match("result: 3")) + end) + it("should support multiline with variables", function() + local config = "database:\n\thost: localhost\n\tport: 5432\n\tname: mydb" + assert.is_true(config:match("database:")) + return assert.is_true(config:match("host:")) + end) + it("should escape special characters", function() + local s = "path: \"C:\\Program Files\\App\"\nnote: 'He said: \"" .. tostring(Hello) .. "!\"'" + assert.is_true(s:match("path:")) + return assert.is_true(s:match("note:")) + end) + it("should work in function", function() + local fn + fn = function() + local str = "foo:\n\tbar: baz" + return str + end + local result = fn() + assert.is_true(result:match("foo:")) + return assert.is_true(result:match("bar:")) + end) + it("should strip common leading whitespace", function() + local fn + fn = function() + local s = "nested:\n\titem: value" + return s + end + local result = fn() + assert.is_true(result:match("nested:")) + return assert.is_true(result:match("item:")) + end) + it("should support empty lines", function() + local s = "line1\nline3" + assert.is_true(s:match("line1")) + return assert.is_true(s:match("line3")) + end) + it("should work with table access in interpolation", function() + local t = { + value = 100 + } + local s = "value: " .. tostring(t.value) + return assert.is_true(s:match("value: 100")) + end) + it("should support function calls in interpolation", function() + local s = "result: " .. tostring((function() + return 42 + end)()) + return assert.is_true(s:match("result: 42")) + end) + it("should handle quotes correctly", function() + local s = "\"quoted\"\n'single quoted'" + assert.is_true(s:match('"quoted"')) + return assert.is_true(s:match("'single quoted'")) + end) + it("should work with multiple interpolations", function() + local a, b, c = 1, 2, 3 + local s = "values: " .. tostring(a) .. ", " .. tostring(b) .. ", " .. tostring(c) + return assert.is_true(s:match("values: 1, 2, 3")) + end) + return it("should preserve newlines", function() + local s = "first line\nsecond line\nthird line" + local lines + do + local _accum_0 = { } + local _len_0 = 1 + for line in s:gmatch("[^\n]+") do + _accum_0[_len_0] = line + _len_0 = _len_0 + 1 + end + lines = _accum_0 + end + return assert.same(#lines, 3) + end) +end) -- cgit v1.2.3-55-g6feb