diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2018-01-06 14:46:52 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2018-01-08 12:52:31 +0100 |
| commit | 402a0dc87e7d51812a18fa76feeb46d66efda175 (patch) | |
| tree | 03ae2832257917a68829137b0a504f6f8c2e499a /pkg/compiler/check.go | |
| parent | 93b4c6f135aeecbb756fe8c8a3d46c7a05412a54 (diff) | |
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.
Diffstat (limited to 'pkg/compiler/check.go')
| -rw-r--r-- | pkg/compiler/check.go | 64 |
1 files changed, 57 insertions, 7 deletions
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 } @@ -148,19 +155,32 @@ 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]) } |
