diff options
Diffstat (limited to 'vendor/github.com/hashicorp/hil/builtins.go')
-rw-r--r-- | vendor/github.com/hashicorp/hil/builtins.go | 331 |
1 files changed, 331 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/hil/builtins.go b/vendor/github.com/hashicorp/hil/builtins.go new file mode 100644 index 00000000..909c788a --- /dev/null +++ b/vendor/github.com/hashicorp/hil/builtins.go @@ -0,0 +1,331 @@ +package hil + +import ( + "errors" + "strconv" + + "github.com/hashicorp/hil/ast" +) + +// NOTE: All builtins are tested in engine_test.go + +func registerBuiltins(scope *ast.BasicScope) *ast.BasicScope { + if scope == nil { + scope = new(ast.BasicScope) + } + if scope.FuncMap == nil { + scope.FuncMap = make(map[string]ast.Function) + } + + // Implicit conversions + scope.FuncMap["__builtin_BoolToString"] = builtinBoolToString() + scope.FuncMap["__builtin_FloatToInt"] = builtinFloatToInt() + scope.FuncMap["__builtin_FloatToString"] = builtinFloatToString() + scope.FuncMap["__builtin_IntToFloat"] = builtinIntToFloat() + scope.FuncMap["__builtin_IntToString"] = builtinIntToString() + scope.FuncMap["__builtin_StringToInt"] = builtinStringToInt() + scope.FuncMap["__builtin_StringToFloat"] = builtinStringToFloat() + scope.FuncMap["__builtin_StringToBool"] = builtinStringToBool() + + // Math operations + scope.FuncMap["__builtin_IntMath"] = builtinIntMath() + scope.FuncMap["__builtin_FloatMath"] = builtinFloatMath() + scope.FuncMap["__builtin_BoolCompare"] = builtinBoolCompare() + scope.FuncMap["__builtin_FloatCompare"] = builtinFloatCompare() + scope.FuncMap["__builtin_IntCompare"] = builtinIntCompare() + scope.FuncMap["__builtin_StringCompare"] = builtinStringCompare() + scope.FuncMap["__builtin_Logical"] = builtinLogical() + return scope +} + +func builtinFloatMath() ast.Function { + return ast.Function{ + ArgTypes: []ast.Type{ast.TypeInt}, + Variadic: true, + VariadicType: ast.TypeFloat, + ReturnType: ast.TypeFloat, + Callback: func(args []interface{}) (interface{}, error) { + op := args[0].(ast.ArithmeticOp) + result := args[1].(float64) + for _, raw := range args[2:] { + arg := raw.(float64) + switch op { + case ast.ArithmeticOpAdd: + result += arg + case ast.ArithmeticOpSub: + result -= arg + case ast.ArithmeticOpMul: + result *= arg + case ast.ArithmeticOpDiv: + result /= arg + } + } + + return result, nil + }, + } +} + +func builtinIntMath() ast.Function { + return ast.Function{ + ArgTypes: []ast.Type{ast.TypeInt}, + Variadic: true, + VariadicType: ast.TypeInt, + ReturnType: ast.TypeInt, + Callback: func(args []interface{}) (interface{}, error) { + op := args[0].(ast.ArithmeticOp) + result := args[1].(int) + for _, raw := range args[2:] { + arg := raw.(int) + switch op { + case ast.ArithmeticOpAdd: + result += arg + case ast.ArithmeticOpSub: + result -= arg + case ast.ArithmeticOpMul: + result *= arg + case ast.ArithmeticOpDiv: + if arg == 0 { + return nil, errors.New("divide by zero") + } + + result /= arg + case ast.ArithmeticOpMod: + if arg == 0 { + return nil, errors.New("divide by zero") + } + + result = result % arg + } + } + + return result, nil + }, + } +} + +func builtinBoolCompare() ast.Function { + return ast.Function{ + ArgTypes: []ast.Type{ast.TypeInt, ast.TypeBool, ast.TypeBool}, + Variadic: false, + ReturnType: ast.TypeBool, + Callback: func(args []interface{}) (interface{}, error) { + op := args[0].(ast.ArithmeticOp) + lhs := args[1].(bool) + rhs := args[2].(bool) + + switch op { + case ast.ArithmeticOpEqual: + return lhs == rhs, nil + case ast.ArithmeticOpNotEqual: + return lhs != rhs, nil + default: + return nil, errors.New("invalid comparison operation") + } + }, + } +} + +func builtinFloatCompare() ast.Function { + return ast.Function{ + ArgTypes: []ast.Type{ast.TypeInt, ast.TypeFloat, ast.TypeFloat}, + Variadic: false, + ReturnType: ast.TypeBool, + Callback: func(args []interface{}) (interface{}, error) { + op := args[0].(ast.ArithmeticOp) + lhs := args[1].(float64) + rhs := args[2].(float64) + + switch op { + case ast.ArithmeticOpEqual: + return lhs == rhs, nil + case ast.ArithmeticOpNotEqual: + return lhs != rhs, nil + case ast.ArithmeticOpLessThan: + return lhs < rhs, nil + case ast.ArithmeticOpLessThanOrEqual: + return lhs <= rhs, nil + case ast.ArithmeticOpGreaterThan: + return lhs > rhs, nil + case ast.ArithmeticOpGreaterThanOrEqual: + return lhs >= rhs, nil + default: + return nil, errors.New("invalid comparison operation") + } + }, + } +} + +func builtinIntCompare() ast.Function { + return ast.Function{ + ArgTypes: []ast.Type{ast.TypeInt, ast.TypeInt, ast.TypeInt}, + Variadic: false, + ReturnType: ast.TypeBool, + Callback: func(args []interface{}) (interface{}, error) { + op := args[0].(ast.ArithmeticOp) + lhs := args[1].(int) + rhs := args[2].(int) + + switch op { + case ast.ArithmeticOpEqual: + return lhs == rhs, nil + case ast.ArithmeticOpNotEqual: + return lhs != rhs, nil + case ast.ArithmeticOpLessThan: + return lhs < rhs, nil + case ast.ArithmeticOpLessThanOrEqual: + return lhs <= rhs, nil + case ast.ArithmeticOpGreaterThan: + return lhs > rhs, nil + case ast.ArithmeticOpGreaterThanOrEqual: + return lhs >= rhs, nil + default: + return nil, errors.New("invalid comparison operation") + } + }, + } +} + +func builtinStringCompare() ast.Function { + return ast.Function{ + ArgTypes: []ast.Type{ast.TypeInt, ast.TypeString, ast.TypeString}, + Variadic: false, + ReturnType: ast.TypeBool, + Callback: func(args []interface{}) (interface{}, error) { + op := args[0].(ast.ArithmeticOp) + lhs := args[1].(string) + rhs := args[2].(string) + + switch op { + case ast.ArithmeticOpEqual: + return lhs == rhs, nil + case ast.ArithmeticOpNotEqual: + return lhs != rhs, nil + default: + return nil, errors.New("invalid comparison operation") + } + }, + } +} + +func builtinLogical() ast.Function { + return ast.Function{ + ArgTypes: []ast.Type{ast.TypeInt}, + Variadic: true, + VariadicType: ast.TypeBool, + ReturnType: ast.TypeBool, + Callback: func(args []interface{}) (interface{}, error) { + op := args[0].(ast.ArithmeticOp) + result := args[1].(bool) + for _, raw := range args[2:] { + arg := raw.(bool) + switch op { + case ast.ArithmeticOpLogicalOr: + result = result || arg + case ast.ArithmeticOpLogicalAnd: + result = result && arg + default: + return nil, errors.New("invalid logical operator") + } + } + + return result, nil + }, + } +} + +func builtinFloatToInt() ast.Function { + return ast.Function{ + ArgTypes: []ast.Type{ast.TypeFloat}, + ReturnType: ast.TypeInt, + Callback: func(args []interface{}) (interface{}, error) { + return int(args[0].(float64)), nil + }, + } +} + +func builtinFloatToString() ast.Function { + return ast.Function{ + ArgTypes: []ast.Type{ast.TypeFloat}, + ReturnType: ast.TypeString, + Callback: func(args []interface{}) (interface{}, error) { + return strconv.FormatFloat( + args[0].(float64), 'g', -1, 64), nil + }, + } +} + +func builtinIntToFloat() ast.Function { + return ast.Function{ + ArgTypes: []ast.Type{ast.TypeInt}, + ReturnType: ast.TypeFloat, + Callback: func(args []interface{}) (interface{}, error) { + return float64(args[0].(int)), nil + }, + } +} + +func builtinIntToString() ast.Function { + return ast.Function{ + ArgTypes: []ast.Type{ast.TypeInt}, + ReturnType: ast.TypeString, + Callback: func(args []interface{}) (interface{}, error) { + return strconv.FormatInt(int64(args[0].(int)), 10), nil + }, + } +} + +func builtinStringToInt() ast.Function { + return ast.Function{ + ArgTypes: []ast.Type{ast.TypeInt}, + ReturnType: ast.TypeString, + Callback: func(args []interface{}) (interface{}, error) { + v, err := strconv.ParseInt(args[0].(string), 0, 0) + if err != nil { + return nil, err + } + + return int(v), nil + }, + } +} + +func builtinStringToFloat() ast.Function { + return ast.Function{ + ArgTypes: []ast.Type{ast.TypeString}, + ReturnType: ast.TypeFloat, + Callback: func(args []interface{}) (interface{}, error) { + v, err := strconv.ParseFloat(args[0].(string), 64) + if err != nil { + return nil, err + } + + return v, nil + }, + } +} + +func builtinBoolToString() ast.Function { + return ast.Function{ + ArgTypes: []ast.Type{ast.TypeBool}, + ReturnType: ast.TypeString, + Callback: func(args []interface{}) (interface{}, error) { + return strconv.FormatBool(args[0].(bool)), nil + }, + } +} + +func builtinStringToBool() ast.Function { + return ast.Function{ + ArgTypes: []ast.Type{ast.TypeString}, + ReturnType: ast.TypeBool, + Callback: func(args []interface{}) (interface{}, error) { + v, err := strconv.ParseBool(args[0].(string)) + if err != nil { + return nil, err + } + + return v, nil + }, + } +} |