diff options
Diffstat (limited to 'spec/inputs/test')
| -rw-r--r-- | spec/inputs/test/attrib_spec.yue | 51 | ||||
| -rw-r--r-- | spec/inputs/test/backcall_spec.yue | 29 | ||||
| -rw-r--r-- | spec/inputs/test/cond_spec.yue | 148 | ||||
| -rw-r--r-- | spec/inputs/test/config_spec.yue | 106 | ||||
| -rw-r--r-- | spec/inputs/test/existential_spec.yue | 100 | ||||
| -rw-r--r-- | spec/inputs/test/export_spec.yue | 99 | ||||
| -rw-r--r-- | spec/inputs/test/goto_spec.yue | 80 | ||||
| -rw-r--r-- | spec/inputs/test/import_spec.yue | 115 | ||||
| -rw-r--r-- | spec/inputs/test/literals_spec.yue | 81 | ||||
| -rw-r--r-- | spec/inputs/test/macro_spec.yue | 135 | ||||
| -rw-r--r-- | spec/inputs/test/metatable_spec.yue | 86 | ||||
| -rw-r--r-- | spec/inputs/test/operators_spec.yue | 137 | ||||
| -rw-r--r-- | spec/inputs/test/return_spec.yue | 85 | ||||
| -rw-r--r-- | spec/inputs/test/string_spec.yue | 143 | ||||
| -rw-r--r-- | spec/inputs/test/switch_spec.yue | 267 | ||||
| -rw-r--r-- | spec/inputs/test/vararg_spec.yue | 69 | ||||
| -rw-r--r-- | spec/inputs/test/with_spec.yue | 104 |
17 files changed, 1835 insertions, 0 deletions
diff --git a/spec/inputs/test/attrib_spec.yue b/spec/inputs/test/attrib_spec.yue new file mode 100644 index 0000000..4a1fcab --- /dev/null +++ b/spec/inputs/test/attrib_spec.yue | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | describe "attrib", -> | ||
| 2 | it "should support const attribute", -> | ||
| 3 | do | ||
| 4 | const x = 10 | ||
| 5 | assert.same x, 10 | ||
| 6 | |||
| 7 | it "should support const with multiple variables", -> | ||
| 8 | do | ||
| 9 | const a, b, c = 1, 2, 3 | ||
| 10 | assert.same a, 1 | ||
| 11 | assert.same b, 2 | ||
| 12 | assert.same c, 3 | ||
| 13 | |||
| 14 | it "should support close attribute", -> | ||
| 15 | -- close attribute for to-be-closed variables | ||
| 16 | do | ||
| 17 | close x = 1 | ||
| 18 | assert.same x, 1 | ||
| 19 | |||
| 20 | it "should work with destructuring", -> | ||
| 21 | do | ||
| 22 | const {a, b} = {a: 1, b: 2} | ||
| 23 | assert.same a, 1 | ||
| 24 | assert.same b, 2 | ||
| 25 | |||
| 26 | it "should work in conditional", -> | ||
| 27 | do | ||
| 28 | flag = true | ||
| 29 | const x = 5 if flag | ||
| 30 | assert.same x, 5 | ||
| 31 | |||
| 32 | it "should work with switch", -> | ||
| 33 | do | ||
| 34 | const y = switch 2 | ||
| 35 | when 2 then 100 | ||
| 36 | else 0 | ||
| 37 | assert.same y, 100 | ||
| 38 | |||
| 39 | it "should work with table literals", -> | ||
| 40 | do | ||
| 41 | const [a, b] = [1, 2] | ||
| 42 | assert.same a, 1 | ||
| 43 | assert.same b, 2 | ||
| 44 | |||
| 45 | it "should support close in expressions", -> | ||
| 46 | do | ||
| 47 | close result = if true | ||
| 48 | 42 | ||
| 49 | else | ||
| 50 | 0 | ||
| 51 | assert.same result, 42 | ||
diff --git a/spec/inputs/test/backcall_spec.yue b/spec/inputs/test/backcall_spec.yue new file mode 100644 index 0000000..9534e7c --- /dev/null +++ b/spec/inputs/test/backcall_spec.yue | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | describe "backcall", -> | ||
| 2 | it "should support basic backcall with <-", -> | ||
| 3 | results = {} | ||
| 4 | mock_map = (list, fn) -> | ||
| 5 | for item in *list | ||
| 6 | table.insert results, fn(item) | ||
| 7 | (x) <- mock_map {1, 2, 3} | ||
| 8 | x * 2 | ||
| 9 | assert.same results, {2, 4, 6} | ||
| 10 | |||
| 11 | it "should support nested backcalls", -> | ||
| 12 | results = {} | ||
| 13 | mock_map = (list, fn) -> | ||
| 14 | for item in *list | ||
| 15 | fn(item) | ||
| 16 | mock_map {1, 2, 3, 4}, (x) -> | ||
| 17 | if x > 2 | ||
| 18 | table.insert results, x | ||
| 19 | assert.same results, {3, 4} | ||
| 20 | |||
| 21 | it "should work with method call backcall", -> | ||
| 22 | results = {} | ||
| 23 | obj = { | ||
| 24 | process: (self, fn) -> | ||
| 25 | fn 42 | ||
| 26 | } | ||
| 27 | (value) <- obj\process | ||
| 28 | table.insert results, value | ||
| 29 | assert.same results, {42} | ||
diff --git a/spec/inputs/test/cond_spec.yue b/spec/inputs/test/cond_spec.yue new file mode 100644 index 0000000..9c7cac7 --- /dev/null +++ b/spec/inputs/test/cond_spec.yue | |||
| @@ -0,0 +1,148 @@ | |||
| 1 | describe "cond", -> | ||
| 2 | it "should execute if branch when condition is true", -> | ||
| 3 | result = nil | ||
| 4 | if true | ||
| 5 | result = "yes" | ||
| 6 | assert.same result, "yes" | ||
| 7 | |||
| 8 | it "should execute else branch when condition is false", -> | ||
| 9 | result = nil | ||
| 10 | if false | ||
| 11 | result = "yes" | ||
| 12 | else | ||
| 13 | result = "no" | ||
| 14 | assert.same result, "no" | ||
| 15 | |||
| 16 | it "should support elseif chain", -> | ||
| 17 | value = 2 | ||
| 18 | result = switch value | ||
| 19 | when 1 then "one" | ||
| 20 | when 2 then "two" | ||
| 21 | else "other" | ||
| 22 | assert.same result, "two" | ||
| 23 | |||
| 24 | it "should handle nested conditions", -> | ||
| 25 | result = nil | ||
| 26 | if true | ||
| 27 | if true | ||
| 28 | result = "nested" | ||
| 29 | assert.same result, "nested" | ||
| 30 | |||
| 31 | it "should work as expression", -> | ||
| 32 | value = if true then "yes" else "no" | ||
| 33 | assert.same value, "yes" | ||
| 34 | |||
| 35 | it "should work in string interpolation", -> | ||
| 36 | flag = true | ||
| 37 | result = "value is #{if flag then 1 else 0}" | ||
| 38 | assert.same result, "value is 1" | ||
| 39 | |||
| 40 | it "should support chained comparisons", -> | ||
| 41 | assert.is_true 1 < 2 <= 2 < 3 | ||
| 42 | |||
| 43 | it "should short-circuit and expression", -> | ||
| 44 | count = 0 | ||
| 45 | inc = -> | ||
| 46 | count += 1 | ||
| 47 | false | ||
| 48 | result = inc! and inc! | ||
| 49 | assert.same count, 1 | ||
| 50 | |||
| 51 | it "should short-circuit or expression", -> | ||
| 52 | count = 0 | ||
| 53 | inc = -> | ||
| 54 | count += 1 | ||
| 55 | true | ||
| 56 | result = inc! or inc! | ||
| 57 | assert.same count, 1 | ||
| 58 | |||
| 59 | it "should support unless keyword", -> | ||
| 60 | result = nil | ||
| 61 | unless false | ||
| 62 | result = "executed" | ||
| 63 | assert.same result, "executed" | ||
| 64 | |||
| 65 | it "should support unless with else", -> | ||
| 66 | result = nil | ||
| 67 | unless true | ||
| 68 | result = "no" | ||
| 69 | else | ||
| 70 | result = "yes" | ||
| 71 | assert.same result, "yes" | ||
| 72 | |||
| 73 | it "should handle postfix if", -> | ||
| 74 | result = nil | ||
| 75 | result = "yes" if true | ||
| 76 | assert.same result, "yes" | ||
| 77 | |||
| 78 | it "should handle postfix unless", -> | ||
| 79 | result = nil | ||
| 80 | result = "yes" unless false | ||
| 81 | assert.same result, "yes" | ||
| 82 | |||
| 83 | it "should evaluate truthiness correctly", -> | ||
| 84 | -- nil and false are falsy | ||
| 85 | assert.is_false if nil then true else false | ||
| 86 | assert.is_false if false then true else false | ||
| 87 | |||
| 88 | -- Everything else is truthy | ||
| 89 | assert.is_true if 0 then true else false | ||
| 90 | assert.is_true if "" then true else false | ||
| 91 | assert.is_true if {} then true else false | ||
| 92 | assert.is_true if 1 then true else false | ||
| 93 | |||
| 94 | it "should support and/or operators", -> | ||
| 95 | assert.same true and false, false | ||
| 96 | assert.same false or true, true | ||
| 97 | assert.same nil or "default", "default" | ||
| 98 | assert.same "value" or "default", "value" | ||
| 99 | |||
| 100 | it "should handle complex boolean expressions", -> | ||
| 101 | a, b, c = true, false, true | ||
| 102 | result = a and b or c | ||
| 103 | assert.same result, c | ||
| 104 | |||
| 105 | it "should support not operator", -> | ||
| 106 | assert.is_true not false | ||
| 107 | assert.is_true not nil | ||
| 108 | assert.is_false not true | ||
| 109 | assert.is_false not 1 | ||
| 110 | |||
| 111 | it "should work with table as condition", -> | ||
| 112 | result = nil | ||
| 113 | if {} | ||
| 114 | result = "truthy" | ||
| 115 | assert.same result, "truthy" | ||
| 116 | |||
| 117 | it "should work with string as condition", -> | ||
| 118 | result = nil | ||
| 119 | if "" | ||
| 120 | result = "truthy" | ||
| 121 | assert.same result, "truthy" | ||
| 122 | |||
| 123 | it "should work with zero as condition", -> | ||
| 124 | result = nil | ||
| 125 | if 0 | ||
| 126 | result = "truthy" | ||
| 127 | assert.same result, "truthy" | ||
| 128 | |||
| 129 | it "should support multiple elseif branches", -> | ||
| 130 | value = 3 | ||
| 131 | result = if value == 1 | ||
| 132 | "one" | ||
| 133 | elseif value == 2 | ||
| 134 | "two" | ||
| 135 | elseif value == 3 | ||
| 136 | "three" | ||
| 137 | else | ||
| 138 | "other" | ||
| 139 | assert.same result, "three" | ||
| 140 | |||
| 141 | it "should handle then keyword syntax", -> | ||
| 142 | result = if true then "yes" else "no" | ||
| 143 | assert.same result, "yes" | ||
| 144 | |||
| 145 | it "should work with function call in condition", -> | ||
| 146 | return_true = -> true | ||
| 147 | result = if return_true! then "yes" else "no" | ||
| 148 | assert.same result, "yes" | ||
diff --git a/spec/inputs/test/config_spec.yue b/spec/inputs/test/config_spec.yue new file mode 100644 index 0000000..2df8ef3 --- /dev/null +++ b/spec/inputs/test/config_spec.yue | |||
| @@ -0,0 +1,106 @@ | |||
| 1 | describe "config", -> | ||
| 2 | -- Note: These tests verify that various compiler configs don't cause errors | ||
| 3 | -- Actual compiler config testing would require the compiler itself | ||
| 4 | |||
| 5 | it "should handle implicit return", -> | ||
| 6 | -- implicitReturnRoot is the default | ||
| 7 | fn = -> | ||
| 8 | 42 | ||
| 9 | assert.same fn!, 42 | ||
| 10 | |||
| 11 | it "should handle return in last position", -> | ||
| 12 | fn = -> | ||
| 13 | if true | ||
| 14 | 100 | ||
| 15 | else | ||
| 16 | 200 | ||
| 17 | assert.same fn!, 100 | ||
| 18 | |||
| 19 | it "should work with various code patterns", -> | ||
| 20 | -- Test that code compiles without explicit config | ||
| 21 | x = 1 + 2 | ||
| 22 | y = if x > 0 then "positive" else "negative" | ||
| 23 | assert.same y, "positive" | ||
| 24 | |||
| 25 | it "should handle class definitions", -> | ||
| 26 | class TestClass | ||
| 27 | value: 100 | ||
| 28 | get_value: => @value | ||
| 29 | instance = TestClass! | ||
| 30 | assert.same instance\get_value!, 100 | ||
| 31 | |||
| 32 | it "should handle macro definitions", -> | ||
| 33 | macro test_macro = (x) -> "#{x} + 1" | ||
| 34 | result = $test_macro 5 | ||
| 35 | assert.same result, 6 | ||
| 36 | |||
| 37 | it "should handle import statements", -> | ||
| 38 | import format from "string" | ||
| 39 | assert.is_true type(format) == "function" | ||
| 40 | |||
| 41 | it "should handle string interpolation", -> | ||
| 42 | name = "world" | ||
| 43 | result = "hello #{name}" | ||
| 44 | assert.same result, "hello world" | ||
| 45 | |||
| 46 | it "should handle comprehensions", -> | ||
| 47 | result = [x * 2 for x = 1, 5] | ||
| 48 | assert.same result, {2, 4, 6, 8, 10} | ||
| 49 | |||
| 50 | it "should handle switch expressions", -> | ||
| 51 | result = switch 2 | ||
| 52 | when 1 then "one" | ||
| 53 | when 2 then "two" | ||
| 54 | else "other" | ||
| 55 | assert.same result, "two" | ||
| 56 | |||
| 57 | it "should handle with statements", -> | ||
| 58 | obj = {x: 10, y: 20} | ||
| 59 | result = with obj | ||
| 60 | .x + .y | ||
| 61 | assert.same result, 30 | ||
| 62 | |||
| 63 | it "should handle existential operators", -> | ||
| 64 | obj = {value: 100} | ||
| 65 | result = obj?.value | ||
| 66 | assert.same result, 100 | ||
| 67 | |||
| 68 | it "should handle pipe operator", -> | ||
| 69 | result = {1, 2, 3} |> table.concat | ||
| 70 | assert.same result, "123" | ||
| 71 | |||
| 72 | it "should handle loops", -> | ||
| 73 | sum = 0 | ||
| 74 | for i = 1, 5 | ||
| 75 | sum += i | ||
| 76 | assert.same sum, 15 | ||
| 77 | |||
| 78 | it "should handle while loops", -> | ||
| 79 | count = 0 | ||
| 80 | while count < 3 | ||
| 81 | count += 1 | ||
| 82 | assert.same count, 3 | ||
| 83 | |||
| 84 | it "should handle table literals", -> | ||
| 85 | t = { | ||
| 86 | key1: "value1" | ||
| 87 | key2: "value2" | ||
| 88 | } | ||
| 89 | assert.same t.key1, "value1" | ||
| 90 | |||
| 91 | it "should handle function definitions", -> | ||
| 92 | fn = (a, b) -> a + b | ||
| 93 | assert.same fn(5, 3), 8 | ||
| 94 | |||
| 95 | it "should handle nested functions", -> | ||
| 96 | outer = -> | ||
| 97 | inner = (x) -> x * 2 | ||
| 98 | inner 10 | ||
| 99 | assert.same outer!, 20 | ||
| 100 | |||
| 101 | it "should handle destructure", -> | ||
| 102 | t = {x: 1, y: 2, z: 3} | ||
| 103 | {:x, :y, :z} = t | ||
| 104 | assert.same x, 1 | ||
| 105 | assert.same y, 2 | ||
| 106 | assert.same z, 3 | ||
diff --git a/spec/inputs/test/existential_spec.yue b/spec/inputs/test/existential_spec.yue new file mode 100644 index 0000000..f63967a --- /dev/null +++ b/spec/inputs/test/existential_spec.yue | |||
| @@ -0,0 +1,100 @@ | |||
| 1 | describe "existential", -> | ||
| 2 | it "should handle ?. with existing object", -> | ||
| 3 | obj = {value: 42} | ||
| 4 | result = obj?.value | ||
| 5 | assert.same result, 42 | ||
| 6 | |||
| 7 | it "should handle ?. with nil object", -> | ||
| 8 | obj = nil | ||
| 9 | result = obj?.value | ||
| 10 | assert.same result, nil | ||
| 11 | |||
| 12 | it "should chain ?. calls", -> | ||
| 13 | obj = {nested: {value: 100}} | ||
| 14 | result = obj?.nested?.value | ||
| 15 | assert.same result, 100 | ||
| 16 | |||
| 17 | it "should return nil in chain with nil", -> | ||
| 18 | obj = nil | ||
| 19 | result = obj?.nested?.value | ||
| 20 | assert.same result, nil | ||
| 21 | |||
| 22 | it "should handle ?. with method call", -> | ||
| 23 | obj = {func: -> "result"} | ||
| 24 | result = obj?.func! | ||
| 25 | assert.same result, "result" | ||
| 26 | |||
| 27 | it "should handle ? on table index", -> | ||
| 28 | tb = {[1]: "first"} | ||
| 29 | result = tb?[1] | ||
| 30 | assert.same result, "first" | ||
| 31 | |||
| 32 | it "should return nil for missing index", -> | ||
| 33 | tb = {} | ||
| 34 | result = tb?[99] | ||
| 35 | assert.same result, nil | ||
| 36 | |||
| 37 | it "should work with ? in if condition", -> | ||
| 38 | obj = {value: 5} | ||
| 39 | if obj?.value | ||
| 40 | result = "exists" | ||
| 41 | assert.same result, "exists" | ||
| 42 | |||
| 43 | it "should combine ?. with and/or", -> | ||
| 44 | obj = {value: 10} | ||
| 45 | result = obj?.value and 20 or 30 | ||
| 46 | assert.same result, 20 | ||
| 47 | |||
| 48 | it "should handle with? safely", -> | ||
| 49 | obj = {x: 1, y: 2} | ||
| 50 | sum = obj?.x + obj?.y | ||
| 51 | assert.same sum, 3 | ||
| 52 | |||
| 53 | it "should return nil with with? on nil", -> | ||
| 54 | obj = nil | ||
| 55 | result = obj?.x | ||
| 56 | assert.same result, nil | ||
| 57 | |||
| 58 | it "should handle false value correctly", -> | ||
| 59 | -- false is a valid value, not nil | ||
| 60 | obj = {value: false} | ||
| 61 | result = obj?.value | ||
| 62 | assert.same result, false | ||
| 63 | |||
| 64 | it "should handle 0 value correctly", -> | ||
| 65 | -- 0 is a valid value, not nil | ||
| 66 | obj = {value: 0} | ||
| 67 | result = obj?.value | ||
| 68 | assert.same result, 0 | ||
| 69 | |||
| 70 | it "should handle empty string correctly", -> | ||
| 71 | -- "" is a valid value, not nil | ||
| 72 | obj = {value: ""} | ||
| 73 | result = obj?.value | ||
| 74 | assert.same result, "" | ||
| 75 | |||
| 76 | it "should handle empty table correctly", -> | ||
| 77 | -- {} is a valid value, not nil | ||
| 78 | obj = {value: {}} | ||
| 79 | result = obj?.value | ||
| 80 | assert.same type(result), "table" | ||
| 81 | |||
| 82 | it "should work with deep chains", -> | ||
| 83 | obj = {a: {b: {c: {d: "deep"}}}} | ||
| 84 | result = obj?.a?.b?.c?.d | ||
| 85 | assert.same result, "deep" | ||
| 86 | |||
| 87 | it "should break chain on first nil", -> | ||
| 88 | obj = {a: nil} | ||
| 89 | result = obj?.a?.b?.c | ||
| 90 | assert.same result, nil | ||
| 91 | |||
| 92 | it "should handle ?. with string methods", -> | ||
| 93 | s = "hello" | ||
| 94 | result = s?\upper! | ||
| 95 | assert.same result, "HELLO" | ||
| 96 | |||
| 97 | it "should handle ?. with nil string", -> | ||
| 98 | s = nil | ||
| 99 | result = s?\upper! | ||
| 100 | assert.same result, nil | ||
diff --git a/spec/inputs/test/export_spec.yue b/spec/inputs/test/export_spec.yue new file mode 100644 index 0000000..c6ea99b --- /dev/null +++ b/spec/inputs/test/export_spec.yue | |||
| @@ -0,0 +1,99 @@ | |||
| 1 | describe "export", -> | ||
| 2 | it "should export basic variables", -> | ||
| 3 | a = 1 | ||
| 4 | b = 2 | ||
| 5 | c = 3 | ||
| 6 | assert.same a, 1 | ||
| 7 | assert.same b, 2 | ||
| 8 | assert.same c, 3 | ||
| 9 | |||
| 10 | it "should export multiple variables at once", -> | ||
| 11 | x, y, z = 10, 20, 30 | ||
| 12 | assert.same x, 10 | ||
| 13 | assert.same y, 20 | ||
| 14 | assert.same z, 30 | ||
| 15 | |||
| 16 | it "should export class definitions", -> | ||
| 17 | MyClass = class | ||
| 18 | value: 100 | ||
| 19 | assert.same MyClass.value, 100 | ||
| 20 | |||
| 21 | it "should export function expressions", -> | ||
| 22 | my_func = -> 42 | ||
| 23 | assert.same my_func!, 42 | ||
| 24 | |||
| 25 | it "should export conditional expressions", -> | ||
| 26 | result = if true | ||
| 27 | "yes" | ||
| 28 | else | ||
| 29 | "no" | ||
| 30 | assert.same result, "yes" | ||
| 31 | |||
| 32 | it "should export switch expressions", -> | ||
| 33 | value = switch 5 | ||
| 34 | when 5 then 100 | ||
| 35 | else 0 | ||
| 36 | assert.same value, 100 | ||
| 37 | |||
| 38 | it "should export with do block", -> | ||
| 39 | result = do | ||
| 40 | x = 5 | ||
| 41 | x * 2 | ||
| 42 | assert.same result, 10 | ||
| 43 | |||
| 44 | it "should export comprehension", -> | ||
| 45 | doubled = [i * 2 for i = 1, 5] | ||
| 46 | assert.same doubled, {2, 4, 6, 8, 10} | ||
| 47 | |||
| 48 | it "should export with pipe operator", -> | ||
| 49 | result = {1, 2, 3} |> table.concat | ||
| 50 | assert.same result, "123" | ||
| 51 | |||
| 52 | it "should export nil values", -> | ||
| 53 | empty = nil | ||
| 54 | assert.same empty, nil | ||
| 55 | |||
| 56 | it "should export tables", -> | ||
| 57 | config = { | ||
| 58 | key1: "value1" | ||
| 59 | key2: "value2" | ||
| 60 | } | ||
| 61 | assert.same config.key1, "value1" | ||
| 62 | assert.same config.key2, "value2" | ||
| 63 | |||
| 64 | it "should export string values", -> | ||
| 65 | message = "hello world" | ||
| 66 | assert.same message, "hello world" | ||
| 67 | |||
| 68 | it "should export boolean values", -> | ||
| 69 | flag_true = true | ||
| 70 | flag_false = false | ||
| 71 | assert.is_true flag_true | ||
| 72 | assert.is_false flag_false | ||
| 73 | |||
| 74 | it "should export number values", -> | ||
| 75 | count = 42 | ||
| 76 | price = 19.99 | ||
| 77 | assert.same count, 42 | ||
| 78 | assert.same price, 19.99 | ||
| 79 | |||
| 80 | it "should work in nested scope", -> | ||
| 81 | do | ||
| 82 | nested = "value" | ||
| 83 | assert.same nested, "value" | ||
| 84 | |||
| 85 | it "should export function with parameters", -> | ||
| 86 | add = (a, b) -> a + b | ||
| 87 | assert.same add(5, 3), 8 | ||
| 88 | |||
| 89 | it "should maintain export order", -> | ||
| 90 | first = 1 | ||
| 91 | second = 2 | ||
| 92 | third = 3 | ||
| 93 | assert.same first, 1 | ||
| 94 | assert.same second, 2 | ||
| 95 | assert.same third, 3 | ||
| 96 | |||
| 97 | it "should work with complex expressions", -> | ||
| 98 | calc = (10 + 20) * 2 | ||
| 99 | assert.same calc, 60 | ||
diff --git a/spec/inputs/test/goto_spec.yue b/spec/inputs/test/goto_spec.yue new file mode 100644 index 0000000..fd2f401 --- /dev/null +++ b/spec/inputs/test/goto_spec.yue | |||
| @@ -0,0 +1,80 @@ | |||
| 1 | describe "goto", -> | ||
| 2 | it "should support basic goto and label", -> | ||
| 3 | a = 0 | ||
| 4 | ::start:: | ||
| 5 | a += 1 | ||
| 6 | if a < 5 | ||
| 7 | goto start | ||
| 8 | assert.same a, 5 | ||
| 9 | |||
| 10 | it "should support conditional goto", -> | ||
| 11 | a = 0 | ||
| 12 | ::loop:: | ||
| 13 | a += 1 | ||
| 14 | goto done if a == 3 | ||
| 15 | goto loop | ||
| 16 | ::done:: | ||
| 17 | assert.same a, 3 | ||
| 18 | |||
| 19 | it "should support goto in nested loops", -> | ||
| 20 | count = 0 | ||
| 21 | for x = 1, 3 | ||
| 22 | for y = 1, 3 | ||
| 23 | count += 1 | ||
| 24 | if x == 2 and y == 2 | ||
| 25 | goto found | ||
| 26 | ::found:: | ||
| 27 | assert.same count, 4 -- (1,1), (1,2), (1,3), (2,1), (2,2) | ||
| 28 | |||
| 29 | it "should support multiple labels", -> | ||
| 30 | a = 0 | ||
| 31 | ::first:: | ||
| 32 | a += 1 | ||
| 33 | goto second if a == 2 | ||
| 34 | goto first | ||
| 35 | ::second:: | ||
| 36 | assert.same a, 2 | ||
| 37 | |||
| 38 | it "should work with for loops", -> | ||
| 39 | sum = 0 | ||
| 40 | for i = 1, 10 | ||
| 41 | sum += i | ||
| 42 | goto done if i == 5 | ||
| 43 | ::done:: | ||
| 44 | assert.same sum, 15 -- 1+2+3+4+5 | ||
| 45 | |||
| 46 | it "should work with while loops", -> | ||
| 47 | count = 0 | ||
| 48 | while true | ||
| 49 | count += 1 | ||
| 50 | goto endwhile if count == 3 | ||
| 51 | ::endwhile:: | ||
| 52 | assert.same count, 3 | ||
| 53 | |||
| 54 | it "should skip rest of loop with goto", -> | ||
| 55 | values = {} | ||
| 56 | for i = 1, 5 | ||
| 57 | goto continue if i % 2 == 0 | ||
| 58 | table.insert values, i | ||
| 59 | ::continue:: | ||
| 60 | assert.same values, {1, 3, 5} | ||
| 61 | |||
| 62 | it "should support goto with switch", -> | ||
| 63 | result = "default" | ||
| 64 | value = 2 | ||
| 65 | switch value | ||
| 66 | when 1 | ||
| 67 | goto case_one | ||
| 68 | when 2 | ||
| 69 | goto case_two | ||
| 70 | goto default_label | ||
| 71 | ::case_one:: | ||
| 72 | result = "one" | ||
| 73 | goto finish | ||
| 74 | ::case_two:: | ||
| 75 | result = "two" | ||
| 76 | goto finish | ||
| 77 | ::default_label:: | ||
| 78 | result = "default" | ||
| 79 | ::finish:: | ||
| 80 | assert.same result, "two" | ||
diff --git a/spec/inputs/test/import_spec.yue b/spec/inputs/test/import_spec.yue new file mode 100644 index 0000000..deeb4a0 --- /dev/null +++ b/spec/inputs/test/import_spec.yue | |||
| @@ -0,0 +1,115 @@ | |||
| 1 | describe "import", -> | ||
| 2 | it "should import from table expression", -> | ||
| 3 | source = {hello: "world", foo: "bar"} | ||
| 4 | import hello, foo from source | ||
| 5 | assert.same hello, "world" | ||
| 6 | assert.same foo, "bar" | ||
| 7 | |||
| 8 | it "should import with backslash escaping", -> | ||
| 9 | source = {x: 1, y: 2, z: 3} | ||
| 10 | import x, \y, z from source | ||
| 11 | assert.same x, 1 | ||
| 12 | assert.same y, 2 | ||
| 13 | assert.same z, 3 | ||
| 14 | |||
| 15 | it "should import from string module", -> | ||
| 16 | -- Test with string library | ||
| 17 | import format from "string" | ||
| 18 | assert.is_true type(format) == "function" | ||
| 19 | |||
| 20 | it "should import from table with dot path", -> | ||
| 21 | -- Using string.sub as an example | ||
| 22 | import sub from "string" | ||
| 23 | result = sub "hello", 1, 2 | ||
| 24 | assert.same result, "he" | ||
| 25 | |||
| 26 | it "should import multiple values with table destructuring", -> | ||
| 27 | source = {a: 1, b: 2, c: 3} | ||
| 28 | import a, b, c from source | ||
| 29 | assert.same a, 1 | ||
| 30 | assert.same b, 2 | ||
| 31 | assert.same c, 3 | ||
| 32 | |||
| 33 | it "should import with multi-line format", -> | ||
| 34 | source = {x: 1, y: 2, z: 3} | ||
| 35 | import x, y, z from source | ||
| 36 | assert.same x, 1 | ||
| 37 | assert.same y, 2 | ||
| 38 | assert.same z, 3 | ||
| 39 | |||
| 40 | it "should import using from syntax", -> | ||
| 41 | source = {foo: "bar", baz: "qux"} | ||
| 42 | from source import foo, baz | ||
| 43 | assert.same foo, "bar" | ||
| 44 | assert.same baz, "qux" | ||
| 45 | |||
| 46 | it "should handle import with computed expressions", -> | ||
| 47 | source = {first: 1, second: 2} | ||
| 48 | target = source | ||
| 49 | import first, second from target | ||
| 50 | assert.same first, 1 | ||
| 51 | assert.same second, 2 | ||
| 52 | |||
| 53 | it "should import from nested table paths", -> | ||
| 54 | deep = {outer: {inner: "value"}} | ||
| 55 | import outer from deep | ||
| 56 | assert.same outer.inner, "value" | ||
| 57 | |||
| 58 | it "should support importing Lua standard library functions", -> | ||
| 59 | import print, type from "_G" | ||
| 60 | assert.is_true type(print) == "function" | ||
| 61 | assert.is_true type(type) == "function" | ||
| 62 | |||
| 63 | it "should handle empty import gracefully", -> | ||
| 64 | -- Empty module shouldn't cause errors | ||
| 65 | source = {} | ||
| 66 | import dummy from source | ||
| 67 | assert.same dummy, nil | ||
| 68 | |||
| 69 | it "should work with table index expressions", -> | ||
| 70 | source = {normal: "ok"} | ||
| 71 | import normal from source | ||
| 72 | assert.same normal, "ok" | ||
| 73 | |||
| 74 | it "should support chaining imports from same source", -> | ||
| 75 | source = {a: 1, b: 2, c: 3} | ||
| 76 | import a, b from source | ||
| 77 | import c from source | ||
| 78 | assert.same a, 1 | ||
| 79 | assert.same b, 2 | ||
| 80 | assert.same c, 3 | ||
| 81 | |||
| 82 | it "should handle importing from table returned by function", -> | ||
| 83 | get_table = -> {x: 100, y: 200} | ||
| 84 | import x, y from get_table! | ||
| 85 | assert.same x, 100 | ||
| 86 | assert.same y, 200 | ||
| 87 | |||
| 88 | it "should support from with multi-line import", -> | ||
| 89 | source = {item1: 1, item2: 2, item3: 3} | ||
| 90 | from source import item1, item2, item3 | ||
| 91 | assert.same item1, 1 | ||
| 92 | assert.same item2, 2 | ||
| 93 | assert.same item3, 3 | ||
| 94 | |||
| 95 | it "should work with import from string literal", -> | ||
| 96 | import char from "string" | ||
| 97 | assert.same char(65), "A" | ||
| 98 | |||
| 99 | it "should support import with table literal keys", -> | ||
| 100 | source = {normal_key: "value2"} | ||
| 101 | import normal_key from source | ||
| 102 | assert.same normal_key, "value2" | ||
| 103 | |||
| 104 | it "should handle consecutive imports", -> | ||
| 105 | source1 = {a: 1} | ||
| 106 | source2 = {b: 2} | ||
| 107 | import a from source1 | ||
| 108 | import b from source2 | ||
| 109 | assert.same a, 1 | ||
| 110 | assert.same b, 2 | ||
| 111 | |||
| 112 | it "should support importing from complex expressions", -> | ||
| 113 | get_source = -> {result: 42} | ||
| 114 | import result from get_source! | ||
| 115 | assert.same result, 42 | ||
diff --git a/spec/inputs/test/literals_spec.yue b/spec/inputs/test/literals_spec.yue new file mode 100644 index 0000000..10bd6b3 --- /dev/null +++ b/spec/inputs/test/literals_spec.yue | |||
| @@ -0,0 +1,81 @@ | |||
| 1 | describe "literals", -> | ||
| 2 | it "should support integer literals", -> | ||
| 3 | assert.same 123, 123 | ||
| 4 | |||
| 5 | it "should support float literals", -> | ||
| 6 | assert.same 1.5, 1.5 | ||
| 7 | |||
| 8 | it "should support scientific notation", -> | ||
| 9 | assert.same 1.5e2, 150 | ||
| 10 | |||
| 11 | it "should support negative numbers", -> | ||
| 12 | assert.same -42, -42 | ||
| 13 | |||
| 14 | it "should support hexadecimal literals", -> | ||
| 15 | assert.same 0xff, 255 | ||
| 16 | |||
| 17 | it "should support hexadecimal with uppercase", -> | ||
| 18 | assert.same 0XFF, 255 | ||
| 19 | |||
| 20 | it "should support binary literals", -> | ||
| 21 | assert.same 0b101, 5 | ||
| 22 | |||
| 23 | it "should support binary with uppercase", -> | ||
| 24 | assert.same 0B101, 5 | ||
| 25 | |||
| 26 | it "should support number with underscores", -> | ||
| 27 | assert.same 1_000_000, 1000000 | ||
| 28 | |||
| 29 | it "should support hex with underscores", -> | ||
| 30 | assert.same 0xDE_AD_BE_EF, 0xDEADBEEF | ||
| 31 | |||
| 32 | it "should support double quote strings", -> | ||
| 33 | assert.same "hello", "hello" | ||
| 34 | |||
| 35 | it "should support single quote strings", -> | ||
| 36 | assert.same 'world', 'world' | ||
| 37 | |||
| 38 | it "should support multi-line strings with [[", -> | ||
| 39 | s = [[ | ||
| 40 | hello | ||
| 41 | world | ||
| 42 | ]] | ||
| 43 | assert.is_true s\match "hello" | ||
| 44 | |||
| 45 | it "should support multi-line strings with [=[", -> | ||
| 46 | s = [==[ | ||
| 47 | test | ||
| 48 | ]==] | ||
| 49 | assert.is_true s\match "test" | ||
| 50 | |||
| 51 | it "should support boolean true", -> | ||
| 52 | assert.same true, true | ||
| 53 | |||
| 54 | it "should support boolean false", -> | ||
| 55 | assert.same false, false | ||
| 56 | |||
| 57 | it "should support nil", -> | ||
| 58 | assert.same nil, nil | ||
| 59 | |||
| 60 | it "should support empty table", -> | ||
| 61 | t = {} | ||
| 62 | assert.same #t, 0 | ||
| 63 | |||
| 64 | it "should support table with keys", -> | ||
| 65 | t = {a: 1, b: 2} | ||
| 66 | assert.same t.a, 1 | ||
| 67 | assert.same t.b, 2 | ||
| 68 | |||
| 69 | it "should support array literal", -> | ||
| 70 | t = {1, 2, 3} | ||
| 71 | assert.same t[1], 1 | ||
| 72 | assert.same t[2], 2 | ||
| 73 | assert.same t[3], 3 | ||
| 74 | |||
| 75 | it "should support mixed table", -> | ||
| 76 | t = { | ||
| 77 | 1, 2, 3 | ||
| 78 | key: "value" | ||
| 79 | } | ||
| 80 | assert.same t[1], 1 | ||
| 81 | assert.same t.key, "value" | ||
diff --git a/spec/inputs/test/macro_spec.yue b/spec/inputs/test/macro_spec.yue new file mode 100644 index 0000000..a4a170b --- /dev/null +++ b/spec/inputs/test/macro_spec.yue | |||
| @@ -0,0 +1,135 @@ | |||
| 1 | describe "macro", -> | ||
| 2 | it "should define and call basic macro", -> | ||
| 3 | macro double = (x) -> "#{x} * 2" | ||
| 4 | result = $double 5 | ||
| 5 | assert.same result, 10 | ||
| 6 | |||
| 7 | it "should maintain hygiene in macros", -> | ||
| 8 | macro get_value_hygienic = -> | ||
| 9 | (-> | ||
| 10 | local a = 1 | ||
| 11 | a + 1)! | ||
| 12 | a = 8 | ||
| 13 | result = $get_value_hygienic! | ||
| 14 | assert.same result, 2 | ||
| 15 | |||
| 16 | it "should validate AST types", -> | ||
| 17 | macro NumAndStr = (num`Num, str`SingleString) -> "[#{num}, #{str}]" | ||
| 18 | result = $NumAndStr 123, 'xyz' | ||
| 19 | assert.same result, "[123, xyz]" | ||
| 20 | |||
| 21 | it "should support simple code generation", -> | ||
| 22 | macro add_one = (x) -> "#{x} + 1" | ||
| 23 | result = $add_one 10 | ||
| 24 | assert.same result, 11 | ||
| 25 | |||
| 26 | it "should support nested macro calls", -> | ||
| 27 | macro inc = (x) -> "#{x} + 1" | ||
| 28 | macro double_inc = (x) -> $inc($inc(x)) | ||
| 29 | result = $double_inc 5 | ||
| 30 | assert.same result, 7 | ||
| 31 | |||
| 32 | it "should respect macro scope in do blocks", -> | ||
| 33 | macro outer = -> "outer" | ||
| 34 | do | ||
| 35 | macro inner = -> "inner" | ||
| 36 | result = $inner! | ||
| 37 | assert.same result, "inner" | ||
| 38 | result = $outer! | ||
| 39 | assert.same result, "outer" | ||
| 40 | |||
| 41 | it "should provide $LINE macro", -> | ||
| 42 | line_num = $LINE | ||
| 43 | assert.is_true line_num > 0 | ||
| 44 | |||
| 45 | it "should inject Lua code", -> | ||
| 46 | macro lua_code = (code) -> {:code, type: "lua"} | ||
| 47 | x = 0 | ||
| 48 | $lua_code [[ | ||
| 49 | local function f(a) | ||
| 50 | return a + 1 | ||
| 51 | end | ||
| 52 | x = x + f(3) | ||
| 53 | ]] | ||
| 54 | assert.same x, 4 | ||
| 55 | |||
| 56 | it "should work in conditional compilation", -> | ||
| 57 | macro if_debug = (debug_code) -> | ||
| 58 | if $LINE > 0 | ||
| 59 | debug_code | ||
| 60 | else | ||
| 61 | "" | ||
| 62 | result = $if_debug "debug mode" | ||
| 63 | assert.same result, "debug mode" | ||
| 64 | |||
| 65 | it "should work with class system", -> | ||
| 66 | class Thing | ||
| 67 | value: 100 | ||
| 68 | get_value: => @value | ||
| 69 | instance = Thing! | ||
| 70 | assert.same instance\get_value!, 100 | ||
| 71 | |||
| 72 | it "should handle macro in switch expressions", -> | ||
| 73 | macro to_value = (x) -> x | ||
| 74 | result = switch $to_value "test" | ||
| 75 | when "test" | ||
| 76 | "matched" | ||
| 77 | else | ||
| 78 | "no match" | ||
| 79 | assert.same result, "matched" | ||
| 80 | |||
| 81 | it "should support macro in expression context", -> | ||
| 82 | macro triple = (x) -> "#{x} * 3" | ||
| 83 | result = 5 + $triple 2 | ||
| 84 | assert.same result, 11 | ||
| 85 | |||
| 86 | it "should handle $is_ast for type checking", -> | ||
| 87 | macro check_num = (x) -> | ||
| 88 | unless $is_ast(Num, x) | ||
| 89 | error "expected number" | ||
| 90 | x | ||
| 91 | result = $check_num 42 | ||
| 92 | assert.same result, 42 | ||
| 93 | |||
| 94 | it "should work with string interpolation", -> | ||
| 95 | macro format_result = (name, value) -> "#{name}: #{value}" | ||
| 96 | result = $format_result "test", 123 | ||
| 97 | assert.same result, "test: 123" | ||
| 98 | |||
| 99 | it "should support function call syntax", -> | ||
| 100 | macro my_func = (x, y) -> "#{x} + #{y}" | ||
| 101 | result = $my_func(5, 10) | ||
| 102 | assert.same result, 15 | ||
| 103 | |||
| 104 | it "should handle empty macro return", -> | ||
| 105 | macro skip = -> "" | ||
| 106 | a = 1 | ||
| 107 | $skip | ||
| 108 | a = 2 | ||
| 109 | assert.same a, 2 | ||
| 110 | |||
| 111 | it "should work with table literals", -> | ||
| 112 | macro make_point = (x, y) -> "{x: #{x}, y: #{y}}" | ||
| 113 | point = $make_point 10, 20 | ||
| 114 | assert.same point.x, 10 | ||
| 115 | assert.same point.y, 20 | ||
| 116 | |||
| 117 | it "should support conditional expressions in macro", -> | ||
| 118 | macro add_one = (x) -> "#{x} + 1" | ||
| 119 | result = $add_one 5 | ||
| 120 | assert.same result, 6 | ||
| 121 | |||
| 122 | it "should work with comprehension", -> | ||
| 123 | macro doubled_list = (items) -> "[_ * 2 for _ in *#{items}]" | ||
| 124 | result = $doubled_list {1, 2, 3} | ||
| 125 | assert.same result, {2, 4, 6} | ||
| 126 | |||
| 127 | it "should support complex expression macros", -> | ||
| 128 | macro calc = (a, b, c) -> "#{a} + #{b} * #{c}" | ||
| 129 | result = $calc 1, 2, 3 | ||
| 130 | assert.same result, 7 | ||
| 131 | |||
| 132 | it "should work with string literals", -> | ||
| 133 | macro greet = (name) -> '"Hello, #{name}"' | ||
| 134 | result = $greet "World" | ||
| 135 | assert.same result, "Hello, World" | ||
diff --git a/spec/inputs/test/metatable_spec.yue b/spec/inputs/test/metatable_spec.yue new file mode 100644 index 0000000..9a2ae6a --- /dev/null +++ b/spec/inputs/test/metatable_spec.yue | |||
| @@ -0,0 +1,86 @@ | |||
| 1 | describe "metatable", -> | ||
| 2 | it "should get metatable with <> syntax", -> | ||
| 3 | obj = setmetatable {value: 42}, {__index: {extra: "data"}} | ||
| 4 | mt = obj.<> | ||
| 5 | assert.is_true mt ~= nil | ||
| 6 | |||
| 7 | it "should set metatable with <>", -> | ||
| 8 | obj = {} | ||
| 9 | obj.<> = {__index: {value: 100}} | ||
| 10 | assert.same obj.value, 100 | ||
| 11 | |||
| 12 | it "should access metatable with <>", -> | ||
| 13 | obj = setmetatable {}, {__index: {value: 50}} | ||
| 14 | result = obj.<>.__index.value | ||
| 15 | assert.same result, 50 | ||
| 16 | |||
| 17 | it "should work with <index> metamethod", -> | ||
| 18 | obj = setmetatable {}, { | ||
| 19 | __index: (self, key) -> | ||
| 20 | if key == "computed" | ||
| 21 | return "computed_value" | ||
| 22 | } | ||
| 23 | assert.same obj.computed, "computed_value" | ||
| 24 | |||
| 25 | it "should work with <newindex> metamethod", -> | ||
| 26 | obj = setmetatable {}, { | ||
| 27 | __newindex: (self, key, value) -> | ||
| 28 | rawset self, "stored_" .. key, value | ||
| 29 | } | ||
| 30 | obj.test = 123 | ||
| 31 | assert.same obj.stored_test, 123 | ||
| 32 | |||
| 33 | it "should work with <add> metamethod", -> | ||
| 34 | obj = setmetatable({value: 10}, { | ||
| 35 | __add: (a, b) -> a.value + b.value | ||
| 36 | }) | ||
| 37 | obj2 = setmetatable({value: 20}, { | ||
| 38 | __add: (a, b) -> a.value + b.value | ||
| 39 | }) | ||
| 40 | result = obj + obj2 | ||
| 41 | assert.same result, 30 | ||
| 42 | |||
| 43 | it "should work with <call> metamethod", -> | ||
| 44 | obj = setmetatable {}, { | ||
| 45 | __call: (self, x) -> x * 2 | ||
| 46 | } | ||
| 47 | result = obj 5 | ||
| 48 | assert.same result, 10 | ||
| 49 | |||
| 50 | it "should work with <tostring> metamethod", -> | ||
| 51 | obj = setmetatable {value: 42}, { | ||
| 52 | __tostring: (self) -> "Value: #{self.value}" | ||
| 53 | } | ||
| 54 | result = tostring obj | ||
| 55 | assert.same result, "Value: 42" | ||
| 56 | |||
| 57 | it "should work with <eq> metamethod", -> | ||
| 58 | obj1 = setmetatable({id: 1}, { | ||
| 59 | __eq: (a, b) -> a.id == b.id | ||
| 60 | }) | ||
| 61 | obj2 = setmetatable({id: 1}, { | ||
| 62 | __eq: (a, b) -> a.id == b.id | ||
| 63 | }) | ||
| 64 | assert.is_true obj1 == obj2 | ||
| 65 | |||
| 66 | it "should destructure metatable", -> | ||
| 67 | obj = setmetatable {}, { | ||
| 68 | new: -> "new result" | ||
| 69 | update: -> "update result" | ||
| 70 | } | ||
| 71 | {:new, :update} = obj.<> | ||
| 72 | assert.is_true type(new) == "function" | ||
| 73 | assert.is_true type(update) == "function" | ||
| 74 | |||
| 75 | it "should check if two objects have same metatable", -> | ||
| 76 | mt = {value: 100} | ||
| 77 | obj1 = setmetatable {}, mt | ||
| 78 | obj2 = setmetatable {}, mt | ||
| 79 | assert.is_true obj1.<> == obj2.<> | ||
| 80 | |||
| 81 | it "should work with <concat> metamethod", -> | ||
| 82 | obj = setmetatable {value: "hello"}, { | ||
| 83 | __concat: (a, b) -> a.value .. b | ||
| 84 | } | ||
| 85 | result = obj .. " world" | ||
| 86 | assert.same result, "hello world" | ||
diff --git a/spec/inputs/test/operators_spec.yue b/spec/inputs/test/operators_spec.yue new file mode 100644 index 0000000..9b5585b --- /dev/null +++ b/spec/inputs/test/operators_spec.yue | |||
| @@ -0,0 +1,137 @@ | |||
| 1 | describe "operators", -> | ||
| 2 | it "should support addition", -> | ||
| 3 | assert.same 1 + 2, 3 | ||
| 4 | |||
| 5 | it "should support subtraction", -> | ||
| 6 | assert.same 5 - 3, 2 | ||
| 7 | |||
| 8 | it "should support multiplication", -> | ||
| 9 | assert.same 4 * 3, 12 | ||
| 10 | |||
| 11 | it "should support division", -> | ||
| 12 | assert.same 10 / 2, 5 | ||
| 13 | |||
| 14 | it "should support modulo", -> | ||
| 15 | assert.same 10 % 3, 1 | ||
| 16 | |||
| 17 | it "should support exponentiation", -> | ||
| 18 | assert.same 2 ^ 3, 8 | ||
| 19 | |||
| 20 | it "should support unary minus", -> | ||
| 21 | assert.same -5, -5 | ||
| 22 | |||
| 23 | it "should support equality comparison", -> | ||
| 24 | assert.is_true 1 == 1 | ||
| 25 | assert.is_false 1 == 2 | ||
| 26 | |||
| 27 | it "should support inequality comparison", -> | ||
| 28 | assert.is_true 1 ~= 2 | ||
| 29 | assert.is_false 1 ~= 1 | ||
| 30 | |||
| 31 | it "should support less than", -> | ||
| 32 | assert.is_true 1 < 2 | ||
| 33 | assert.is_false 2 < 1 | ||
| 34 | |||
| 35 | it "should support greater than", -> | ||
| 36 | assert.is_true 2 > 1 | ||
| 37 | assert.is_false 1 > 2 | ||
| 38 | |||
| 39 | it "should support less than or equal", -> | ||
| 40 | assert.is_true 1 <= 2 | ||
| 41 | assert.is_true 2 <= 2 | ||
| 42 | assert.is_false 3 <= 2 | ||
| 43 | |||
| 44 | it "should support greater than or equal", -> | ||
| 45 | assert.is_true 2 >= 1 | ||
| 46 | assert.is_true 2 >= 2 | ||
| 47 | assert.is_false 1 >= 2 | ||
| 48 | |||
| 49 | it "should support logical and", -> | ||
| 50 | assert.same true and false, false | ||
| 51 | assert.same true and true, true | ||
| 52 | assert.same false and true, false | ||
| 53 | |||
| 54 | it "should support logical or", -> | ||
| 55 | assert.same true or false, true | ||
| 56 | assert.same false or true, true | ||
| 57 | assert.same false or false, false | ||
| 58 | |||
| 59 | it "should support logical not", -> | ||
| 60 | assert.same not true, false | ||
| 61 | assert.same not false, true | ||
| 62 | assert.same not nil, true | ||
| 63 | |||
| 64 | it "should support bitwise and", -> | ||
| 65 | assert.same 5 & 3, 1 -- 101 & 011 = 001 | ||
| 66 | |||
| 67 | it "should support bitwise or", -> | ||
| 68 | assert.same 5 | 3, 7 -- 101 | 011 = 111 | ||
| 69 | |||
| 70 | it "should support bitwise xor", -> | ||
| 71 | assert.same 5 ~ 3, 6 -- 101 ~ 011 = 110 | ||
| 72 | |||
| 73 | it "should support left shift", -> | ||
| 74 | assert.same 2 << 3, 16 | ||
| 75 | |||
| 76 | it "should support right shift", -> | ||
| 77 | assert.same 16 >> 2, 4 | ||
| 78 | |||
| 79 | it "should support string concatenation", -> | ||
| 80 | assert.same "hello" .. " world", "hello world" | ||
| 81 | |||
| 82 | it "should support length operator", -> | ||
| 83 | assert.same #"hello", 5 | ||
| 84 | assert.same #{1, 2, 3}, 3 | ||
| 85 | |||
| 86 | it "should respect operator precedence", -> | ||
| 87 | assert.same 1 + 2 * 3, 7 -- multiplication before addition | ||
| 88 | assert.same (1 + 2) * 3, 9 -- parentheses first | ||
| 89 | |||
| 90 | it "should support compound assignment", -> | ||
| 91 | x = 10 | ||
| 92 | x += 5 | ||
| 93 | assert.same x, 15 | ||
| 94 | |||
| 95 | it "should support compound subtraction", -> | ||
| 96 | x = 10 | ||
| 97 | x -= 3 | ||
| 98 | assert.same x, 7 | ||
| 99 | |||
| 100 | it "should support compound multiplication", -> | ||
| 101 | x = 5 | ||
| 102 | x *= 2 | ||
| 103 | assert.same x, 10 | ||
| 104 | |||
| 105 | it "should support compound division", -> | ||
| 106 | x = 20 | ||
| 107 | x /= 4 | ||
| 108 | assert.same x, 5 | ||
| 109 | |||
| 110 | it "should handle division by zero", -> | ||
| 111 | -- Lua returns inf or nan | ||
| 112 | result = pcall(-> | ||
| 113 | x = 10 / 0 | ||
| 114 | ) | ||
| 115 | assert.is_true result -- doesn't error in Lua | ||
| 116 | |||
| 117 | it "should handle very large numbers", -> | ||
| 118 | big = 1e100 | ||
| 119 | assert.is_true big > 0 | ||
| 120 | |||
| 121 | it "should handle very small numbers", -> | ||
| 122 | small = 1e-100 | ||
| 123 | assert.is_true small > 0 | ||
| 124 | |||
| 125 | it "should support negation", -> | ||
| 126 | assert.same -10, -10 | ||
| 127 | assert.same --5, 5 | ||
| 128 | |||
| 129 | it "should work with complex expressions", -> | ||
| 130 | result = (1 + 2) * (3 + 4) / 2 | ||
| 131 | assert.same result, 10.5 | ||
| 132 | |||
| 133 | it "should support power with decimal", -> | ||
| 134 | assert.same 4 ^ 0.5, 2 | ||
| 135 | |||
| 136 | it "should handle modulo with negative numbers", -> | ||
| 137 | assert.same -10 % 3, 2 -- Lua's modulo behavior | ||
diff --git a/spec/inputs/test/return_spec.yue b/spec/inputs/test/return_spec.yue new file mode 100644 index 0000000..3bf0bed --- /dev/null +++ b/spec/inputs/test/return_spec.yue | |||
| @@ -0,0 +1,85 @@ | |||
| 1 | describe "return", -> | ||
| 2 | it "should return from comprehension", -> | ||
| 3 | fn = -> | ||
| 4 | return [x * 2 for x = 1, 5] | ||
| 5 | result = fn! | ||
| 6 | assert.same result, {2, 4, 6, 8, 10} | ||
| 7 | |||
| 8 | it "should return from table comprehension", -> | ||
| 9 | fn = -> | ||
| 10 | return {k, v for k, v in pairs {a: 1, b: 2}} | ||
| 11 | result = fn! | ||
| 12 | assert.same type(result), "table" | ||
| 13 | |||
| 14 | it "should return from nested if", -> | ||
| 15 | fn = (a, b) -> | ||
| 16 | if a | ||
| 17 | if b | ||
| 18 | return "both" | ||
| 19 | else | ||
| 20 | return "only a" | ||
| 21 | else | ||
| 22 | return "neither" | ||
| 23 | assert.same fn(true, true), "both" | ||
| 24 | assert.same fn(true, false), "only a" | ||
| 25 | assert.same fn(false, false), "neither" | ||
| 26 | |||
| 27 | it "should return from switch", -> | ||
| 28 | fn = (value) -> | ||
| 29 | return switch value | ||
| 30 | when 1 then "one" | ||
| 31 | when 2 then "two" | ||
| 32 | else "other" | ||
| 33 | assert.same fn(1), "one" | ||
| 34 | assert.same fn(2), "two" | ||
| 35 | assert.same fn(3), "other" | ||
| 36 | |||
| 37 | it "should return table literal", -> | ||
| 38 | fn = -> | ||
| 39 | return | ||
| 40 | value: 42 | ||
| 41 | name: "test" | ||
| 42 | result = fn! | ||
| 43 | assert.same result.value, 42 | ||
| 44 | assert.same result.name, "test" | ||
| 45 | |||
| 46 | it "should return array literal", -> | ||
| 47 | fn = -> | ||
| 48 | return | ||
| 49 | * 1 | ||
| 50 | * 2 | ||
| 51 | * 3 | ||
| 52 | result = fn! | ||
| 53 | assert.same result, {1, 2, 3} | ||
| 54 | |||
| 55 | it "should return from with statement", -> | ||
| 56 | fn = (obj) -> | ||
| 57 | result = obj.value | ||
| 58 | return result | ||
| 59 | assert.same fn({value: 100}), 100 | ||
| 60 | |||
| 61 | it "should return nil implicitly", -> | ||
| 62 | fn -> print "no return" | ||
| 63 | assert.same fn!, nil | ||
| 64 | |||
| 65 | it "should return multiple values", -> | ||
| 66 | fn -> 1, 2, 3 | ||
| 67 | a, b, c = fn! | ||
| 68 | assert.same a, 1 | ||
| 69 | assert.same b, 2 | ||
| 70 | assert.same c, 3 | ||
| 71 | |||
| 72 | it "should return from function call", -> | ||
| 73 | fn = -> | ||
| 74 | inner = -> 42 | ||
| 75 | return inner! | ||
| 76 | assert.same fn!, 42 | ||
| 77 | |||
| 78 | it "should handle return in expression context", -> | ||
| 79 | fn = (cond) -> | ||
| 80 | if cond | ||
| 81 | return "yes" | ||
| 82 | else | ||
| 83 | return "no" | ||
| 84 | assert.same fn(true), "yes" | ||
| 85 | assert.same fn(false), "no" | ||
diff --git a/spec/inputs/test/string_spec.yue b/spec/inputs/test/string_spec.yue new file mode 100644 index 0000000..b790518 --- /dev/null +++ b/spec/inputs/test/string_spec.yue | |||
| @@ -0,0 +1,143 @@ | |||
| 1 | describe "string", -> | ||
| 2 | it "should support single quote strings", -> | ||
| 3 | s = 'hello' | ||
| 4 | assert.same s, "hello" | ||
| 5 | |||
| 6 | it "should support double quote strings", -> | ||
| 7 | s = "world" | ||
| 8 | assert.same s, "world" | ||
| 9 | |||
| 10 | it "should support escape sequences", -> | ||
| 11 | s = "hello\nworld" | ||
| 12 | assert.is_true s\match("\n") ~= nil | ||
| 13 | |||
| 14 | it "should support escaped quotes", -> | ||
| 15 | s = "he said \"hello\"" | ||
| 16 | assert.same s, 'he said "hello"' | ||
| 17 | |||
| 18 | it "should support backslash escape", -> | ||
| 19 | s = "\\" | ||
| 20 | assert.same s, "\\" | ||
| 21 | |||
| 22 | it "should support multi-line strings with [[ ]]", -> | ||
| 23 | s = [[ | ||
| 24 | hello | ||
| 25 | world | ||
| 26 | ]] | ||
| 27 | assert.is_true s\match("hello") ~= nil | ||
| 28 | assert.is_true s\match("world") ~= nil | ||
| 29 | |||
| 30 | it "should support multi-line strings with [=[ ]=]", -> | ||
| 31 | s = [==[ | ||
| 32 | hello | ||
| 33 | world | ||
| 34 | ]==] | ||
| 35 | assert.is_true s\match("hello") ~= nil | ||
| 36 | assert.is_true s\match("world") ~= nil | ||
| 37 | |||
| 38 | it "should support string interpolation with double quotes", -> | ||
| 39 | name = "world" | ||
| 40 | s = "hello #{name}" | ||
| 41 | assert.same s, "hello world" | ||
| 42 | |||
| 43 | it "should support expression interpolation", -> | ||
| 44 | a, b = 1, 2 | ||
| 45 | s = "#{a} + #{b} = #{a + b}" | ||
| 46 | assert.same s, "1 + 2 = 3" | ||
| 47 | |||
| 48 | it "should not interpolate in single quotes", -> | ||
| 49 | name = "world" | ||
| 50 | s = 'hello #{name}' | ||
| 51 | assert.same s, "hello #{name}" | ||
| 52 | |||
| 53 | it "should escape interpolation with \\#", -> | ||
| 54 | name = "world" | ||
| 55 | s = "hello \\#{name}" | ||
| 56 | assert.same s, "hello #{name}" | ||
| 57 | |||
| 58 | it "should support method calls on string literals", -> | ||
| 59 | result = "hello"\upper! | ||
| 60 | assert.same result, "HELLO" | ||
| 61 | |||
| 62 | it "should support chained method calls", -> | ||
| 63 | result = "hello world"\upper!\match "HELLO" | ||
| 64 | assert.same result, "HELLO" | ||
| 65 | |||
| 66 | it "should support YAML style strings", -> | ||
| 67 | s = | | ||
| 68 | hello | ||
| 69 | world | ||
| 70 | assert.is_true s\match("hello") ~= nil | ||
| 71 | assert.is_true s\match("world") ~= nil | ||
| 72 | |||
| 73 | it "should support YAML style with interpolation", -> | ||
| 74 | name = "test" | ||
| 75 | s = | | ||
| 76 | hello #{name} | ||
| 77 | assert.same s, "hello test\n" | ||
| 78 | |||
| 79 | it "should support string concatenation", -> | ||
| 80 | s = "hello" .. " " .. "world" | ||
| 81 | assert.same s, "hello world" | ||
| 82 | |||
| 83 | it "should handle empty strings", -> | ||
| 84 | s = "" | ||
| 85 | assert.same s, "" | ||
| 86 | |||
| 87 | it "should support Unicode characters", -> | ||
| 88 | s = "hello 世界" | ||
| 89 | assert.is_true s\match("世界") ~= nil | ||
| 90 | |||
| 91 | it "should support string length", -> | ||
| 92 | s = "hello" | ||
| 93 | assert.same #s, 5 | ||
| 94 | |||
| 95 | it "should support multi-line YAML with complex content", -> | ||
| 96 | config = | | ||
| 97 | key1: value1 | ||
| 98 | key2: value2 | ||
| 99 | key3: value3 | ||
| 100 | assert.is_true config\match("key1") ~= nil | ||
| 101 | |||
| 102 | it "should support interpolation in YAML strings", -> | ||
| 103 | x, y = 10, 20 | ||
| 104 | s = | | ||
| 105 | point: | ||
| 106 | x: #{x} | ||
| 107 | y: #{y} | ||
| 108 | assert.is_true s\match("x: 10") ~= nil | ||
| 109 | assert.is_true s\match("y: 20") ~= nil | ||
| 110 | |||
| 111 | it "should support function call in interpolation", -> | ||
| 112 | s = "result: #{-> 42}" | ||
| 113 | assert.same s, "result: 42" | ||
| 114 | |||
| 115 | it "should support table indexing in interpolation", -> | ||
| 116 | t = {value: 100} | ||
| 117 | s = "value: #{t.value}" | ||
| 118 | assert.same s, "value: 100" | ||
| 119 | |||
| 120 | it "should handle escaped characters correctly", -> | ||
| 121 | s = "tab:\t, newline:\n, return:\r" | ||
| 122 | assert.is_true s\match("\t") ~= nil | ||
| 123 | assert.is_true s\match("\n") ~= nil | ||
| 124 | |||
| 125 | it "should support string methods with colon syntax", -> | ||
| 126 | s = "hello" | ||
| 127 | assert.same s\sub(1, 2), "he" | ||
| 128 | |||
| 129 | it "should work in expressions", -> | ||
| 130 | result = "hello" .. " world" | ||
| 131 | assert.same result, "hello world" | ||
| 132 | |||
| 133 | it "should support octal escape", -> | ||
| 134 | s = "\65" | ||
| 135 | assert.same s, "A" | ||
| 136 | |||
| 137 | it "should support hex escape", -> | ||
| 138 | s = "\x41" | ||
| 139 | assert.same s, "A" | ||
| 140 | |||
| 141 | it "should support unicode escape", -> | ||
| 142 | s = "\u{4e16}" | ||
| 143 | assert.same s, "世" | ||
diff --git a/spec/inputs/test/switch_spec.yue b/spec/inputs/test/switch_spec.yue new file mode 100644 index 0000000..3696cbe --- /dev/null +++ b/spec/inputs/test/switch_spec.yue | |||
| @@ -0,0 +1,267 @@ | |||
| 1 | describe "switch", -> | ||
| 2 | it "should match single value", -> | ||
| 3 | value = "cool" | ||
| 4 | result = switch value | ||
| 5 | when "cool" | ||
| 6 | "matched" | ||
| 7 | else | ||
| 8 | "not matched" | ||
| 9 | assert.same result, "matched" | ||
| 10 | |||
| 11 | it "should match multiple values with or", -> | ||
| 12 | hi = "world" | ||
| 13 | matched = false | ||
| 14 | switch hi | ||
| 15 | when "one", "two" | ||
| 16 | matched = true | ||
| 17 | assert.is_false matched | ||
| 18 | |||
| 19 | hi = "one" | ||
| 20 | switch hi | ||
| 21 | when "one", "two" | ||
| 22 | matched = true | ||
| 23 | assert.is_true matched | ||
| 24 | |||
| 25 | it "should execute else branch when no match", -> | ||
| 26 | value = "other" | ||
| 27 | result = switch value | ||
| 28 | when "cool" | ||
| 29 | "matched cool" | ||
| 30 | when "yeah" | ||
| 31 | "matched yeah" | ||
| 32 | else | ||
| 33 | "else branch" | ||
| 34 | assert.same result, "else branch" | ||
| 35 | |||
| 36 | it "should destructure table with single key", -> | ||
| 37 | tb = {x: 100} | ||
| 38 | result = switch tb | ||
| 39 | when :x | ||
| 40 | x | ||
| 41 | else | ||
| 42 | "no match" | ||
| 43 | assert.same result, 100 | ||
| 44 | |||
| 45 | it "should destructure table with multiple keys", -> | ||
| 46 | tb = {x: 100, y: 200} | ||
| 47 | result = switch tb | ||
| 48 | when :x, :y | ||
| 49 | x + y | ||
| 50 | else | ||
| 51 | "no match" | ||
| 52 | assert.same result, 300 | ||
| 53 | |||
| 54 | it "should destructure table with default values", -> | ||
| 55 | tb = {a: 1} | ||
| 56 | switch tb | ||
| 57 | when {:a = 1, :b = 2} | ||
| 58 | assert.same a, 1 | ||
| 59 | assert.same b, 2 | ||
| 60 | |||
| 61 | it "should destructure nested tables", -> | ||
| 62 | dict = { | ||
| 63 | {} | ||
| 64 | {1, 2, 3} | ||
| 65 | a: b: c: 1 | ||
| 66 | x: y: z: 1 | ||
| 67 | } | ||
| 68 | matched = false | ||
| 69 | switch dict | ||
| 70 | when { | ||
| 71 | first | ||
| 72 | {one, two, three} | ||
| 73 | a: b: :c | ||
| 74 | x: y: :z | ||
| 75 | } | ||
| 76 | matched = first == {} and one == 1 and two == 2 and three == 3 and c == 1 and z == 1 | ||
| 77 | assert.is_true matched | ||
| 78 | |||
| 79 | it "should destructure arrays with exact match", -> | ||
| 80 | tb = {1, 2, 3} | ||
| 81 | result = switch tb | ||
| 82 | when [1, 2, 3] | ||
| 83 | "exact match" | ||
| 84 | else | ||
| 85 | "no match" | ||
| 86 | assert.same result, "exact match" | ||
| 87 | |||
| 88 | it "should destructure arrays with variables", -> | ||
| 89 | tb = {1, "b", 3} | ||
| 90 | result = switch tb | ||
| 91 | when [1, b, 3] | ||
| 92 | b | ||
| 93 | else | ||
| 94 | "no match" | ||
| 95 | assert.same result, "b" | ||
| 96 | |||
| 97 | it "should destructure arrays with defaults", -> | ||
| 98 | tb = {1, 2} | ||
| 99 | result = switch tb | ||
| 100 | when [1, 2, b = 3] | ||
| 101 | b | ||
| 102 | else | ||
| 103 | "no match" | ||
| 104 | assert.same result, 3 | ||
| 105 | |||
| 106 | it "should match pattern with __class", -> | ||
| 107 | class ClassA | ||
| 108 | class ClassB | ||
| 109 | item = ClassA! | ||
| 110 | result = switch item | ||
| 111 | when __class: ClassA | ||
| 112 | "Object A" | ||
| 113 | when __class: ClassB | ||
| 114 | "Object B" | ||
| 115 | else | ||
| 116 | "unknown" | ||
| 117 | assert.same result, "Object A" | ||
| 118 | |||
| 119 | it "should match pattern with metatable", -> | ||
| 120 | tb = setmetatable {}, {__mode: "v"} | ||
| 121 | metatable_matched = false | ||
| 122 | switch tb | ||
| 123 | when <>: mt | ||
| 124 | metatable_matched = mt ~= nil | ||
| 125 | assert.is_true metatable_matched | ||
| 126 | |||
| 127 | it "should use switch as expression in assignment", -> | ||
| 128 | tb = {x: "abc"} | ||
| 129 | matched = switch tb | ||
| 130 | when 1 | ||
| 131 | "1" | ||
| 132 | when :x | ||
| 133 | x | ||
| 134 | when false | ||
| 135 | "false" | ||
| 136 | else | ||
| 137 | nil | ||
| 138 | assert.same matched, "abc" | ||
| 139 | |||
| 140 | it "should use switch in return statement", -> | ||
| 141 | fn = (tb) -> | ||
| 142 | switch tb | ||
| 143 | when nil | ||
| 144 | "invalid" | ||
| 145 | when :a, :b | ||
| 146 | "#{a + b}" | ||
| 147 | when 1, 2, 3, 4, 5 | ||
| 148 | "number 1 - 5" | ||
| 149 | else | ||
| 150 | "should not reach here" | ||
| 151 | assert.same fn({a: 1, b: 2}), "3" | ||
| 152 | assert.same fn(3), "number 1 - 5" | ||
| 153 | assert.same fn(nil), "invalid" | ||
| 154 | |||
| 155 | it "should support pattern matching assignment with :=", -> | ||
| 156 | v = "hello" | ||
| 157 | matched = false | ||
| 158 | switch v := "hello" | ||
| 159 | when "hello" | ||
| 160 | matched = true | ||
| 161 | else | ||
| 162 | matched = false | ||
| 163 | assert.is_true matched | ||
| 164 | assert.same v, "hello" | ||
| 165 | |||
| 166 | it "should match with computed expressions", -> | ||
| 167 | hi = 4 | ||
| 168 | matched = false | ||
| 169 | switch hi | ||
| 170 | when 3+1, (-> 4)!, 5-1 | ||
| 171 | matched = true | ||
| 172 | assert.is_true matched | ||
| 173 | |||
| 174 | it "should handle nested array destructuring", -> | ||
| 175 | tb = { | ||
| 176 | {a: 1, b: 2} | ||
| 177 | {a: 3, b: 4} | ||
| 178 | {a: 5, b: 6} | ||
| 179 | "fourth" | ||
| 180 | } | ||
| 181 | result = switch tb | ||
| 182 | when [ | ||
| 183 | {a: 1, b: 2} | ||
| 184 | {a: 3, b: 4} | ||
| 185 | {a: 5, b: 6} | ||
| 186 | fourth | ||
| 187 | ] | ||
| 188 | fourth | ||
| 189 | else | ||
| 190 | "no match" | ||
| 191 | assert.same result, "fourth" | ||
| 192 | |||
| 193 | it "should match combined patterns", -> | ||
| 194 | tb = {success: true, result: "data"} | ||
| 195 | result = switch tb | ||
| 196 | when success: true, :result | ||
| 197 | {"success", result} | ||
| 198 | when success: false | ||
| 199 | {"failed", result} | ||
| 200 | else | ||
| 201 | {"invalid"} | ||
| 202 | assert.same result, {"success", "data"} | ||
| 203 | |||
| 204 | it "should match type discriminated patterns", -> | ||
| 205 | tb = {type: "success", content: "data"} | ||
| 206 | result = switch tb | ||
| 207 | when {type: "success", :content} | ||
| 208 | {"success", content} | ||
| 209 | when {type: "error", :content} | ||
| 210 | {"error", content} | ||
| 211 | else | ||
| 212 | {"invalid"} | ||
| 213 | assert.same result, {"success", "data"} | ||
| 214 | |||
| 215 | it "should match with wildcard array capture", -> | ||
| 216 | clientData = {"Meta", "CUST_1001", "CHK123"} | ||
| 217 | metadata = nil | ||
| 218 | customerId = nil | ||
| 219 | checksum = nil | ||
| 220 | switch clientData | ||
| 221 | when [...capturedMetadata, customerId, checksum] | ||
| 222 | metadata = capturedMetadata | ||
| 223 | assert.same metadata, {"Meta"} | ||
| 224 | assert.same customerId, "CUST_1001" | ||
| 225 | assert.same checksum, "CHK123" | ||
| 226 | |||
| 227 | it "should work with complex tuple patterns", -> | ||
| 228 | handlePath = (segments) -> | ||
| 229 | switch segments | ||
| 230 | when [..._, resource, action] | ||
| 231 | {"Resource: #{resource}", "Action: #{action}"} | ||
| 232 | else | ||
| 233 | {"no match"} | ||
| 234 | result = handlePath {"admin", "logs", "view"} | ||
| 235 | assert.same result, {"Resource: logs", "Action: view"} | ||
| 236 | |||
| 237 | it "should match boolean false correctly", -> | ||
| 238 | items = { | ||
| 239 | {x: 100, y: 200} | ||
| 240 | {width: 300, height: 400} | ||
| 241 | false | ||
| 242 | } | ||
| 243 | results = {} | ||
| 244 | for item in *items | ||
| 245 | switch item | ||
| 246 | when :x, :y | ||
| 247 | table.insert results, "Vec2" | ||
| 248 | when :width, :height | ||
| 249 | table.insert results, "Size" | ||
| 250 | when false | ||
| 251 | table.insert results, "None" | ||
| 252 | assert.same results, {"Vec2", "Size", "None"} | ||
| 253 | |||
| 254 | it "should handle switch with then syntax", -> | ||
| 255 | value = "cool" | ||
| 256 | result = switch value | ||
| 257 | when "cool" then "matched cool" | ||
| 258 | else "else branch" | ||
| 259 | assert.same result, "matched cool" | ||
| 260 | |||
| 261 | it "should handle switch in function call", -> | ||
| 262 | getValue = -> | ||
| 263 | switch something | ||
| 264 | when 1 then "yes" | ||
| 265 | else "no" | ||
| 266 | something = 1 | ||
| 267 | assert.same getValue!, "yes" | ||
diff --git a/spec/inputs/test/vararg_spec.yue b/spec/inputs/test/vararg_spec.yue new file mode 100644 index 0000000..4d2557f --- /dev/null +++ b/spec/inputs/test/vararg_spec.yue | |||
| @@ -0,0 +1,69 @@ | |||
| 1 | describe "vararg", -> | ||
| 2 | it "should pass varargs to function", -> | ||
| 3 | sum = (...) -> | ||
| 4 | total = 0 | ||
| 5 | for i = 1, select("#", ...) | ||
| 6 | if type(select(i, ...)) == "number" | ||
| 7 | total += select(i, ...) | ||
| 8 | total | ||
| 9 | result = sum 1, 2, 3, 4, 5 | ||
| 10 | assert.same result, 15 | ||
| 11 | |||
| 12 | it "should handle empty varargs", -> | ||
| 13 | fn = (...) -> select "#", ... | ||
| 14 | result = fn! | ||
| 15 | assert.same result, 0 | ||
| 16 | |||
| 17 | it "should spread varargs in function call", -> | ||
| 18 | receiver = (a, b, c) -> {a, b, c} | ||
| 19 | source = -> 1, 2, 3 | ||
| 20 | result = receiver source! | ||
| 21 | assert.same result, {1, 2, 3} | ||
| 22 | |||
| 23 | it "should use varargs in table", -> | ||
| 24 | fn = (...) -> {...} | ||
| 25 | result = fn 1, 2, 3 | ||
| 26 | assert.same result, {1, 2, 3} | ||
| 27 | |||
| 28 | it "should forward varargs", -> | ||
| 29 | middle = (fn, ...) -> fn(...) | ||
| 30 | inner = (a, b, c) -> a + b + c | ||
| 31 | result = middle inner, 1, 2, 3 | ||
| 32 | assert.same result, 6 | ||
| 33 | |||
| 34 | it "should count varargs with select", -> | ||
| 35 | fn = (...) -> select "#", ... | ||
| 36 | assert.same fn(1, 2, 3), 3 | ||
| 37 | assert.same fn("a", "b"), 2 | ||
| 38 | assert.same fn!, 0 | ||
| 39 | |||
| 40 | it "should select from varargs", -> | ||
| 41 | fn = (...) -> select 2, ... | ||
| 42 | result = fn 1, 2, 3 | ||
| 43 | assert.same result, 2 | ||
| 44 | |||
| 45 | it "should work with named parameters and varargs", -> | ||
| 46 | fn = (first, ...) -> | ||
| 47 | {first, select("#", ...)} | ||
| 48 | result = fn "first", "second", "third" | ||
| 49 | assert.same result, {"first", 2} | ||
| 50 | |||
| 51 | it "should handle nil in varargs", -> | ||
| 52 | fn = (...) -> | ||
| 53 | count = select "#", ... | ||
| 54 | has_nil = false | ||
| 55 | for i = 1, count | ||
| 56 | has_nil = true if select(i, ...) == nil | ||
| 57 | {count, has_nil} | ||
| 58 | result = fn 1, nil, 3 | ||
| 59 | assert.same result, {3, true} | ||
| 60 | |||
| 61 | it "should work with table unpack", -> | ||
| 62 | fn = (...) -> {...} | ||
| 63 | result = fn table.unpack {1, 2, 3} | ||
| 64 | assert.same result, {1, 2, 3} | ||
| 65 | |||
| 66 | it "should work with varargs in comprehension", -> | ||
| 67 | fn = (...) -> [x * 2 for x in *{...}] | ||
| 68 | result = fn 1, 2, 3, 4, 5 | ||
| 69 | assert.same result, {2, 4, 6, 8, 10} | ||
diff --git a/spec/inputs/test/with_spec.yue b/spec/inputs/test/with_spec.yue new file mode 100644 index 0000000..c3b8428 --- /dev/null +++ b/spec/inputs/test/with_spec.yue | |||
| @@ -0,0 +1,104 @@ | |||
| 1 | describe "with", -> | ||
| 2 | it "should access property with . syntax", -> | ||
| 3 | obj = {value: 42} | ||
| 4 | with obj | ||
| 5 | result = .value | ||
| 6 | assert.same result, 42 | ||
| 7 | |||
| 8 | it "should call method with : syntax", -> | ||
| 9 | obj = {func: -> "result"} | ||
| 10 | with obj | ||
| 11 | result = \func! | ||
| 12 | assert.same result, "result" | ||
| 13 | |||
| 14 | it "should work as statement", -> | ||
| 15 | obj = {x: 10, y: 20} | ||
| 16 | with obj | ||
| 17 | .sum = .x + .y | ||
| 18 | assert.same obj.sum, 30 | ||
| 19 | |||
| 20 | it "should support nested with", -> | ||
| 21 | outer = {inner: {value: 100}} | ||
| 22 | with outer.inner | ||
| 23 | result = .value | ||
| 24 | assert.same result, 100 | ||
| 25 | |||
| 26 | it "should work with? safely", -> | ||
| 27 | obj = {x: 5} | ||
| 28 | with obj | ||
| 29 | result = .x | ||
| 30 | assert.same result, 5 | ||
| 31 | |||
| 32 | it "should work with if inside with", -> | ||
| 33 | obj = {x: 10, y: 20} | ||
| 34 | with obj | ||
| 35 | if .x > 5 | ||
| 36 | result = .x + .y | ||
| 37 | assert.same result, 30 | ||
| 38 | |||
| 39 | it "should work with switch inside with", -> | ||
| 40 | obj = {type: "add", a: 5, b: 3} | ||
| 41 | with obj | ||
| 42 | result = switch .type | ||
| 43 | when "add" then .a + .b | ||
| 44 | else 0 | ||
| 45 | assert.same result, 8 | ||
| 46 | |||
| 47 | it "should work with loop inside with", -> | ||
| 48 | obj = {items: {1, 2, 3}} | ||
| 49 | sum = 0 | ||
| 50 | with obj | ||
| 51 | for item in *.items | ||
| 52 | sum += item | ||
| 53 | assert.same sum, 6 | ||
| 54 | |||
| 55 | it "should work with destructure", -> | ||
| 56 | obj = {x: 1, y: 2, z: 3} | ||
| 57 | with obj | ||
| 58 | {x, y, z} = obj | ||
| 59 | assert.same x, 1 | ||
| 60 | assert.same y, 2 | ||
| 61 | assert.same z, 3 | ||
| 62 | |||
| 63 | it "should handle simple with body", -> | ||
| 64 | obj = {value: 42} | ||
| 65 | with obj | ||
| 66 | .value2 = 100 | ||
| 67 | assert.same obj.value2, 100 | ||
| 68 | |||
| 69 | it "should work with return inside", -> | ||
| 70 | obj = {value: 100} | ||
| 71 | fn = -> | ||
| 72 | with obj | ||
| 73 | return .value | ||
| 74 | assert.same fn!, 100 | ||
| 75 | |||
| 76 | it "should work with break inside", -> | ||
| 77 | sum = 0 | ||
| 78 | for i = 1, 5 | ||
| 79 | obj = {value: i} | ||
| 80 | with obj | ||
| 81 | if .value == 3 | ||
| 82 | break | ||
| 83 | sum += .value | ||
| 84 | assert.same sum, 3 -- 1 + 2 | ||
| 85 | |||
| 86 | it "should chain property access", -> | ||
| 87 | obj = {a: {b: {c: 42}}} | ||
| 88 | with obj.a.b | ||
| 89 | result = .c | ||
| 90 | assert.same result, 42 | ||
| 91 | |||
| 92 | it "should work with multiple statements", -> | ||
| 93 | obj = {x: 1, y: 2} | ||
| 94 | sum = 0 | ||
| 95 | with obj | ||
| 96 | sum += .x | ||
| 97 | sum += .y | ||
| 98 | assert.same sum, 3 | ||
| 99 | |||
| 100 | it "should preserve object reference", -> | ||
| 101 | obj = {value: 42} | ||
| 102 | with obj | ||
| 103 | .value = 100 | ||
| 104 | assert.same obj.value, 100 | ||
