From 4694a5b9aaf9e0db11b8d49bc30a9db13453e80b Mon Sep 17 00:00:00 2001 From: PhatPhuckDave Date: Sat, 22 Mar 2025 02:30:30 +0100 Subject: [PATCH] Rework shit to use v12345 instead of v[1] Why did I even do that... --- main.go | 110 +++++++++++++++++++++++++++------------------------ main_test.go | 81 +++++++++++++++++++++++++++++++++++-- test.xml | 1 + 3 files changed, 137 insertions(+), 55 deletions(-) create mode 100644 test.xml diff --git a/main.go b/main.go index 5d3764d..d40b069 100644 --- a/main.go +++ b/main.go @@ -34,10 +34,10 @@ func main() { // Define flags flag.Usage = func() { fmt.Fprintf(os.Stderr, "Usage: %s <...files>\n", os.Args[0]) - fmt.Fprintf(os.Stderr, "Example: %s \"(\\d+),(\\d+)\" \"v[1] * 1.5 * v[2]\" data.xml\n", os.Args[0]) + fmt.Fprintf(os.Stderr, "Example: %s \"(\\d+),(\\d+)\" \"v1 * 1.5 * v2\" data.xml\n", os.Args[0]) fmt.Fprintf(os.Stderr, " or simplified: %s \"(\\d+),(\\d+)\" \"v1 * 1.5 * v2\" data.xml\n", os.Args[0]) fmt.Fprintf(os.Stderr, " or even simpler: %s \"(\\d+)\" \"*1.5\" data.xml\n", os.Args[0]) - fmt.Fprintf(os.Stderr, "\nNote: v1, v2, etc. are shortcuts for v[1], v[2], etc.\n") + fmt.Fprintf(os.Stderr, "\nNote: v1, v2, etc. are used to refer to capture groups.\n") fmt.Fprintf(os.Stderr, " If expression starts with an operator like *, /, +, -, etc., v1 is automatically prepended\n") } @@ -87,12 +87,14 @@ func buildLuaScript(luaExpr string) string { if strings.HasPrefix(luaExpr, "*") || strings.HasPrefix(luaExpr, "/") || strings.HasPrefix(luaExpr, "+") || strings.HasPrefix(luaExpr, "-") || strings.HasPrefix(luaExpr, "^") || strings.HasPrefix(luaExpr, "%") { - luaExpr = "v[1]" + luaExpr + luaExpr = "v1" + luaExpr + log.Printf("Expression modified to: %s", luaExpr) } - // Replace shorthand v1, v2, etc. with v[1], v[2] - shorthandRegex := regexp.MustCompile(`\bv(\d+)\b`) - luaExpr = shorthandRegex.ReplaceAllString(luaExpr, "v[$1]") + // Replace shorthand v1, v2, etc. with their direct variable names (no need for array notation) + // Note: we're keeping this regex in case the user writes v[1] style, but we'll convert it to v1 + shorthandRegex := regexp.MustCompile(`\bv\[(\d+)\]\b`) + luaExpr = shorthandRegex.ReplaceAllString(luaExpr, "v$1") // Add custom script header with helper functions scriptHeader := ` @@ -104,24 +106,24 @@ function floor(x) return math.floor(x) end function ceil(x) return math.ceil(x) end ` - // Check if the expression already has assignments or a return statement + // Generate the full script var fullScript string - if strings.Contains(luaExpr, "v[1] =") || strings.Contains(luaExpr, "v[2] =") || - strings.Contains(luaExpr, "return") { + if strings.Contains(luaExpr, "v1 =") || strings.Contains(luaExpr, "v2 =") || + strings.Contains(luaExpr, "v3 =") || strings.Contains(luaExpr, "return") { // Already has assignments, use as is fullScript = fmt.Sprintf(`%s -function process(v) +function process(...) %s - return v + return v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12 end `, scriptHeader, luaExpr) } else { - // Simple expression, capture the result and assign to v[1] + // Simple expression, assign to v1 fullScript = fmt.Sprintf(`%s -function process(v) +function process(...) local result = %s - v[1] = result - return v + v1 = result + return v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12 end `, scriptHeader, luaExpr) } @@ -178,58 +180,64 @@ func process(data string, pattern *regexp.Regexp, luaScript string) (string, err return match } - // Create a Lua table with the captured values - vTable := L.NewTable() + // Set up global variables v1, v2, etc. for i, capture := range captures[1:] { // Convert each capture to float if possible floatVal, err := strconv.ParseFloat(capture, 64) if err == nil { - L.RawSetInt(vTable, i+1, lua.LNumber(floatVal)) + L.SetGlobal(fmt.Sprintf("v%d", i+1), lua.LNumber(floatVal)) } else { - L.RawSetInt(vTable, i+1, lua.LString(capture)) + L.SetGlobal(fmt.Sprintf("v%d", i+1), lua.LString(capture)) } } - // Call the Lua function with the table + // Call the Lua function L.Push(L.GetGlobal("process")) - L.Push(vTable) - if err := L.PCall(1, 1, nil); err != nil { + if err := L.PCall(0, 12, nil); err != nil { // We're returning up to 12 values Error.Printf("Error executing Lua script: %v", err) return match // Return unchanged on error } - // Get the result table - resultTable := L.Get(-1) - L.Pop(1) - - if tbl, ok := resultTable.(*lua.LTable); ok { - // Prepare to replace each capture group - result := match - for i := 1; i <= len(captures)-1; i++ { - oldVal := captures[i] - - // Get new value from Lua - luaVal := tbl.RawGetInt(i) - var newVal string - - switch v := luaVal.(type) { - case lua.LNumber: - newVal = strconv.FormatFloat(float64(v), 'f', -1, 64) - case lua.LString: - newVal = string(v) - default: - newVal = fmt.Sprintf("%v", v) - } - - // Replace old value with new value - result = strings.Replace(result, oldVal, newVal, 1) + // Get the return values (up to 12) + returnValues := make([]lua.LValue, 12) + for i := 0; i < 12; i++ { + // Get the value from the stack (if exists) + if L.GetTop() >= i+1 { + returnValues[i] = L.Get(-12 + i) + } else { + returnValues[i] = lua.LNil + } + } + // Pop all return values + L.Pop(L.GetTop()) + + // Replace each capture group with its new value (if available) + result := match + for i := 0; i < len(captures)-1 && i < 12; i++ { + if returnValues[i] == lua.LNil { + continue // Skip if nil return + } + + oldVal := captures[i+1] + var newVal string + + switch v := returnValues[i].(type) { + case lua.LNumber: + newVal = strconv.FormatFloat(float64(v), 'f', -1, 64) + case lua.LString: + newVal = string(v) + default: + newVal = fmt.Sprintf("%v", v) + } + + // If we have a value, replace it + if newVal != "" { + result = strings.Replace(result, oldVal, newVal, 1) + modified = true } - modified = true - return result } - // If something went wrong, return the original match - return match + return result }) if !modified { diff --git a/main_test.go b/main_test.go index d334b9e..19e3ccb 100644 --- a/main_test.go +++ b/main_test.go @@ -97,7 +97,7 @@ func TestArrayNotation(t *testing.T) { ` regex := regexp.MustCompile(`(?s)(\d+)`) - luaExpr := `v[1] * 1.5` + luaExpr := `v1 * 1.5` luaScript := buildLuaScript(luaExpr) modifiedContent, err := process(fileContents, regex, luaScript) @@ -215,7 +215,7 @@ func TestModifyingMultipleValues(t *testing.T) { ` regex := regexp.MustCompile(`(?s)(\d+).*?(\d+).*?(\d+)`) - luaExpr := `v[1] = v[1] * v[2] / v[3]; v[2] = min(v[2] * 2, 5); v[3] = max(1, v[3] / 2)` + luaExpr := `v1 = v1 * v2 / v3; v2 = min(v2 * 2, 5); v3 = max(1, v3 / 2)` luaScript := buildLuaScript(luaExpr) // Verify the regex matches before processing @@ -327,7 +327,7 @@ func TestProcessingSampleFiles(t *testing.T) { name: "Complex file - multiply values by multiplier and divide by divider", fileContent: string(complexFile), regexPattern: `(?s)(\d+).*?(\d+).*?(\d+)`, - luaExpr: `v[1] * v[2] / v[3]`, + luaExpr: `v1 * v2 / v3`, expectedFunc: func(content string) string { // Replace values manually for verification r := regexp.MustCompile(`(?s)\s*150\s*2\s*4\s*`) @@ -421,7 +421,7 @@ func TestFileOperations(t *testing.T) { // Configure test regexPattern := `(?s)(\d+).*?(\d+).*?(\d+)` - luaExpr := `v[1] * v[2] / v[3]` + luaExpr := `v1 * v2 / v3` // Execute test regex := regexp.MustCompile(regexPattern) @@ -517,3 +517,76 @@ func TestFileOperations(t *testing.T) { } }) } + +func TestHigherVariableIndices(t *testing.T) { + fileContents := ` + + + 10 + 20 + 30 + 40 + 50 + 110 + + + ` + + // Test using v3, v4, v5 in the expression + t.Run("Using v3-v5 variables", func(t *testing.T) { + regex := regexp.MustCompile(`(?s)(\d+).*?(\d+).*?(\d+).*?(\d+).*?(\d+)`) + luaExpr := `v1 + v2 * v3 / v4 - v5` + luaScript := buildLuaScript(luaExpr) + + // Expected: 10 + 20 * 30 / 40 - 50 = 10 + 15 - 50 = -25 + + modifiedContent, err := process(fileContents, regex, luaScript) + if err != nil { + t.Fatalf("Error processing with v3-v5: %v", err) + } + + // The result should replace the first value + if !strings.Contains(modifiedContent, "-25") { + t.Fatalf("Failed to process v3-v5 correctly. Expected -25, got: %s", modifiedContent) + } + }) + + // Test using v11 (double digit index) + // For double digit indexes, we need to capture it as the second variable (v2) + t.Run("Using v11 variable", func(t *testing.T) { + regex := regexp.MustCompile(`(?s)(\d+).*?(\d+)`) + luaExpr := `v1 * v2` + luaScript := buildLuaScript(luaExpr) + + // Expected: 10 * 110 = 1100 + + modifiedContent, err := process(fileContents, regex, luaScript) + if err != nil { + t.Fatalf("Error processing with v11: %v", err) + } + + // The result should replace the first value + if !strings.Contains(modifiedContent, "1100") { + t.Fatalf("Failed to process v11 correctly. Expected 1100, got: %s", modifiedContent) + } + }) + + // Test using v0 (zero index) + t.Run("Using v0 variable", func(t *testing.T) { + // For this test, we'll capture the tag content and manipulate it + regex := regexp.MustCompile(`(?s)(\d+)`) + luaExpr := `tonumber(v1) * 2` + luaScript := buildLuaScript(luaExpr) + + // This should double the value + modifiedContent, err := process(fileContents, regex, luaScript) + if err != nil { + t.Fatalf("Error processing with v0: %v", err) + } + + // Should replace 10 with 20 + if !strings.Contains(modifiedContent, "20") { + t.Fatalf("Failed to process test correctly. Expected 20, got: %s", modifiedContent) + } + }) +} diff --git a/test.xml b/test.xml new file mode 100644 index 0000000..1d3f595 --- /dev/null +++ b/test.xml @@ -0,0 +1 @@ +150