From 402a0dc87e7d51812a18fa76feeb46d66efda175 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Sat, 6 Jan 2018 14:46:52 +0100 Subject: sys: support type aliases (aka typedefs) Complex types that are often repeated can be given short type aliases using the following syntax: ``` type identifier underlying_type ``` For example: ``` type signalno int32[0:65] type net_port proc[20000, 4, int16be] ``` Then, type alias can be used instead of the underlying type in any contexts. Underlying type needs to be described as if it's a struct field, that is, with the base type if it's required. However, type alias can be used as syscall arguments as well. Underlying types are currently restricted to integer types, `ptr`, `ptr64`, `const`, `flags` and `proc` types. --- pkg/compiler/check.go | 64 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 57 insertions(+), 7 deletions(-) (limited to 'pkg/compiler/check.go') diff --git a/pkg/compiler/check.go b/pkg/compiler/check.go index bfe1c9d75..ff87ead79 100644 --- a/pkg/compiler/check.go +++ b/pkg/compiler/check.go @@ -34,7 +34,7 @@ func (comp *compiler) checkNames() { calls := make(map[string]*ast.Call) for _, decl := range comp.desc.Nodes { switch decl.(type) { - case *ast.Resource, *ast.Struct: + case *ast.Resource, *ast.Struct, *ast.TypeDef: pos, typ, name := decl.Info() if reservedName[name] { comp.error(pos, "%v uses reserved name %v", typ, name) @@ -49,6 +49,11 @@ func (comp *compiler) checkNames() { name, prev.Pos) continue } + if prev := comp.typedefs[name]; prev != nil { + comp.error(pos, "type %v redeclared, previously declared as type alias at %v", + name, prev.Pos) + continue + } if prev := comp.structs[name]; prev != nil { _, typ, _ := prev.Info() comp.error(pos, "type %v redeclared, previously declared as %v at %v", @@ -57,6 +62,8 @@ func (comp *compiler) checkNames() { } if res, ok := decl.(*ast.Resource); ok { comp.resources[name] = res + } else if n, ok := decl.(*ast.TypeDef); ok { + comp.typedefs[name] = n } else if str, ok := decl.(*ast.Struct); ok { comp.structs[name] = str } @@ -146,21 +153,34 @@ func (comp *compiler) checkFields() { } func (comp *compiler) checkTypes() { + for _, decl := range comp.desc.Nodes { + switch n := decl.(type) { + case *ast.TypeDef: + if comp.typedefs[n.Name.Name] == nil { + continue + } + err0 := comp.errors + comp.checkType(n.Type, false, false, false, false, true, true) + if err0 != comp.errors { + delete(comp.typedefs, n.Name.Name) + } + } + } for _, decl := range comp.desc.Nodes { switch n := decl.(type) { case *ast.Resource: - comp.checkType(n.Base, false, false, false, true) + comp.checkType(n.Base, false, false, false, true, false, false) case *ast.Struct: for _, f := range n.Fields { - comp.checkType(f.Type, false, false, !n.IsUnion, false) + comp.checkType(f.Type, false, false, !n.IsUnion, false, false, false) } comp.checkStruct(n) case *ast.Call: for _, a := range n.Args { - comp.checkType(a.Type, true, false, false, false) + comp.checkType(a.Type, true, false, false, false, false, false) } if n.Ret != nil { - comp.checkType(n.Ret, true, true, false, false) + comp.checkType(n.Ret, true, true, false, false, false, false) } } } @@ -459,7 +479,7 @@ func (comp *compiler) checkStruct(n *ast.Struct) { } } -func (comp *compiler) checkType(t *ast.Type, isArg, isRet, isStruct, isResourceBase bool) { +func (comp *compiler) checkType(t *ast.Type, isArg, isRet, isStruct, isResourceBase, isTypedef, isTypedefCtx bool) { if unexpected, _, ok := checkTypeKind(t, kindIdent); !ok { comp.error(t.Pos, "unexpected %v, expect type", unexpected) return @@ -469,6 +489,32 @@ func (comp *compiler) checkType(t *ast.Type, isArg, isRet, isStruct, isResourceB comp.error(t.Pos, "unknown type %v", t.Ident) return } + if desc == typeTypedef { + if isTypedefCtx { + comp.error(t.Pos, "type aliases can't refer to other type aliases") + return + } + if t.HasColon { + comp.error(t.Pos, "type alias %v with ':'", t.Ident) + return + } + if len(t.Args) != 0 { + comp.error(t.Pos, "type alias %v with arguments", t.Ident) + return + } + *t = *comp.typedefs[t.Ident].Type.Clone(t.Pos).(*ast.Type) + desc = comp.getTypeDesc(t) + if isArg && desc.NeedBase { + baseTypePos := len(t.Args) - 1 + if t.Args[baseTypePos].Ident == "opt" { + baseTypePos-- + } + copy(t.Args[baseTypePos:], t.Args[baseTypePos+1:]) + t.Args = t.Args[:len(t.Args)-1] + } + comp.checkType(t, isArg, isRet, isStruct, isResourceBase, isTypedef, isTypedefCtx) + return + } if t.HasColon { if !desc.AllowColon { comp.error(t.Pos2, "unexpected ':'") @@ -487,6 +533,10 @@ func (comp *compiler) checkType(t *ast.Type, isArg, isRet, isStruct, isResourceB comp.error(t.Pos, "%v can't be syscall argument", t.Ident) return } + if isTypedef && !desc.CanBeTypedef { + comp.error(t.Pos, "%v can't be type alias target", t.Ident) + return + } if isResourceBase && !desc.ResourceBase { comp.error(t.Pos, "%v can't be resource base (int types can)", t.Ident) return @@ -519,7 +569,7 @@ func (comp *compiler) checkType(t *ast.Type, isArg, isRet, isStruct, isResourceB err0 := comp.errors for i, arg := range args { if desc.Args[i].Type == typeArgType { - comp.checkType(arg, false, isRet, false, false) + comp.checkType(arg, false, isRet, false, false, false, isTypedefCtx) } else { comp.checkTypeArg(t, arg, desc.Args[i]) } -- cgit mrf-deployment