github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/pkg/ast/format.go (about) 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 4 package ast 5 6 import ( 7 "bytes" 8 "fmt" 9 "io" 10 "strings" 11 ) 12 13 func Format(desc *Description) []byte { 14 buf := new(bytes.Buffer) 15 FormatWriter(buf, desc) 16 return buf.Bytes() 17 } 18 19 func FormatWriter(w io.Writer, desc *Description) { 20 for _, n := range desc.Nodes { 21 s, ok := n.(serializer) 22 if !ok { 23 panic(fmt.Sprintf("unknown top level decl: %#v", n)) 24 } 25 s.serialize(w) 26 } 27 } 28 29 func SerializeNode(n Node) string { 30 s, ok := n.(serializer) 31 if !ok { 32 panic(fmt.Sprintf("unknown node: %#v", n)) 33 } 34 buf := new(bytes.Buffer) 35 s.serialize(buf) 36 return buf.String() 37 } 38 39 func FormatInt(v uint64, format IntFmt) string { 40 switch format { 41 case IntFmtDec: 42 return fmt.Sprint(v) 43 case IntFmtNeg: 44 return fmt.Sprint(int64(v)) 45 case IntFmtHex: 46 return fmt.Sprintf("0x%x", v) 47 case IntFmtChar: 48 return fmt.Sprintf("'%c'", v) 49 default: 50 panic(fmt.Sprintf("unknown int format %v", format)) 51 } 52 } 53 54 func FormatStr(v string, format StrFmt) string { 55 switch format { 56 case StrFmtRaw: 57 return fmt.Sprintf(`"%v"`, v) 58 case StrFmtHex: 59 return fmt.Sprintf("`%x`", v) 60 case StrFmtIdent: 61 return fmt.Sprintf("%v", v) 62 default: 63 panic(fmt.Sprintf("unknown str format %v", format)) 64 } 65 } 66 67 type serializer interface { 68 serialize(w io.Writer) 69 } 70 71 func (n *NewLine) serialize(w io.Writer) { 72 fmt.Fprintf(w, "\n") 73 } 74 75 func (n *Comment) serialize(w io.Writer) { 76 fmt.Fprintf(w, "#%v\n", strings.TrimRight(n.Text, " \t")) 77 } 78 79 func (n *Meta) serialize(w io.Writer) { 80 fmt.Fprintf(w, "meta ") 81 n.Value.serialize(w) 82 fmt.Fprintf(w, "\n") 83 } 84 85 func (n *Include) serialize(w io.Writer) { 86 fmt.Fprintf(w, "include <%v>\n", n.File.Value) 87 } 88 89 func (n *Incdir) serialize(w io.Writer) { 90 fmt.Fprintf(w, "incdir <%v>\n", n.Dir.Value) 91 } 92 93 func (n *Define) serialize(w io.Writer) { 94 fmt.Fprintf(w, "define %v\t%v\n", n.Name.Name, fmtInt(n.Value)) 95 } 96 97 func (n *Resource) serialize(w io.Writer) { 98 fmt.Fprintf(w, "resource %v[%v]", n.Name.Name, fmtType(n.Base)) 99 for i, v := range n.Values { 100 fmt.Fprintf(w, "%v%v", comma(i, ": "), fmtInt(v)) 101 } 102 fmt.Fprintf(w, "\n") 103 } 104 105 func (n *TypeDef) serialize(w io.Writer) { 106 fmt.Fprintf(w, "type %v%v", n.Name.Name, fmtIdentList(n.Args)) 107 if n.Type != nil { 108 fmt.Fprintf(w, " %v\n", fmtType(n.Type)) 109 } 110 if n.Struct != nil { 111 n.Struct.serialize(w) 112 } 113 } 114 115 func (n *Call) serialize(w io.Writer) { 116 fmt.Fprintf(w, "%v(", n.Name.Name) 117 for i, a := range n.Args { 118 fmt.Fprintf(w, "%v%v", comma(i, ""), fmtField(a)) 119 } 120 fmt.Fprintf(w, ")") 121 if n.Ret != nil { 122 fmt.Fprintf(w, " %v", fmtType(n.Ret)) 123 } 124 if len(n.Attrs) != 0 { 125 fmt.Fprintf(w, " %v", fmtTypeList(n.Attrs, "(", ")")) 126 } 127 fmt.Fprintf(w, "\n") 128 } 129 130 func (n *Struct) serialize(w io.Writer) { 131 opening, closing := '{', '}' 132 if n.IsUnion { 133 opening, closing = '[', ']' 134 } 135 fmt.Fprintf(w, "%v %c\n", n.Name.Name, opening) 136 // Align all field types to the same column. 137 const tabWidth = 8 138 maxTabs := 0 139 for _, f := range n.Fields { 140 tabs := (len(f.Name.Name) + tabWidth) / tabWidth 141 if maxTabs < tabs { 142 maxTabs = tabs 143 } 144 } 145 for _, f := range n.Fields { 146 if f.NewBlock { 147 fmt.Fprintf(w, "\n") 148 } 149 for _, com := range f.Comments { 150 com.serialize(w) 151 } 152 fmt.Fprintf(w, "\t%v\t", f.Name.Name) 153 for tabs := len(f.Name.Name)/tabWidth + 1; tabs < maxTabs; tabs++ { 154 fmt.Fprintf(w, "\t") 155 } 156 fmt.Fprintf(w, "%v", fmtType(f.Type)) 157 if len(f.Attrs) != 0 { 158 fmt.Fprintf(w, "\t%v", fmtTypeList(f.Attrs, "(", ")")) 159 } 160 fmt.Fprintf(w, "\n") 161 } 162 for _, com := range n.Comments { 163 com.serialize(w) 164 } 165 fmt.Fprintf(w, "%c", closing) 166 if attrs := fmtTypeList(n.Attrs, "[", "]"); attrs != "" { 167 fmt.Fprintf(w, " %v", attrs) 168 } 169 fmt.Fprintf(w, "\n") 170 } 171 172 func (n *IntFlags) serialize(w io.Writer) { 173 fmt.Fprintf(w, "%v = ", n.Name.Name) 174 for i, v := range n.Values { 175 fmt.Fprintf(w, "%v%v", comma(i, ""), fmtInt(v)) 176 } 177 fmt.Fprintf(w, "\n") 178 } 179 180 func (n *StrFlags) serialize(w io.Writer) { 181 fmt.Fprintf(w, "%v = ", n.Name.Name) 182 for i, v := range n.Values { 183 fmt.Fprintf(w, "%v%v", comma(i, ""), FormatStr(v.Value, v.Fmt)) 184 } 185 fmt.Fprintf(w, "\n") 186 } 187 188 func fmtField(f *Field) string { 189 return fmt.Sprintf("%v %v", f.Name.Name, fmtType(f.Type)) 190 } 191 192 func (n *Type) serialize(w io.Writer) { 193 w.Write([]byte(fmtType(n))) 194 } 195 196 func fmtType(t *Type) string { 197 var sb strings.Builder 198 fmtExpressionRec(&sb, t, -1) 199 return sb.String() 200 } 201 202 func fmtEndType(t *Type) string { 203 v := "" 204 switch { 205 case t.Ident != "": 206 v = t.Ident 207 case t.HasString: 208 v = FormatStr(t.String, t.StringFmt) 209 default: 210 v = FormatInt(t.Value, t.ValueFmt) 211 } 212 for _, c := range t.Colon { 213 v += ":" + fmtType(c) 214 } 215 v += fmtTypeList(t.Args, "[", "]") 216 return v 217 } 218 219 func fmtTypeList(args []*Type, opening, closing string) string { 220 if len(args) == 0 { 221 return "" 222 } 223 w := new(bytes.Buffer) 224 fmt.Fprint(w, opening) 225 for i, t := range args { 226 fmt.Fprintf(w, "%v%v", comma(i, ""), fmtType(t)) 227 } 228 fmt.Fprint(w, closing) 229 return w.String() 230 } 231 232 func fmtIdentList(args []*Ident) string { 233 if len(args) == 0 { 234 return "" 235 } 236 w := new(bytes.Buffer) 237 fmt.Fprintf(w, "[") 238 for i, arg := range args { 239 fmt.Fprintf(w, "%v%v", comma(i, ""), arg.Name) 240 } 241 fmt.Fprintf(w, "]") 242 return w.String() 243 } 244 245 func fmtInt(i *Int) string { 246 switch { 247 case i.Ident != "": 248 return i.Ident 249 case i.CExpr != "": 250 return fmt.Sprintf("%v", i.CExpr) 251 default: 252 return FormatInt(i.Value, i.ValueFmt) 253 } 254 } 255 256 func fmtExpressionRec(sb *strings.Builder, t *Type, parentPrio int) { 257 if t.Expression == nil { 258 sb.WriteString(fmtEndType(t)) 259 return 260 } 261 be := t.Expression 262 myPrio := operatorPrio(be.Operator) 263 parentheses := myPrio < parentPrio 264 if parentheses { 265 sb.WriteByte('(') 266 } 267 fmtExpressionRec(sb, be.Left, myPrio) 268 sb.WriteByte(' ') 269 switch be.Operator { 270 case OperatorCompareEq: 271 sb.WriteString("==") 272 case OperatorCompareNeq: 273 sb.WriteString("!=") 274 case OperatorBinaryAnd: 275 sb.WriteString("&") 276 default: 277 panic(fmt.Sprintf("unknown operator %q", be.Operator)) 278 } 279 sb.WriteByte(' ') 280 fmtExpressionRec(sb, be.Right, myPrio) 281 if parentheses { 282 sb.WriteByte(')') 283 } 284 } 285 286 func operatorPrio(op Operator) int { 287 for _, info := range binaryOperators { 288 if info.op == op { 289 return info.prio 290 } 291 } 292 panic(fmt.Sprintf("unknown operator %q", op)) 293 } 294 295 func comma(i int, or string) string { 296 if i == 0 { 297 return or 298 } 299 return ", " 300 }