aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/ast
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2018-01-06 14:46:52 +0100
committerDmitry Vyukov <dvyukov@google.com>2018-01-08 12:52:31 +0100
commit402a0dc87e7d51812a18fa76feeb46d66efda175 (patch)
tree03ae2832257917a68829137b0a504f6f8c2e499a /pkg/ast
parent93b4c6f135aeecbb756fe8c8a3d46c7a05412a54 (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.go14
-rw-r--r--pkg/ast/clone.go131
-rw-r--r--pkg/ast/format.go4
-rw-r--r--pkg/ast/parser.go14
-rw-r--r--pkg/ast/testdata/all.txt5
-rw-r--r--pkg/ast/walk.go3
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 {