config/lang: implicit builtins are coming in
This commit is contained in:
parent
36b6601baf
commit
d12bf66403
|
@ -0,0 +1,24 @@
|
|||
package lang
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/hashicorp/terraform/config/lang/ast"
|
||||
)
|
||||
|
||||
func registerBuiltins(scope *Scope) {
|
||||
if scope.FuncMap == nil {
|
||||
scope.FuncMap = make(map[string]Function)
|
||||
}
|
||||
scope.FuncMap["__builtin_IntToString"] = builtinIntToString()
|
||||
}
|
||||
|
||||
func builtinIntToString() Function {
|
||||
return Function{
|
||||
ArgTypes: []ast.Type{ast.TypeInt},
|
||||
ReturnType: ast.TypeString,
|
||||
Callback: func(args []interface{}) (interface{}, error) {
|
||||
return strconv.FormatInt(int64(args[0].(int)), 10), nil
|
||||
},
|
||||
}
|
||||
}
|
|
@ -155,7 +155,9 @@ func (v *TypeCheck) visitVariableAccess(n *ast.VariableAccess) {
|
|||
}
|
||||
|
||||
func (v *TypeCheck) createErr(n ast.Node, str string) {
|
||||
v.err = fmt.Errorf("%s: %s", n.Pos(), str)
|
||||
pos := n.Pos()
|
||||
v.err = fmt.Errorf("At column %d, line %d: %s",
|
||||
pos.Column, pos.Line, str)
|
||||
}
|
||||
|
||||
func (v *TypeCheck) implicitConversion(
|
||||
|
|
|
@ -27,9 +27,17 @@ type SemanticChecker func(ast.Node) error
|
|||
// Execute executes the given ast.Node and returns its final value, its
|
||||
// type, and an error if one exists.
|
||||
func (e *Engine) Execute(root ast.Node) (interface{}, ast.Type, error) {
|
||||
// Copy the scope so we can add our builtins
|
||||
scope := e.scope()
|
||||
implicitMap := map[ast.Type]map[ast.Type]string{
|
||||
ast.TypeInt: {
|
||||
ast.TypeString: "__builtin_IntToString",
|
||||
},
|
||||
}
|
||||
|
||||
// Build our own semantic checks that we always run
|
||||
tv := &TypeCheck{Scope: e.GlobalScope}
|
||||
ic := &IdentifierCheck{Scope: e.GlobalScope}
|
||||
tv := &TypeCheck{Scope: scope, Implicit: implicitMap}
|
||||
ic := &IdentifierCheck{Scope: scope}
|
||||
|
||||
// Build up the semantic checks for execution
|
||||
checks := make(
|
||||
|
@ -46,10 +54,20 @@ func (e *Engine) Execute(root ast.Node) (interface{}, ast.Type, error) {
|
|||
}
|
||||
|
||||
// Execute
|
||||
v := &executeVisitor{Scope: e.GlobalScope}
|
||||
v := &executeVisitor{Scope: scope}
|
||||
return v.Visit(root)
|
||||
}
|
||||
|
||||
func (e *Engine) scope() *Scope {
|
||||
var scope Scope
|
||||
if e.GlobalScope != nil {
|
||||
scope = *e.GlobalScope
|
||||
}
|
||||
|
||||
registerBuiltins(&scope)
|
||||
return &scope
|
||||
}
|
||||
|
||||
// executeVisitor is the visitor used to do the actual execution of
|
||||
// a program. Note at this point it is assumed that the types check out
|
||||
// and the identifiers exist.
|
||||
|
|
|
@ -77,6 +77,23 @@ func TestEngineExecute(t *testing.T) {
|
|||
"foo foobar",
|
||||
ast.TypeString,
|
||||
},
|
||||
|
||||
// Testing implicit type conversions
|
||||
|
||||
{
|
||||
"foo ${bar}",
|
||||
&Scope{
|
||||
VarMap: map[string]Variable{
|
||||
"bar": Variable{
|
||||
Value: 42,
|
||||
Type: ast.TypeInt,
|
||||
},
|
||||
},
|
||||
},
|
||||
false,
|
||||
"foo 42",
|
||||
ast.TypeString,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
|
|
Loading…
Reference in New Issue