diff options
| -rw-r--r-- | docs/syscall_descriptions_syntax.md | 22 | ||||
| -rw-r--r-- | pkg/ast/ast.go | 14 | ||||
| -rw-r--r-- | pkg/ast/clone.go | 131 | ||||
| -rw-r--r-- | pkg/ast/format.go | 4 | ||||
| -rw-r--r-- | pkg/ast/parser.go | 14 | ||||
| -rw-r--r-- | pkg/ast/testdata/all.txt | 5 | ||||
| -rw-r--r-- | pkg/ast/walk.go | 3 | ||||
| -rw-r--r-- | pkg/compiler/check.go | 64 | ||||
| -rw-r--r-- | pkg/compiler/compiler.go | 5 | ||||
| -rw-r--r-- | pkg/compiler/compiler_test.go | 49 | ||||
| -rw-r--r-- | pkg/compiler/consts.go | 4 | ||||
| -rw-r--r-- | pkg/compiler/testdata/errors.txt | 63 | ||||
| -rw-r--r-- | pkg/compiler/types.go | 62 |
13 files changed, 324 insertions, 116 deletions
diff --git a/docs/syscall_descriptions_syntax.md b/docs/syscall_descriptions_syntax.md index 8bf6b64ee..bafe0480c 100644 --- a/docs/syscall_descriptions_syntax.md +++ b/docs/syscall_descriptions_syntax.md @@ -137,6 +137,28 @@ accept(fd sock, ...) sock listen(fd sock, backlog int32) ``` +## Type Aliases + +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. + ## Length You can specify length of a particular field in struct or a named argument by using `len`, `bytesize` and `bitsize` types, for example: diff --git a/pkg/ast/ast.go b/pkg/ast/ast.go index 4c9101f79..9e87a1b81 100644 --- a/pkg/ast/ast.go +++ b/pkg/ast/ast.go @@ -20,6 +20,10 @@ type Description struct { // Node is AST node interface. type Node interface { Info() (pos Pos, typ string, name string) + // Clone makes a deep copy of the node. + // If newPos is not zero, sets Pos of all nodes to newPos. + // If newPos is zero, Pos of nodes is left intact. + Clone(newPos Pos) Node } // Top-level AST nodes: @@ -130,6 +134,16 @@ func (n *StrFlags) Info() (Pos, string, string) { return n.Pos, "string flags", n.Name.Name } +type TypeDef struct { + Pos Pos + Name *Ident + Type *Type +} + +func (n *TypeDef) Info() (Pos, string, string) { + return n.Pos, "type", n.Name.Name +} + // Not top-level AST nodes: type Ident struct { diff --git a/pkg/ast/clone.go b/pkg/ast/clone.go index 5c2d773f7..044b6c17d 100644 --- a/pkg/ast/clone.go +++ b/pkg/ast/clone.go @@ -3,86 +3,89 @@ package ast -import ( - "fmt" -) - func Clone(desc *Description) *Description { desc1 := &Description{} for _, n := range desc.Nodes { - c, ok := n.(cloner) - if !ok { - panic(fmt.Sprintf("unknown top level decl: %#v", n)) - } - desc1.Nodes = append(desc1.Nodes, c.clone()) + desc1.Nodes = append(desc1.Nodes, n.Clone(Pos{})) } return desc1 } -type cloner interface { - clone() Node +func selectPos(newPos, oldPos Pos) Pos { + if newPos.File != "" || newPos.Off != 0 || newPos.Line != 0 || newPos.Col != 0 { + return newPos + } + return oldPos } -func (n *NewLine) clone() Node { +func (n *NewLine) Clone(newPos Pos) Node { return &NewLine{ - Pos: n.Pos, + Pos: selectPos(newPos, n.Pos), } } -func (n *Comment) clone() Node { +func (n *Comment) Clone(newPos Pos) Node { return &Comment{ - Pos: n.Pos, + Pos: selectPos(newPos, n.Pos), Text: n.Text, } } -func (n *Include) clone() Node { +func (n *Include) Clone(newPos Pos) Node { return &Include{ - Pos: n.Pos, - File: n.File.clone(), + Pos: selectPos(newPos, n.Pos), + File: n.File.Clone(newPos).(*String), } } -func (n *Incdir) clone() Node { +func (n *Incdir) Clone(newPos Pos) Node { return &Incdir{ - Pos: n.Pos, - Dir: n.Dir.clone(), + Pos: selectPos(newPos, n.Pos), + Dir: n.Dir.Clone(newPos).(*String), } } -func (n *Define) clone() Node { +func (n *Define) Clone(newPos Pos) Node { return &Define{ - Pos: n.Pos, - Name: n.Name.clone(), - Value: n.Value.clone(), + Pos: selectPos(newPos, n.Pos), + Name: n.Name.Clone(newPos).(*Ident), + Value: n.Value.Clone(newPos).(*Int), } } -func (n *Resource) clone() Node { +func (n *Resource) Clone(newPos Pos) Node { var values []*Int for _, v := range n.Values { - values = append(values, v.clone()) + values = append(values, v.Clone(newPos).(*Int)) } return &Resource{ - Pos: n.Pos, - Name: n.Name.clone(), - Base: n.Base.clone(), + Pos: selectPos(newPos, n.Pos), + Name: n.Name.Clone(newPos).(*Ident), + Base: n.Base.Clone(newPos).(*Type), Values: values, } } -func (n *Call) clone() Node { +func (n *TypeDef) Clone(newPos Pos) Node { + return &TypeDef{ + Pos: selectPos(newPos, n.Pos), + Name: n.Name.Clone(newPos).(*Ident), + Type: n.Type.Clone(newPos).(*Type), + } +} + +func (n *Call) Clone(newPos Pos) Node { var args []*Field for _, a := range n.Args { - args = append(args, a.clone()) + args = append(args, a.Clone(newPos).(*Field)) } var ret *Type if n.Ret != nil { - ret = n.Ret.clone() + ret = n.Ret.Clone(newPos).(*Type) } return &Call{ - Pos: n.Pos, - Name: n.Name.clone(), + Pos: selectPos(newPos, n.Pos), + Name: n.Name.Clone(newPos).(*Ident), CallName: n.CallName, NR: n.NR, Args: args, @@ -90,22 +93,22 @@ func (n *Call) clone() Node { } } -func (n *Struct) clone() Node { +func (n *Struct) Clone(newPos Pos) Node { var fields []*Field for _, f := range n.Fields { - fields = append(fields, f.clone()) + fields = append(fields, f.Clone(newPos).(*Field)) } var attrs []*Ident for _, a := range n.Attrs { - attrs = append(attrs, a.clone()) + attrs = append(attrs, a.Clone(newPos).(*Ident)) } var comments []*Comment for _, c := range n.Comments { - comments = append(comments, c.clone().(*Comment)) + comments = append(comments, c.Clone(newPos).(*Comment)) } return &Struct{ - Pos: n.Pos, - Name: n.Name.clone(), + Pos: selectPos(newPos, n.Pos), + Name: n.Name.Clone(newPos).(*Ident), Fields: fields, Attrs: attrs, Comments: comments, @@ -113,47 +116,47 @@ func (n *Struct) clone() Node { } } -func (n *IntFlags) clone() Node { +func (n *IntFlags) Clone(newPos Pos) Node { var values []*Int for _, v := range n.Values { - values = append(values, v.clone()) + values = append(values, v.Clone(newPos).(*Int)) } return &IntFlags{ - Pos: n.Pos, - Name: n.Name.clone(), + Pos: selectPos(newPos, n.Pos), + Name: n.Name.Clone(newPos).(*Ident), Values: values, } } -func (n *StrFlags) clone() Node { +func (n *StrFlags) Clone(newPos Pos) Node { var values []*String for _, v := range n.Values { - values = append(values, v.clone()) + values = append(values, v.Clone(newPos).(*String)) } return &StrFlags{ - Pos: n.Pos, - Name: n.Name.clone(), + Pos: selectPos(newPos, n.Pos), + Name: n.Name.Clone(newPos).(*Ident), Values: values, } } -func (n *Ident) clone() *Ident { +func (n *Ident) Clone(newPos Pos) Node { return &Ident{ - Pos: n.Pos, + Pos: selectPos(newPos, n.Pos), Name: n.Name, } } -func (n *String) clone() *String { +func (n *String) Clone(newPos Pos) Node { return &String{ - Pos: n.Pos, + Pos: selectPos(newPos, n.Pos), Value: n.Value, } } -func (n *Int) clone() *Int { +func (n *Int) Clone(newPos Pos) Node { return &Int{ - Pos: n.Pos, + Pos: selectPos(newPos, n.Pos), Value: n.Value, ValueHex: n.ValueHex, Ident: n.Ident, @@ -161,19 +164,19 @@ func (n *Int) clone() *Int { } } -func (n *Type) clone() *Type { +func (n *Type) Clone(newPos Pos) Node { var args []*Type for _, a := range n.Args { - args = append(args, a.clone()) + args = append(args, a.Clone(newPos).(*Type)) } return &Type{ - Pos: n.Pos, + Pos: selectPos(newPos, n.Pos), Value: n.Value, ValueHex: n.ValueHex, Ident: n.Ident, String: n.String, HasColon: n.HasColon, - Pos2: n.Pos2, + Pos2: selectPos(newPos, n.Pos2), Value2: n.Value2, Value2Hex: n.Value2Hex, Ident2: n.Ident2, @@ -181,15 +184,15 @@ func (n *Type) clone() *Type { } } -func (n *Field) clone() *Field { +func (n *Field) Clone(newPos Pos) Node { var comments []*Comment for _, c := range n.Comments { - comments = append(comments, c.clone().(*Comment)) + comments = append(comments, c.Clone(newPos).(*Comment)) } return &Field{ - Pos: n.Pos, - Name: n.Name.clone(), - Type: n.Type.clone(), + Pos: selectPos(newPos, n.Pos), + Name: n.Name.Clone(newPos).(*Ident), + Type: n.Type.Clone(newPos).(*Type), NewBlock: n.NewBlock, Comments: comments, } diff --git a/pkg/ast/format.go b/pkg/ast/format.go index 0f95d7ebf..a77662df8 100644 --- a/pkg/ast/format.go +++ b/pkg/ast/format.go @@ -62,6 +62,10 @@ func (res *Resource) serialize(w io.Writer) { fmt.Fprintf(w, "\n") } +func (typedef *TypeDef) serialize(w io.Writer) { + fmt.Fprintf(w, "type %v %v\n", typedef.Name.Name, fmtType(typedef.Type)) +} + func (c *Call) serialize(w io.Writer) { fmt.Fprintf(w, "%v(", c.Name.Name) for i, a := range c.Args { diff --git a/pkg/ast/parser.go b/pkg/ast/parser.go index 9e1ab679e..db211ab2a 100644 --- a/pkg/ast/parser.go +++ b/pkg/ast/parser.go @@ -128,6 +128,9 @@ func (p *parser) parseTop() Node { return p.parseResource() case tokIdent: name := p.parseIdent() + if name.Name == "type" { + return p.parseTypeDef() + } switch p.tok { case tokLParen: return p.parseCall(name) @@ -245,6 +248,17 @@ func (p *parser) parseResource() *Resource { } } +func (p *parser) parseTypeDef() *TypeDef { + pos0 := p.pos + name := p.parseIdent() + typ := p.parseType() + return &TypeDef{ + Pos: pos0, + Name: name, + Type: typ, + } +} + func (p *parser) parseCall(name *Ident) *Call { c := &Call{ Pos: name.Pos, diff --git a/pkg/ast/testdata/all.txt b/pkg/ast/testdata/all.txt index 3f647e4ca..fedcc51a2 100644 --- a/pkg/ast/testdata/all.txt +++ b/pkg/ast/testdata/all.txt @@ -45,3 +45,8 @@ s2 { # comment } + +type bool8 int8 +type net_port proc[1, 2, int16be] +type bool16 ### unexpected '\n', expecting int, identifier, string +type type4:4 int32 ### unexpected ':', expecting int, identifier, string diff --git a/pkg/ast/walk.go b/pkg/ast/walk.go index 79e0b4bec..7bc34410e 100644 --- a/pkg/ast/walk.go +++ b/pkg/ast/walk.go @@ -32,6 +32,9 @@ func WalkNode(n0 Node, cb func(n Node)) { for _, v := range n.Values { WalkNode(v, cb) } + case *TypeDef: + WalkNode(n.Name, cb) + WalkNode(n.Type, cb) case *Call: WalkNode(n.Name, cb) for _, f := range n.Args { 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]) } diff --git a/pkg/compiler/compiler.go b/pkg/compiler/compiler.go index d250eda68..0be7f2817 100644 --- a/pkg/compiler/compiler.go +++ b/pkg/compiler/compiler.go @@ -53,6 +53,7 @@ func Compile(desc *ast.Description, consts map[string]uint64, target *targets.Ta ptrSize: target.PtrSize, unsupported: make(map[string]bool), resources: make(map[string]*ast.Resource), + typedefs: make(map[string]*ast.TypeDef), structs: make(map[string]*ast.Struct), intFlags: make(map[string]*ast.IntFlags), strFlags: make(map[string]*ast.StrFlags), @@ -89,6 +90,7 @@ type compiler struct { unsupported map[string]bool resources map[string]*ast.Resource + typedefs map[string]*ast.TypeDef structs map[string]*ast.Struct intFlags map[string]*ast.IntFlags strFlags map[string]*ast.StrFlags @@ -163,6 +165,9 @@ func (comp *compiler) getTypeDesc(t *ast.Type) *typeDesc { if comp.structs[t.Ident] != nil { return typeStruct } + if comp.typedefs[t.Ident] != nil { + return typeTypedef + } return nil } diff --git a/pkg/compiler/compiler_test.go b/pkg/compiler/compiler_test.go index ac2d88167..f26c272e6 100644 --- a/pkg/compiler/compiler_test.go +++ b/pkg/compiler/compiler_test.go @@ -5,7 +5,6 @@ package compiler import ( "path/filepath" - "runtime" "testing" "github.com/google/syzkaller/pkg/ast" @@ -13,21 +12,33 @@ import ( ) func TestCompileAll(t *testing.T) { - eh := func(pos ast.Pos, msg string) { - t.Logf("%v: %v", pos, msg) - } - desc := ast.ParseGlob(filepath.Join("..", "..", "sys", "linux", "*.txt"), eh) - if desc == nil { - t.Fatalf("parsing failed") - } - glob := filepath.Join("..", "..", "sys", "linux", "*_"+runtime.GOARCH+".const") - consts := DeserializeConstsGlob(glob, eh) - if consts == nil { - t.Fatalf("reading consts failed") - } - prog := Compile(desc, consts, targets.List["linux"]["amd64"], eh) - if prog == nil { - t.Fatalf("compilation failed") + for os, arches := range targets.List { + os, arches := os, arches + t.Run(os, func(t *testing.T) { + t.Parallel() + eh := func(pos ast.Pos, msg string) { + t.Logf("%v: %v", pos, msg) + } + path := filepath.Join("..", "..", "sys", os) + desc := ast.ParseGlob(filepath.Join(path, "*.txt"), eh) + if desc == nil { + t.Fatalf("parsing failed") + } + for arch, target := range arches { + arch, target := arch, target + t.Run(arch, func(t *testing.T) { + t.Parallel() + consts := DeserializeConstsGlob(filepath.Join(path, "*_"+arch+".const"), eh) + if consts == nil { + t.Fatalf("reading consts failed") + } + prog := Compile(desc, consts, target, eh) + if prog == nil { + t.Fatalf("compilation failed") + } + }) + } + }) } } @@ -38,7 +49,7 @@ func TestErrors(t *testing.T) { "C1": 1, "C2": 2, } - target := targets.List["linux"]["amd64"] + target := targets.List["test"]["64"] for _, name := range []string{"errors.txt", "errors2.txt"} { name := name t.Run(name, func(t *testing.T) { @@ -69,7 +80,7 @@ func TestFuzz(t *testing.T) { for _, data := range inputs { desc := ast.Parse([]byte(data), "", eh) if desc != nil { - Compile(desc, consts, targets.List["linux"]["amd64"], eh) + Compile(desc, consts, targets.List["test"]["64"], eh) } } } @@ -96,7 +107,7 @@ s2 { if desc == nil { t.Fatal("failed to parse") } - p := Compile(desc, map[string]uint64{"__NR_foo": 1}, targets.List["linux"]["amd64"], nil) + p := Compile(desc, map[string]uint64{"__NR_foo": 1}, targets.List["test"]["64"], nil) if p == nil { t.Fatal("failed to compile") } diff --git a/pkg/compiler/consts.go b/pkg/compiler/consts.go index 61198c96a..338dea4b1 100644 --- a/pkg/compiler/consts.go +++ b/pkg/compiler/consts.go @@ -145,7 +145,7 @@ func (comp *compiler) assignSyscallNumbers(consts map[string]uint64) { comp.warning(c.Pos, "unsupported syscall: %v due to missing const %v", c.CallName, str) } - case *ast.IntFlags, *ast.Resource, *ast.Struct, *ast.StrFlags: + case *ast.IntFlags, *ast.Resource, *ast.Struct, *ast.StrFlags, *ast.TypeDef: top = append(top, decl) case *ast.NewLine, *ast.Comment, *ast.Include, *ast.Incdir, *ast.Define: // These are not needed anymore. @@ -176,7 +176,7 @@ func (comp *compiler) patchConsts(consts map[string]uint64) { top = append(top, n) case *ast.StrFlags: top = append(top, decl) - case *ast.Resource, *ast.Struct, *ast.Call: + case *ast.Resource, *ast.Struct, *ast.Call, *ast.TypeDef: // Walk whole tree and replace consts in Int's and Type's. missing := "" ast.WalkNode(decl, func(n0 ast.Node) { diff --git a/pkg/compiler/testdata/errors.txt b/pkg/compiler/testdata/errors.txt index ade8c624f..237519aa3 100644 --- a/pkg/compiler/testdata/errors.txt +++ b/pkg/compiler/testdata/errors.txt @@ -178,3 +178,66 @@ define d1 `some C expression` define d2 some C expression define d2 SOMETHING ### duplicate define d2 define d3 1 + +# Type aliases. + +type bool8 int8[0:1] +type bool16 int16[0:1] +type net_port proc[100, 1, int16be] +resource typeres0[bool8] +typestruct { + f1 bool8 + f2 bool16 +} +typeunion [ + f1 bool8 + f2 bool16 +] + +type type0 int8 +type type0 int8 ### type type0 redeclared, previously declared as type alias at errors.txt:197:6 +resource type0[int32] ### type type0 redeclared, previously declared as type alias at errors.txt:197:6 +type0 = 0, 1 +type type1 type1 ### type aliases can't refer to other type aliases +type type2 int8:4 ### unexpected ':', only struct fields can be bitfields +type type3 type2 ### unknown type type2 +type type4 const[0] ### wrong number of arguments for type const, expect value, base type +type type5 typeunion ### typeunion can't be type alias target +type type6 len[foo, int32] ### len can't be type alias target +type type7 len[foo] ### len can't be type alias target +resource typeres1[int32] +type type8 typeres1 ### typeres1 can't be type alias target +type int8 int8 ### type name int8 conflicts with builtin type +type opt int8 ### type uses reserved name opt +type type9 const[0, int8] +type type10 type0 ### type aliases can't refer to other type aliases +type type11 typestruct11 ### typestruct11 can't be type alias target +type type12 proc[123, 2, int16, opt] +type type13 ptr[in, typestruct13] +type type14 flags[type0, int32] +type type15 const[0, type0] ### unexpected value type0 for base type argument of const type, expect [int8 int16 int32 int64 int16be int32be int64be intptr] +type type16 ptr[in, type0] ### type aliases can't refer to other type aliases + +typestruct11 { + f type11 ### unknown type type11 +} + +typestruct12 { + f type11 ### unknown type type11 +} + +typestruct13 { + f1 type9 + f2 type12 +} + +foo$100(a bool8, b bool16) +foo$101(a type5) ### unknown type type5 +foo$102(a type2) ### unknown type type2 +foo$103(a type0:4) ### type alias type0 with ':' +foo$104(a type0[opt]) ### type alias type0 with arguments +foo$105() type0 +foo$106() type6 ### unknown type type6 +foo$107(a type9, b type12) +foo$108(a flags[type0]) +foo$109(a ptr[in, type0]) diff --git a/pkg/compiler/types.go b/pkg/compiler/types.go index 30d3dac64..fbd44c0fa 100644 --- a/pkg/compiler/types.go +++ b/pkg/compiler/types.go @@ -15,6 +15,7 @@ import ( type typeDesc struct { Names []string CanBeArg bool // can be argument of syscall? + CanBeTypedef bool // can be type alias target? CantBeOpt bool // can't be marked as opt? CantBeRet bool // can't be syscall return (directly or indirectly)? NeedBase bool // needs base type when used as field? @@ -54,6 +55,7 @@ const ( var typeInt = &typeDesc{ Names: []string{"int8", "int16", "int32", "int64", "int16be", "int32be", "int64be", "intptr"}, CanBeArg: true, + CanBeTypedef: true, AllowColon: true, ResourceBase: true, OptArgs: 1, @@ -78,9 +80,10 @@ var typeInt = &typeDesc{ } var typePtr = &typeDesc{ - Names: []string{"ptr", "ptr64"}, - CanBeArg: true, - Args: []namedArg{{"direction", typeArgDir}, {"type", typeArgType}}, + Names: []string{"ptr", "ptr64"}, + CanBeArg: true, + CanBeTypedef: true, + Args: []namedArg{{"direction", typeArgDir}, {"type", typeArgType}}, Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type { base.ArgDir = prog.DirIn // pointers are always in base.TypeSize = comp.ptrSize @@ -175,11 +178,12 @@ var typeLen = &typeDesc{ } var typeConst = &typeDesc{ - Names: []string{"const"}, - CanBeArg: true, - CantBeOpt: true, - NeedBase: true, - Args: []namedArg{{"value", typeArgInt}}, + Names: []string{"const"}, + CanBeArg: true, + CanBeTypedef: true, + CantBeOpt: true, + NeedBase: true, + Args: []namedArg{{"value", typeArgInt}}, Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type { return &prog.ConstType{ IntTypeCommon: base, @@ -193,11 +197,12 @@ var typeArgLenTarget = &typeArg{ } var typeFlags = &typeDesc{ - Names: []string{"flags"}, - CanBeArg: true, - CantBeOpt: true, - NeedBase: true, - Args: []namedArg{{"flags", typeArgFlags}}, + Names: []string{"flags"}, + CanBeArg: true, + CanBeTypedef: true, + CantBeOpt: true, + NeedBase: true, + Args: []namedArg{{"flags", typeArgFlags}}, Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type { name := args[0].Ident base.TypeName = name @@ -334,10 +339,11 @@ func genCsumKind(t *ast.Type) prog.CsumKind { } var typeProc = &typeDesc{ - Names: []string{"proc"}, - CanBeArg: true, - NeedBase: true, - Args: []namedArg{{"range start", typeArgInt}, {"per-proc values", typeArgInt}}, + Names: []string{"proc"}, + CanBeArg: true, + CanBeTypedef: true, + NeedBase: true, + Args: []namedArg{{"range start", typeArgInt}, {"per-proc values", typeArgInt}}, Check: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) { start := args[0].Value perProc := args[1].Value @@ -522,7 +528,7 @@ var typeArgType = &typeArg{ } var typeResource = &typeDesc{ - // No Names, but compiler knows how to match it. + // No Names, but getTypeDesc knows how to match it. CanBeArg: true, ResourceBase: true, // Gen is assigned below to avoid initialization loop. @@ -544,7 +550,7 @@ func init() { } var typeStruct = &typeDesc{ - // No Names, but compiler knows how to match it. + // No Names, but getTypeDesc knows how to match it. CantBeOpt: true, // Varlen/Gen are assigned below due to initialization cycle. } @@ -579,6 +585,16 @@ func init() { } } +var typeTypedef = &typeDesc{ + // No Names, but getTypeDesc knows how to match it. + Check: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) { + panic("must not be called") + }, + Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type { + panic("must not be called") + }, +} + var typeArgDir = &typeArg{ Kind: kindIdent, Names: []string{"in", "out", "inout"}, @@ -660,16 +676,14 @@ func init() { typeConst, typeFlags, typeFilename, - typeFileoff, + typeFileoff, // make a type alias typeVMA, - typeSignalno, + typeSignalno, // make a type alias typeCsum, typeProc, typeText, - typeBuffer, + typeBuffer, // make a type alias typeString, - typeResource, - typeStruct, } for _, desc := range builtins { for _, name := range desc.Names { |
