-
-
Couldn't load subscription status.
- Fork 463
Typecasting values automatically #703
-
There are cases where the numbers are sent as strings in the param map. Is there a way to typecast based on the expression?
Expression: 7 < "47" == true
Beta Was this translation helpful? Give feedback.
All reactions
Replies: 1 comment 3 replies
-
Beta Was this translation helpful? Give feedback.
All reactions
-
Hi @antonmedv Thanks for the inputs, I've tried the following simple approach to verify data type can be corrected, and it wasn't working.
var stringType = reflect.TypeOf("")
var numberType = reflect.TypeOf(0)
type NumberPatcher struct{}
func (NumberPatcher) Visit(node *ast.Node) {
if n, ok := (*node).(*ast.BinaryNode); ok {
l := n.Left
r := n.Right
fmt.Printf("Left %s (type: %s) \n", l, l.Type())
fmt.Printf("Right %s (type: %s) \n", r, r.Type())
fmt.Printf("Operator %s \n", n.Operator)
switch n.Operator {
case "<", ">", ">=", "<=", "==", "!=", "+", "-":
if l.Type() == stringType && r.Type() == numberType {
// patch the node to number type
l.SetType(numberType)
ast.Patch(&l, l)
} else if l.Type() == numberType && r.Type() == stringType {
// patch the node to number type
r.SetType(numberType)
ast.Patch(&r, r)
// ast.Patch(&r, &ast.IntegerNode{Value: 47})
}
}
}
}
func TestExpPatcher(t *testing.T) {
env := map[string]interface{}{
"a": 7,
"b": "47",
}
code := `a < b == true`
program, err := expr.Compile(code, expr.Env(env), expr.AllowUndefinedVariables(), expr.Patch(NumberPatcher{}))
if err != nil {
panic(err)
}
output, err := expr.Run(program, env)
if err != nil {
panic(err)
}
fmt.Println("Output:", output)
}
Even I tried with hardcoded node type, but no luck :(, Please correct me on the approach to handling different data types.
ast.Patch(&r, &ast.IntegerNode{Value: 47})
From the codebase, noticed type information is lost with the patch method, may I know what that means?
// Patch replaces the node with a new one.
// Location information is preserved.
// Type information is lost.
func Patch(node *Node, newNode Node) {
...
}
Also, I looked into the code, we compare data types in the binary node, is there a possibility to address handling different data types?
Line 269 in da04c55
Beta Was this translation helpful? Give feedback.
All reactions
-
The issue you're encountering seems to stem from trying to modify the abstract syntax tree (AST) node types to force a type cast from string to int (or other numeric types) during the expression evaluation phase. Your approach with the NumberPatcher seems logical, but it’s important to ensure that the AST manipulation is done correctly and that the types are compatible after patching.
Here are some suggestions that might help you resolve this issue:
-
Ensure Proper Type Conversion Logic: When patching the AST nodes, ensure that you are converting the string values to integers correctly. The
ast.Patch()function replaces one node with another, but it doesn't automatically convert the data type. The patched node should be a correctly typed node (e.g.,ast.IntegerNode). -
Type Information in Patching: As you noticed,
ast.Patch()does lose type information. This can be problematic when the rest of the code relies on type information for further processing or evaluation. Ensure that after patching, the new node reflects the correct type. The loss of type information might be affecting the downstream type checks, causing unexpected behavior. -
Alternative Approach: Instead of directly manipulating the AST, consider pre-processing the expression or the environment map before passing it to
expr.Compile(). For instance, you could convert all numeric strings in the environment map to their respective numeric types. This way, the expression you pass in will already have the correct types, and you won’t need to perform any AST manipulation.func convertEnvValues(env map[string]interface{}) { for k, v := range env { switch v := v.(type) { case string: if num, err := strconv.Atoi(v); err == nil { env[k] = num } } } }
-
Using
int()in Expression: Another straightforward approach is to enforce the type conversion directly in the expression string using theint()function provided byexpr. For instance:code := `a < int(b) == true`
This way, you sidestep the need for AST manipulation altogether.
-
Debugging AST Changes: Add more debugging output to verify that the AST nodes are being modified as expected. Sometimes, the issue might not be in the typecasting itself but in the timing or the context in which the node is being patched.
Beta Was this translation helpful? Give feedback.
All reactions
-
@antonmedv Thanks for the inputs, will try out the options.
Beta Was this translation helpful? Give feedback.