config/lang: completed type checking

This commit is contained in:
Mitchell Hashimoto 2015-01-12 00:35:43 -08:00
parent 662760da11
commit a0926de4a9
2 changed files with 72 additions and 2 deletions

View File

@ -46,8 +46,31 @@ func (v *TypeVisitor) visit(raw ast.Node) {
}
func (v *TypeVisitor) visitCall(n *ast.Call) {
// TODO
v.stackPush(ast.TypeString)
// Look up the function in the map
function, ok := v.FuncMap[n.Func]
if !ok {
v.createErr(n, fmt.Sprintf("unknown function called: %s", n.Func))
return
}
// The arguments are on the stack in reverse order, so pop them off.
args := make([]ast.Type, len(n.Args))
for i, _ := range n.Args {
args[len(n.Args)-1-i] = v.stackPop()
}
// Verify the args
for i, expected := range function.ArgTypes {
if args[i] != expected {
v.createErr(n, fmt.Sprintf(
"%s: argument %d should be %s, got %s",
n.Func, i+1, expected, args[i]))
return
}
}
// Return type
v.stackPush(function.ReturnType)
}
func (v *TypeVisitor) visitConcat(n *ast.Concat) {

View File

@ -46,6 +46,38 @@ func TestTypeVisitor(t *testing.T) {
false,
},
{
`foo ${rand("42")}`,
&TypeVisitor{
FuncMap: map[string]Function{
"rand": Function{
ArgTypes: []ast.Type{ast.TypeString},
ReturnType: ast.TypeString,
Callback: func([]interface{}) (interface{}, error) {
return "42", nil
},
},
},
},
false,
},
{
`foo ${rand(42)}`,
&TypeVisitor{
FuncMap: map[string]Function{
"rand": Function{
ArgTypes: []ast.Type{ast.TypeString},
ReturnType: ast.TypeString,
Callback: func([]interface{}) (interface{}, error) {
return "42", nil
},
},
},
},
true,
},
{
"foo ${bar}",
&TypeVisitor{
@ -58,6 +90,21 @@ func TestTypeVisitor(t *testing.T) {
},
true,
},
{
"foo ${rand()}",
&TypeVisitor{
FuncMap: map[string]Function{
"rand": Function{
ReturnType: ast.TypeInt,
Callback: func([]interface{}) (interface{}, error) {
return 42, nil
},
},
},
},
true,
},
}
for _, tc := range cases {