diff --git a/processor/regex.go b/processor/regex.go index 3e1e984..187c126 100644 --- a/processor/regex.go +++ b/processor/regex.go @@ -9,75 +9,9 @@ import ( lua "github.com/yuin/gopher-lua" "modify/logger" + "modify/utils" ) -// RegexProcessor implements the Processor interface using regex patterns -type RegexProcessor struct{} - -// ToLua sets capture groups as Lua variables (v1, v2, etc. for numeric values and s1, s2, etc. for strings) -func (p *RegexProcessor) ToLua(L *lua.LState, data interface{}) error { - captureGroups, ok := data.([]*CaptureGroup) - if !ok { - return fmt.Errorf("expected []*CaptureGroup for captures, got %T", data) - } - - groupindex := 0 - for _, capture := range captureGroups { - if capture.Name == "" { - // We don't want to change the name of the capture group - // Even if it's empty - tempName := fmt.Sprintf("%d", groupindex+1) - groupindex++ - - L.SetGlobal("s"+tempName, lua.LString(capture.Value)) - - val, err := strconv.ParseFloat(capture.Value, 64) - if err == nil { - L.SetGlobal("v"+tempName, lua.LNumber(val)) - } - } else { - val, err := strconv.ParseFloat(capture.Value, 64) - if err == nil { - L.SetGlobal(capture.Name, lua.LNumber(val)) - } else { - L.SetGlobal(capture.Name, lua.LString(capture.Value)) - } - } - } - - return nil -} - -// FromLua implements the Processor interface for RegexProcessor -func (p *RegexProcessor) FromLuaCustom(L *lua.LState, captureGroups []*CaptureGroup) ([]*CaptureGroup, error) { - captureIndex := 0 - for _, capture := range captureGroups { - if capture.Name == "" { - capture.Name = fmt.Sprintf("%d", captureIndex+1) - - vVarName := fmt.Sprintf("v%s", capture.Name) - sVarName := fmt.Sprintf("s%s", capture.Name) - captureIndex++ - - vLuaVal := L.GetGlobal(vVarName) - sLuaVal := L.GetGlobal(sVarName) - - if sLuaVal.Type() == lua.LTString { - capture.Updated = sLuaVal.String() - } - // Numbers have priority - if vLuaVal.Type() == lua.LTNumber { - capture.Updated = vLuaVal.String() - } - } else { - // Easy shit - capture.Updated = L.GetGlobal(capture.Name).String() - } - } - - return captureGroups, nil -} - type CaptureGroup struct { Name string Value string @@ -86,8 +20,10 @@ type CaptureGroup struct { } // ProcessContent applies regex replacement with Lua processing -func (p *RegexProcessor) ProcessContent(content string, pattern string, luaExpr string) (string, int, int, error) { - pattern = ResolveRegexPlaceholders(pattern) +func ProcessRegex(content string, command utils.ModifyCommand) (string, int, int, error) { + // We don't HAVE to do this multiple times for a pattern + // But it's quick enough for us to not care + pattern := resolveRegexPlaceholders(command.Pattern) logger.Debug("Compiling regex pattern: %s", pattern) compiledPattern, err := regexp.Compile(pattern) if err != nil { @@ -96,8 +32,11 @@ func (p *RegexProcessor) ProcessContent(content string, pattern string, luaExpr } logger.Debug("Compiled pattern successfully: %s", pattern) - previous := luaExpr - luaExpr = BuildLuaScript(luaExpr) + // Same here, it's just string concatenation, it won't kill us + // More important is that we don't fuck up the command + // But we shouldn't be able to since it's passed by value + previous := command.LuaExpr + luaExpr := BuildLuaScript(command.LuaExpr) logger.Debug("Transformed Lua expression: %q → %q", previous, luaExpr) // Initialize Lua environment @@ -199,7 +138,7 @@ func (p *RegexProcessor) ProcessContent(content string, pattern string, luaExpr captureGroups = deduplicateGroups(captureGroups) - if err := p.ToLua(L, captureGroups); err != nil { + if err := toLua(L, captureGroups); err != nil { logger.Error("Failed to set Lua variables: %v", err) continue } @@ -213,7 +152,7 @@ func (p *RegexProcessor) ProcessContent(content string, pattern string, luaExpr logger.Trace("Lua script executed successfully") // Get modifications from Lua - captureGroups, err = p.FromLuaCustom(L, captureGroups) + captureGroups, err = fromLua(L, captureGroups) if err != nil { logger.Error("Failed to retrieve modifications from Lua: %v", err) continue @@ -314,7 +253,7 @@ func deduplicateGroups(captureGroups []*CaptureGroup) []*CaptureGroup { // If it were not here our !num in a named capture group would // Expand to another capture group in the capture group // We really only want one (our named) capture group -func ResolveRegexPlaceholders(pattern string) string { +func resolveRegexPlaceholders(pattern string) string { // Handle special pattern modifications if !strings.HasPrefix(pattern, "(?s)") { pattern = "(?s)" + pattern @@ -348,3 +287,67 @@ func ResolveRegexPlaceholders(pattern string) string { }) return pattern } + +// ToLua sets capture groups as Lua variables (v1, v2, etc. for numeric values and s1, s2, etc. for strings) +func toLua(L *lua.LState, data interface{}) error { + captureGroups, ok := data.([]*CaptureGroup) + if !ok { + return fmt.Errorf("expected []*CaptureGroup for captures, got %T", data) + } + + groupindex := 0 + for _, capture := range captureGroups { + if capture.Name == "" { + // We don't want to change the name of the capture group + // Even if it's empty + tempName := fmt.Sprintf("%d", groupindex+1) + groupindex++ + + L.SetGlobal("s"+tempName, lua.LString(capture.Value)) + + val, err := strconv.ParseFloat(capture.Value, 64) + if err == nil { + L.SetGlobal("v"+tempName, lua.LNumber(val)) + } + } else { + val, err := strconv.ParseFloat(capture.Value, 64) + if err == nil { + L.SetGlobal(capture.Name, lua.LNumber(val)) + } else { + L.SetGlobal(capture.Name, lua.LString(capture.Value)) + } + } + } + + return nil +} + +// FromLua implements the Processor interface for RegexProcessor +func fromLua(L *lua.LState, captureGroups []*CaptureGroup) ([]*CaptureGroup, error) { + captureIndex := 0 + for _, capture := range captureGroups { + if capture.Name == "" { + capture.Name = fmt.Sprintf("%d", captureIndex+1) + + vVarName := fmt.Sprintf("v%s", capture.Name) + sVarName := fmt.Sprintf("s%s", capture.Name) + captureIndex++ + + vLuaVal := L.GetGlobal(vVarName) + sLuaVal := L.GetGlobal(sVarName) + + if sLuaVal.Type() == lua.LTString { + capture.Updated = sLuaVal.String() + } + // Numbers have priority + if vLuaVal.Type() == lua.LTNumber { + capture.Updated = vLuaVal.String() + } + } else { + // Easy shit + capture.Updated = L.GetGlobal(capture.Name).String() + } + } + + return captureGroups, nil +}