• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2017 syzkaller project authors. All rights reserved.
2// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
3
4package ast
5
6import (
7	"bytes"
8	"fmt"
9	"io"
10)
11
12func Format(desc *Description) []byte {
13	buf := new(bytes.Buffer)
14	FormatWriter(buf, desc)
15	return buf.Bytes()
16}
17
18func FormatWriter(w io.Writer, desc *Description) {
19	for _, n := range desc.Nodes {
20		s, ok := n.(serializer)
21		if !ok {
22			panic(fmt.Sprintf("unknown top level decl: %#v", n))
23		}
24		s.serialize(w)
25	}
26}
27
28func SerializeNode(n Node) string {
29	s, ok := n.(serializer)
30	if !ok {
31		panic(fmt.Sprintf("unknown node: %#v", n))
32	}
33	buf := new(bytes.Buffer)
34	s.serialize(buf)
35	return buf.String()
36}
37
38func FormatInt(v uint64, format IntFmt) string {
39	switch format {
40	case IntFmtDec:
41		return fmt.Sprint(v)
42	case IntFmtNeg:
43		return fmt.Sprint(int64(v))
44	case IntFmtHex:
45		return fmt.Sprintf("0x%x", v)
46	case IntFmtChar:
47		return fmt.Sprintf("'%c'", v)
48	default:
49		panic(fmt.Sprintf("unknown int format %v", format))
50	}
51}
52
53type serializer interface {
54	serialize(w io.Writer)
55}
56
57func (nl *NewLine) serialize(w io.Writer) {
58	fmt.Fprintf(w, "\n")
59}
60
61func (com *Comment) serialize(w io.Writer) {
62	fmt.Fprintf(w, "#%v\n", com.Text)
63}
64
65func (incl *Include) serialize(w io.Writer) {
66	fmt.Fprintf(w, "include <%v>\n", incl.File.Value)
67}
68
69func (inc *Incdir) serialize(w io.Writer) {
70	fmt.Fprintf(w, "incdir <%v>\n", inc.Dir.Value)
71}
72
73func (def *Define) serialize(w io.Writer) {
74	fmt.Fprintf(w, "define %v\t%v\n", def.Name.Name, fmtInt(def.Value))
75}
76
77func (res *Resource) serialize(w io.Writer) {
78	fmt.Fprintf(w, "resource %v[%v]", res.Name.Name, fmtType(res.Base))
79	for i, v := range res.Values {
80		fmt.Fprintf(w, "%v%v", comma(i, ": "), fmtInt(v))
81	}
82	fmt.Fprintf(w, "\n")
83}
84
85func (typedef *TypeDef) serialize(w io.Writer) {
86	fmt.Fprintf(w, "type %v%v", typedef.Name.Name, fmtIdentList(typedef.Args))
87	if typedef.Type != nil {
88		fmt.Fprintf(w, " %v\n", fmtType(typedef.Type))
89	}
90	if typedef.Struct != nil {
91		typedef.Struct.serialize(w)
92	}
93}
94
95func (c *Call) serialize(w io.Writer) {
96	fmt.Fprintf(w, "%v(", c.Name.Name)
97	for i, a := range c.Args {
98		fmt.Fprintf(w, "%v%v", comma(i, ""), fmtField(a))
99	}
100	fmt.Fprintf(w, ")")
101	if c.Ret != nil {
102		fmt.Fprintf(w, " %v", fmtType(c.Ret))
103	}
104	fmt.Fprintf(w, "\n")
105}
106
107func (str *Struct) serialize(w io.Writer) {
108	opening, closing := '{', '}'
109	if str.IsUnion {
110		opening, closing = '[', ']'
111	}
112	fmt.Fprintf(w, "%v %c\n", str.Name.Name, opening)
113	// Align all field types to the same column.
114	const tabWidth = 8
115	maxTabs := 0
116	for _, f := range str.Fields {
117		tabs := (len(f.Name.Name) + tabWidth) / tabWidth
118		if maxTabs < tabs {
119			maxTabs = tabs
120		}
121	}
122	for _, f := range str.Fields {
123		if f.NewBlock {
124			fmt.Fprintf(w, "\n")
125		}
126		for _, com := range f.Comments {
127			fmt.Fprintf(w, "#%v\n", com.Text)
128		}
129		fmt.Fprintf(w, "\t%v\t", f.Name.Name)
130		for tabs := len(f.Name.Name)/tabWidth + 1; tabs < maxTabs; tabs++ {
131			fmt.Fprintf(w, "\t")
132		}
133		fmt.Fprintf(w, "%v\n", fmtType(f.Type))
134	}
135	for _, com := range str.Comments {
136		fmt.Fprintf(w, "#%v\n", com.Text)
137	}
138	fmt.Fprintf(w, "%c", closing)
139	if attrs := fmtTypeList(str.Attrs); attrs != "" {
140		fmt.Fprintf(w, " %v", attrs)
141	}
142	fmt.Fprintf(w, "\n")
143}
144
145func (flags *IntFlags) serialize(w io.Writer) {
146	fmt.Fprintf(w, "%v = ", flags.Name.Name)
147	for i, v := range flags.Values {
148		fmt.Fprintf(w, "%v%v", comma(i, ""), fmtInt(v))
149	}
150	fmt.Fprintf(w, "\n")
151}
152
153func (flags *StrFlags) serialize(w io.Writer) {
154	fmt.Fprintf(w, "%v = ", flags.Name.Name)
155	for i, v := range flags.Values {
156		fmt.Fprintf(w, "%v\"%v\"", comma(i, ""), v.Value)
157	}
158	fmt.Fprintf(w, "\n")
159}
160
161func fmtField(f *Field) string {
162	return fmt.Sprintf("%v %v", f.Name.Name, fmtType(f.Type))
163}
164
165func (n *Type) serialize(w io.Writer) {
166	w.Write([]byte(fmtType(n)))
167}
168
169func fmtType(t *Type) string {
170	v := ""
171	switch {
172	case t.Ident != "":
173		v = t.Ident
174	case t.HasString:
175		v = fmt.Sprintf("\"%v\"", t.String)
176	default:
177		v = FormatInt(t.Value, t.ValueFmt)
178	}
179	if t.HasColon {
180		switch {
181		case t.Ident2 != "":
182			v += fmt.Sprintf(":%v", t.Ident2)
183		default:
184			v += fmt.Sprintf(":%v", FormatInt(t.Value2, t.Value2Fmt))
185		}
186	}
187	v += fmtTypeList(t.Args)
188	return v
189}
190
191func fmtTypeList(args []*Type) string {
192	if len(args) == 0 {
193		return ""
194	}
195	w := new(bytes.Buffer)
196	fmt.Fprintf(w, "[")
197	for i, t := range args {
198		fmt.Fprintf(w, "%v%v", comma(i, ""), fmtType(t))
199	}
200	fmt.Fprintf(w, "]")
201	return w.String()
202}
203
204func fmtIdentList(args []*Ident) string {
205	if len(args) == 0 {
206		return ""
207	}
208	w := new(bytes.Buffer)
209	fmt.Fprintf(w, "[")
210	for i, arg := range args {
211		fmt.Fprintf(w, "%v%v", comma(i, ""), arg.Name)
212	}
213	fmt.Fprintf(w, "]")
214	return w.String()
215}
216
217func fmtInt(i *Int) string {
218	switch {
219	case i.Ident != "":
220		return i.Ident
221	case i.CExpr != "":
222		return fmt.Sprintf("%v", i.CExpr)
223	default:
224		return FormatInt(i.Value, i.ValueFmt)
225	}
226}
227
228func comma(i int, or string) string {
229	if i == 0 {
230		return or
231	}
232	return ", "
233}
234