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/ast | |
| 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/ast')
| -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 |
6 files changed, 107 insertions, 64 deletions
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 { |
