feat: parse functions

This commit is contained in:
debugtalk
2021-10-03 21:16:05 +08:00
parent cc736e9aed
commit 36b3e21880
2 changed files with 71 additions and 0 deletions

View File

@@ -55,6 +55,12 @@ func parseData(raw interface{}, variablesMapping map[string]interface{}) interfa
value := rawValue.String()
value = strings.TrimSpace(value)
return parseString(value, variablesMapping)
case reflect.Slice:
parsedSlice := make([]interface{}, rawValue.Len())
for i := 0; i < rawValue.Len(); i++ {
parsedSlice[i] = parseData(rawValue.Index(i).Interface(), variablesMapping)
}
return parsedSlice
case reflect.Map: // convert any map to map[string]interface{}
parsedMap := make(map[string]interface{})
for _, k := range rawValue.MapKeys() {
@@ -109,6 +115,9 @@ func parseString(raw string, variablesMapping map[string]interface{}) interface{
parsedString += remainedString[0:startPosition]
remainedString = remainedString[startPosition:]
// Notice: notation priority
// $$ > ${func($a, $b)} > $var
// search $$, use $$ to escape $ notation
if strings.HasPrefix(remainedString, "$$") { // found $$
matchStartPosition += 2
@@ -117,6 +126,35 @@ func parseString(raw string, variablesMapping map[string]interface{}) interface{
continue
}
// search function like ${func($a, $b)}
funcMatched := regexCompileFunction.FindStringSubmatch(remainedString)
if len(funcMatched) == 3 {
funcName := funcMatched[1]
argsStr := funcMatched[2]
arguments, err := parseFunctionArguments(argsStr)
if err != nil {
return raw
}
parsedArgs := parseData(arguments, variablesMapping).([]interface{})
result, err := callFunc(funcName, parsedArgs...)
if err != nil {
return raw
}
if funcMatched[0] == raw {
// raw_string is a function, e.g. "${add_one(3)}", return its eval value directly
return result
}
// raw_string contains one or many functions, e.g. "abc${add_one(3)}def"
matchStartPosition += len(funcMatched[0])
parsedString += fmt.Sprintf("%v", result)
remainedString = raw[matchStartPosition:]
log.Printf("[parseString] parsedString: %v, matchStartPosition: %v", parsedString, matchStartPosition)
continue
}
// search variable like ${var} or $var
varMatched := regexCompileVariable.FindStringSubmatch(remainedString)
if len(varMatched) == 3 {

View File

@@ -166,6 +166,7 @@ func TestParseDataStringWithVariables(t *testing.T) {
}
}
}
func TestParseDataStringWithVariablesAbnormal(t *testing.T) {
variablesMapping := map[string]interface{}{
"var_1": "abc",
@@ -374,3 +375,35 @@ func TestParseFunctionArguments(t *testing.T) {
}
}
}
func TestParseDataStringWithFunctions(t *testing.T) {
variablesMapping := map[string]interface{}{
"n": 5,
"a": 12.3,
"b": 3.45,
}
if !assert.Len(t, parseData("${gen_random_string(5)}", variablesMapping), 5) {
t.Fail()
}
if !assert.Len(t, parseData("${gen_random_string($n)}", variablesMapping), 5) {
t.Fail()
}
if !assert.Len(t, parseData("123${gen_random_string(5)}abc", variablesMapping), 11) {
t.Fail()
}
if !assert.Len(t, parseData("123${gen_random_string($n)}abc", variablesMapping), 11) {
t.Fail()
}
if !assert.Equal(t, parseData("${max($a, $b)}", variablesMapping), 12.3) {
t.Fail()
}
if !assert.Equal(t, parseData("abc${max($a, $b)}123", variablesMapping), "abc12.3123") {
t.Fail()
}
if !assert.Equal(t, parseData("abc${max($a, 3.45)}123", variablesMapping), "abc12.3123") {
t.Fail()
}
}