From 414c035582c39398ddd927b5e4fdfd7a6f3aefc5 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Sat, 17 Feb 2018 17:00:53 +0100 Subject: pkg/compiler: support template template arguments Can be useful for netfilter descriptions. --- pkg/compiler/check.go | 23 +++++++++++++++++++---- pkg/compiler/testdata/all.txt | 20 ++++++++++++++++++++ pkg/compiler/testdata/errors.txt | 17 +++++++++++++++++ 3 files changed, 56 insertions(+), 4 deletions(-) (limited to 'pkg/compiler') diff --git a/pkg/compiler/check.go b/pkg/compiler/check.go index 003fe424f..e7333b9ae 100644 --- a/pkg/compiler/check.go +++ b/pkg/compiler/check.go @@ -683,12 +683,16 @@ func (comp *compiler) replaceTypedef(ctx *checkCtx, t *ast.Type, desc *typeDesc, } if typedef.Type != nil { *t = *typedef.Type.Clone().(*ast.Type) - comp.instantiate(t, typedef.Args, args) + if !comp.instantiate(t, typedef.Args, args) { + return + } } else { if comp.structs[fullTypeName] == nil { inst := typedef.Struct.Clone().(*ast.Struct) inst.Name.Name = fullTypeName - comp.instantiate(inst, typedef.Args, args) + if !comp.instantiate(inst, typedef.Args, args) { + return + } comp.checkStruct(*ctx, inst) comp.desc.Nodes = append(comp.desc.Nodes, inst) comp.structs[fullTypeName] = inst @@ -711,21 +715,31 @@ func (comp *compiler) replaceTypedef(ctx *checkCtx, t *ast.Type, desc *typeDesc, } } -func (comp *compiler) instantiate(templ ast.Node, params []*ast.Ident, args []*ast.Type) { +func (comp *compiler) instantiate(templ ast.Node, params []*ast.Ident, args []*ast.Type) bool { if len(params) == 0 { - return + return true } argMap := make(map[string]*ast.Type) for i, param := range params { argMap[param.Name] = args[i] } + err0 := comp.errors templ.Walk(ast.Recursive(func(n ast.Node) { templArg, ok := n.(*ast.Type) if !ok { return } if concreteArg := argMap[templArg.Ident]; concreteArg != nil { + origArgs := templArg.Args + if len(origArgs) != 0 && len(concreteArg.Args) != 0 { + comp.error(templArg.Pos, "both template parameter %v and its usage"+ + " have sub-arguments", templArg.Ident) + return + } *templArg = *concreteArg.Clone().(*ast.Type) + if len(origArgs) != 0 { + templArg.Args = origArgs + } } // TODO(dvyukov): somewhat hacky, but required for int8[0:CONST_ARG] // Need more checks here. E.g. that CONST_ARG does not have subargs. @@ -736,6 +750,7 @@ func (comp *compiler) instantiate(templ ast.Node, params []*ast.Ident, args []*a templArg.Pos2 = concreteArg.Pos } })) + return err0 == comp.errors } func (comp *compiler) checkTypeArg(t, arg *ast.Type, argDesc namedArg) { diff --git a/pkg/compiler/testdata/all.txt b/pkg/compiler/testdata/all.txt index 2bf76c28b..dd2a90ba3 100644 --- a/pkg/compiler/testdata/all.txt +++ b/pkg/compiler/testdata/all.txt @@ -133,6 +133,26 @@ struct0 { f2 int16 } +type templ_base0[TYPE, CONST] { + f1 TYPE + f2 const[CONST, int32] +} + +type templ_base1[TYPE, CONST] { + f2 const[CONST, int8] + f1 TYPE +} + +type templ_templ[BASE, CONST] { + f1 BASE[int8, CONST] + f2 BASE[int32, 0] +} + +templ_templ_use { + f1 templ_templ[templ_base0, 0] + f2 templ_templ[templ_base1, 1] +} + type templ_struct2[A] templ_struct0[A, int8] type templ_struct3 templ_struct2[C1] type templ_struct4 templ_struct3 diff --git a/pkg/compiler/testdata/errors.txt b/pkg/compiler/testdata/errors.txt index 2be2e65ad..f4c9cf69a 100644 --- a/pkg/compiler/testdata/errors.txt +++ b/pkg/compiler/testdata/errors.txt @@ -260,6 +260,23 @@ type templ_struct2[A] { f B ### unknown type B } +type templ_base0[TYPE] { + f1 TYPE +} + +type templ_templ0[BASE] { + f1 BASE +} + +type templ_templ1[BASE] { + f1 BASE[int16] ### both template parameter BASE and its usage have sub-arguments +} + +templ_templ_use0 { + f1 templ_templ0[templ_base0] ### template templ_base0 needs 1 arguments instead of 0 + f2 templ_templ1[templ_base0[int32]] +} + foo$200(a templ0[42, int8]) foo$202(a templ0) ### template templ0 needs 2 arguments instead of 0 foo$203(a type0[42]) ### type type0 is not a template -- cgit mrf-deployment