package tests import ( "testing" assert "git.sharkk.net/Go/Assert" "git.sharkk.net/Sharkk/Mako/compiler" "git.sharkk.net/Sharkk/Mako/lexer" "git.sharkk.net/Sharkk/Mako/parser" "git.sharkk.net/Sharkk/Mako/types" "git.sharkk.net/Sharkk/Mako/vm" ) // Helper function to execute Mako code func executeMakoWithErrors(code string) (*vm.VM, []string) { lex := lexer.New(code) p := parser.New(lex) program := p.ParseProgram() errors := p.Errors() bytecode := compiler.Compile(program) virtualMachine := vm.New() virtualMachine.Run(bytecode) return virtualMachine, errors } func TestTypeConversions(t *testing.T) { // Test automatic type conversions in operations vm, errors := executeMakoWithErrors(` // String concatenation result1 = "Hello " + "World"; // Should work // Using boolean in a condition if true then result2 = "Boolean works in condition"; end // Numeric conditions if 1 then result3 = "Numeric 1 is truthy"; end if 0 then result4 = "This should not execute"; else result4 = "Numeric 0 is falsy"; end `) assert.Equal(t, 0, len(errors)) // Verify results result1, found := vm.GetGlobal("result1") assert.True(t, found) assert.Equal(t, types.TypeString, result1.Type) assert.Equal(t, "Hello World", result1.Data.(string)) result2, found := vm.GetGlobal("result2") assert.True(t, found) assert.Equal(t, types.TypeString, result2.Type) assert.Equal(t, "Boolean works in condition", result2.Data.(string)) result3, found := vm.GetGlobal("result3") assert.True(t, found) assert.Equal(t, types.TypeString, result3.Type) assert.Equal(t, "Numeric 1 is truthy", result3.Data.(string)) result4, found := vm.GetGlobal("result4") assert.True(t, found) assert.Equal(t, types.TypeString, result4.Type) assert.Equal(t, "Numeric 0 is falsy", result4.Data.(string)) } func TestEdgeCases(t *testing.T) { // Test edge cases that might cause issues vm, errors := executeMakoWithErrors(` // Deep nesting table = { level1 = { level2 = { level3 = { level4 = { value = "Deep nesting" } } } } }; result1 = table["level1"]["level2"]["level3"]["level4"]["value"]; // Empty tables emptyTable = {}; result2 = emptyTable["nonexistent"]; // Should return null // Table with invalid access someTable = { key = "value" }; someTable[123] = "numeric key"; // Should work result3 = someTable[123]; // Should retrieve the value `) assert.Equal(t, 0, len(errors)) // Verify deep nesting result result1, found := vm.GetGlobal("result1") assert.True(t, found) assert.Equal(t, types.TypeString, result1.Type) assert.Equal(t, "Deep nesting", result1.Data.(string)) // Verify empty table result result2, found := vm.GetGlobal("result2") assert.True(t, found) assert.Equal(t, types.TypeNull, result2.Type) // Verify numeric key result result3, found := vm.GetGlobal("result3") assert.True(t, found) assert.Equal(t, types.TypeString, result3.Type) assert.Equal(t, "numeric key", result3.Data.(string)) } func TestErrorHandling(t *testing.T) { // Test error handling in the parser _, errors := executeMakoWithErrors(` // Invalid syntax - missing semicolon x = 5 y = 10; `) // Should have at least one error assert.True(t, len(errors) > 0) // Test parser recovery _, errors = executeMakoWithErrors(` // Missing end keyword if x < 10 then echo "x is less than 10"; // end - missing `) // Should have at least one error assert.True(t, len(errors) > 0) } func TestNestedScopes(t *testing.T) { // Test nested scopes and variable shadowing vm, errors := executeMakoWithErrors(` x = "global"; { echo x; // Should be "global" x = "outer"; echo x; // Should be "outer" { echo x; // Should be "outer" x = "inner"; echo x; // Should be "inner" { echo x; // Should be "inner" x = "innermost"; echo x; // Should be "innermost" } echo x; // Should be "inner" again } echo x; // Should be "outer" again } echo x; // Should be "global" again result = x; `) assert.Equal(t, 0, len(errors)) // Verify that x returns to its global value result, found := vm.GetGlobal("result") assert.True(t, found) assert.Equal(t, types.TypeString, result.Type) assert.Equal(t, "global", result.Data.(string)) // Also verify x directly x, found := vm.GetGlobal("x") assert.True(t, found) assert.Equal(t, types.TypeString, x.Type) assert.Equal(t, "global", x.Data.(string)) } func TestComplexExpressions(t *testing.T) { // Test complex expressions with multiple operators vm, errors := executeMakoWithErrors(` // Arithmetic precedence result1 = 5 + 10 * 2; // Should be 25, not 30 // Parentheses override precedence result2 = (5 + 10) * 2; // Should be 30 // Combined comparison and logical operators x = 5; y = 10; z = 15; result3 = x < y and y < z; // Should be true result4 = x > y or y < z; // Should be true result5 = not (x > y); // Should be true // Complex conditional if x < y and y < z then result6 = "Condition passed"; else result6 = "Condition failed"; end `) assert.Equal(t, 0, len(errors)) // Verify arithmetic precedence result1, found := vm.GetGlobal("result1") assert.True(t, found) assert.Equal(t, types.TypeNumber, result1.Type) assert.Equal(t, 25.0, result1.Data.(float64)) // Verify parentheses precedence result2, found := vm.GetGlobal("result2") assert.True(t, found) assert.Equal(t, types.TypeNumber, result2.Type) assert.Equal(t, 30.0, result2.Data.(float64)) // Verify logical operators result3, found := vm.GetGlobal("result3") assert.True(t, found) assert.Equal(t, types.TypeBoolean, result3.Type) assert.Equal(t, true, result3.Data.(bool)) result4, found := vm.GetGlobal("result4") assert.True(t, found) assert.Equal(t, types.TypeBoolean, result4.Type) assert.Equal(t, true, result4.Data.(bool)) result5, found := vm.GetGlobal("result5") assert.True(t, found) assert.Equal(t, types.TypeBoolean, result5.Type) assert.Equal(t, true, result5.Data.(bool)) // Verify complex conditional result6, found := vm.GetGlobal("result6") assert.True(t, found) assert.Equal(t, types.TypeString, result6.Type) assert.Equal(t, "Condition passed", result6.Data.(string)) } func TestNestedTables(t *testing.T) { // Test nested tables and complex access patterns vm, errors := executeMakoWithErrors(` // Define a nested table config = { server = { host = "localhost", port = 8080, settings = { timeout = 30, retries = 3 } }, database = { host = "db.example.com", port = 5432, credentials = { username = "admin", password = "secret" } } }; // Access nested values result1 = config["server"]["host"]; result2 = config["server"]["settings"]["timeout"]; result3 = config["database"]["credentials"]["username"]; // Update nested values config["server"]["settings"]["timeout"] = 60; result4 = config["server"]["settings"]["timeout"]; // Add new nested values config["logging"] = { level = "info", file = "app.log" }; result5 = config["logging"]["level"]; `) assert.Equal(t, 0, len(errors)) // Verify nested table access result1, found := vm.GetGlobal("result1") assert.True(t, found) assert.Equal(t, types.TypeString, result1.Type) assert.Equal(t, "localhost", result1.Data.(string)) result2, found := vm.GetGlobal("result2") assert.True(t, found) assert.Equal(t, types.TypeNumber, result2.Type) assert.Equal(t, 30.0, result2.Data.(float64)) result3, found := vm.GetGlobal("result3") assert.True(t, found) assert.Equal(t, types.TypeString, result3.Type) assert.Equal(t, "admin", result3.Data.(string)) // Verify nested table update result4, found := vm.GetGlobal("result4") assert.True(t, found) assert.Equal(t, types.TypeNumber, result4.Type) assert.Equal(t, 60.0, result4.Data.(float64)) // Verify adding new nested values result5, found := vm.GetGlobal("result5") assert.True(t, found) assert.Equal(t, types.TypeString, result5.Type) assert.Equal(t, "info", result5.Data.(string)) } func TestTableAsArguments(t *testing.T) { // Test using tables as arguments vm, errors := executeMakoWithErrors(` // Define a table person = { name = "John", age = 30 }; // Use as index lookup = { John = "Developer", Jane = "Designer" }; // Access using value from another table role = lookup[person["name"]]; result1 = role; // Should print "Developer" `) assert.Equal(t, 0, len(errors)) // Verify table as argument result1, found := vm.GetGlobal("result1") assert.True(t, found) assert.Equal(t, types.TypeString, result1.Type) assert.Equal(t, "Developer", result1.Data.(string)) // Test complex table indexing - this is more advanced and might not work yet complexVM, complexErrors := executeMakoWithErrors(` // Test with table as key - might not work in current implementation matrix = {}; // Instead use a string representation matrix["0,0"] = "origin"; result2 = matrix["0,0"]; `) // For now, we expect no errors with the string-based approach assert.Equal(t, 0, len(complexErrors)) result2, found := complexVM.GetGlobal("result2") assert.True(t, found) assert.Equal(t, types.TypeString, result2.Type) assert.Equal(t, "origin", result2.Data.(string)) } func TestTableEquality(t *testing.T) { // Test table equality and using tables as keys vm, errors := executeMakoWithErrors(` // Test table equality t1 = { x = 1, y = 2 }; t2 = { x = 1, y = 2 }; t3 = { x = 1, y = 3 }; // Test basic equality eq_result1 = t1 == t2; // Should be true eq_result2 = t1 == t3; // Should be false eq_result3 = t2 == t3; // Should be false // Test using tables as keys lookup = {}; lookup[t1] = "first table"; lookup[t3] = "third table"; // Try to retrieve values using table keys result1 = lookup[t1]; // Should be "first table" result2 = lookup[t2]; // Should also be "first table" because t1 and t2 are equal result3 = lookup[t3]; // Should be "third table" // Test with nested tables nested1 = { table = t1, name = "nested1" }; nested2 = { table = t2, name = "nested2" }; nested3 = { table = t3, name = "nested3" }; // Check equality with nested tables neq_result1 = nested1 == nested2; // Should be false (different names) neq_result2 = nested1 == nested3; // Should be false (different tables and names) `) assert.Equal(t, 0, len(errors)) // Verify basic table equality results eq_result1, found := vm.GetGlobal("eq_result1") assert.True(t, found) assert.Equal(t, types.TypeBoolean, eq_result1.Type) assert.Equal(t, true, eq_result1.Data.(bool)) eq_result2, found := vm.GetGlobal("eq_result2") assert.True(t, found) assert.Equal(t, types.TypeBoolean, eq_result2.Type) assert.Equal(t, false, eq_result2.Data.(bool)) // Verify table as key results result1, found := vm.GetGlobal("result1") assert.True(t, found) assert.Equal(t, types.TypeString, result1.Type) assert.Equal(t, "first table", result1.Data.(string)) result2, found := vm.GetGlobal("result2") assert.True(t, found) assert.Equal(t, types.TypeString, result2.Type) assert.Equal(t, "first table", result2.Data.(string)) result3, found := vm.GetGlobal("result3") assert.True(t, found) assert.Equal(t, types.TypeString, result3.Type) assert.Equal(t, "third table", result3.Data.(string)) // Verify nested table equality neq_result1, found := vm.GetGlobal("neq_result1") assert.True(t, found) assert.Equal(t, types.TypeBoolean, neq_result1.Type) assert.Equal(t, false, neq_result1.Data.(bool)) }