introduced mutators

This commit is contained in:
Timon Ringwald 2022-04-18 17:39:41 +02:00
parent 9f51afa15f
commit 86ac1ebcf2
2 changed files with 116 additions and 4 deletions

89
main.go
View File

@ -18,8 +18,21 @@ var (
// format string with {0} as placeholders
// {0} always matches the whole line
// {1} and onwards match their respective sub groups
//
// You can optionally specify a printf-syntax for formatting like this: {1:%s} or {1:%02d}
// printf-syntax is currently supported for: strings, floats, integers
// printf-syntax is currently supported for: strings, floats, integers.
//
// Addtionally mutators can be provided
// to further manipulate the value using the given syntax: {1:%d:+1}
//
// The value mutated by can also be a back reference to another group
// using round brackets like this: {1:%d:+(2)}}
//
// Multiple mutators can be used at once: {1:%d:+2*3-(2)}
// Be aware that they will be applied strictly from left to right!
//
// The following number mutators (integers and floats) are allowed:
// + - * / ^ %
output = flag.String("o", "{0}", "output pattern")
// don't ignore lines which do not match against input.
@ -31,7 +44,9 @@ var (
// it may be useful to have a boolean flag for this behavior
lineParseAmount = flag.Int("n", 1, "amount of lines to feed into input pattern")
replacePattern = regexp.MustCompile(`\{(\d+)(?::(.*?))?\}`)
replacePattern = regexp.MustCompile(`\{(\d+)(?::(.*?))?(?::(.*?))?\}`)
numMutationPattern = regexp.MustCompile(`([+\-*/])(\d+|\((\d+)\))`)
)
func main() {
@ -100,10 +115,12 @@ func replaceVars(format string, vars ...string) string {
if strings.HasSuffix(rplFmt, "d") { // replace integers
value, _ := strconv.ParseInt(vars[varIndex], 10, 64)
format = strings.Replace(format, rplStr, fmt.Sprintf(rplFmt, value), 1)
mutate := numMut2func[int64](replacement[3])
format = strings.Replace(format, rplStr, fmt.Sprintf(rplFmt, mutate(value, vars)), 1)
} else if strings.HasSuffix(rplFmt, "f") { // replace floats
value, _ := strconv.ParseFloat(vars[varIndex], 64)
format = strings.Replace(format, rplStr, fmt.Sprintf(rplFmt, value), 1)
mutate := numMut2func[float64](replacement[3])
format = strings.Replace(format, rplStr, fmt.Sprintf(rplFmt, mutate(value, vars)), 1)
} else { // replace strings
format = strings.Replace(format, rplStr, fmt.Sprintf(rplFmt, vars[varIndex]), 1)
}
@ -112,3 +129,67 @@ func replaceVars(format string, vars ...string) string {
return format
}
var numMutatorCache = map[string]interface{}{}
func numMut2func[T int64 | float64](mutation string) (f func(value T, vars []string) T) {
if mutation == "" {
return func(value T, vars []string) T { return value }
}
// caching
if v, ok := numMutatorCache[mutation]; ok {
return v.(func(value T, vars []string) T)
}
defer func() { numMutatorCache[mutation] = f }()
matches := numMutationPattern.FindAllStringSubmatch(mutation, -1)
mutators := make([]NumMutator, 0, len(matches))
var err error
for _, match := range matches {
mut := NumMutator{Op: NewNumOperatorFromString(match[1])}
if match[3] == "" {
mut.Value, err = strconv.Atoi(match[2])
mut.Var = false
if err != nil {
panic("invalid number in number mutator: " + match[2])
}
} else {
mut.Var = true
mut.Value, err = strconv.Atoi(match[3])
if err != nil {
panic("invalid back reference group in number mutator: " + match[2])
}
}
mutators = append(mutators, mut)
}
return func(value T, vars []string) T {
for _, mutator := range mutators {
var otherValue T
if mutator.Var {
other, err := strconv.Atoi(vars[mutator.Value])
if err != nil {
panic("back reference group for number mutator is not a number")
}
otherValue = T(other)
} else {
otherValue = T(mutator.Value)
}
switch mutator.Op {
case NumOperatorAdd:
value += otherValue
case NumOperatorSub:
value -= otherValue
case NumOperatorMul:
value *= otherValue
case NumOperatorDiv:
value /= otherValue
default:
}
}
return value
}
}

31
mutator.go Normal file
View File

@ -0,0 +1,31 @@
package main
type NumMutator struct {
Op NumOperator
Var bool
Value int
}
type NumOperator string
const (
NumOperatorAdd NumOperator = "+"
NumOperatorSub NumOperator = "-"
NumOperatorMul NumOperator = "*"
NumOperatorDiv NumOperator = "/"
)
func NewNumOperatorFromString(str string) NumOperator {
switch str {
case "+":
return NumOperatorAdd
case "-":
return NumOperatorSub
case "*":
return NumOperatorMul
case "/":
return NumOperatorDiv
default:
panic("invalid number operator: " + str)
}
}