github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/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 maxTabs = max(maxTabs, tabs) 142 } 143 for _, f := range n.Fields { 144 if f.NewBlock { 145 fmt.Fprintf(w, "\n") 146 } 147 for _, com := range f.Comments { 148 com.serialize(w) 149 } 150 fmt.Fprintf(w, "\t%v\t", f.Name.Name) 151 for tabs := len(f.Name.Name)/tabWidth + 1; tabs < maxTabs; tabs++ { 152 fmt.Fprintf(w, "\t") 153 } 154 fmt.Fprintf(w, "%v", fmtType(f.Type)) 155 if len(f.Attrs) != 0 { 156 fmt.Fprintf(w, "\t%v", fmtTypeList(f.Attrs, "(", ")")) 157 } 158 fmt.Fprintf(w, "\n") 159 } 160 for _, com := range n.Comments { 161 com.serialize(w) 162 } 163 fmt.Fprintf(w, "%c", closing) 164 if attrs := fmtTypeList(n.Attrs, "[", "]"); attrs != "" { 165 fmt.Fprintf(w, " %v", attrs) 166 } 167 fmt.Fprintf(w, "\n") 168 } 169 170 func (n *IntFlags) serialize(w io.Writer) { 171 fmt.Fprintf(w, "%v = ", n.Name.Name) 172 for i, v := range n.Values { 173 fmt.Fprintf(w, "%v%v", comma(i, ""), fmtInt(v)) 174 } 175 fmt.Fprintf(w, "\n") 176 } 177 178 func (n *StrFlags) serialize(w io.Writer) { 179 fmt.Fprintf(w, "%v = ", n.Name.Name) 180 for i, v := range n.Values { 181 fmt.Fprintf(w, "%v%v", comma(i, ""), FormatStr(v.Value, v.Fmt)) 182 } 183 fmt.Fprintf(w, "\n") 184 } 185 186 func fmtField(f *Field) string { 187 return fmt.Sprintf("%v %v", f.Name.Name, fmtType(f.Type)) 188 } 189 190 func (n *Type) serialize(w io.Writer) { 191 w.Write([]byte(fmtType(n))) 192 } 193 194 func fmtType(t *Type) string { 195 var sb strings.Builder 196 fmtExpressionRec(&sb, t, -1) 197 return sb.String() 198 } 199 200 func fmtEndType(t *Type) string { 201 v := "" 202 switch { 203 case t.Ident != "": 204 v = t.Ident 205 case t.HasString: 206 v = FormatStr(t.String, t.StringFmt) 207 default: 208 v = FormatInt(t.Value, t.ValueFmt) 209 } 210 for _, c := range t.Colon { 211 v += ":" + fmtType(c) 212 } 213 v += fmtTypeList(t.Args, "[", "]") 214 return v 215 } 216 217 func fmtTypeList(args []*Type, opening, closing string) string { 218 if len(args) == 0 { 219 return "" 220 } 221 w := new(bytes.Buffer) 222 fmt.Fprint(w, opening) 223 for i, t := range args { 224 fmt.Fprintf(w, "%v%v", comma(i, ""), fmtType(t)) 225 } 226 fmt.Fprint(w, closing) 227 return w.String() 228 } 229 230 func fmtIdentList(args []*Ident) string { 231 if len(args) == 0 { 232 return "" 233 } 234 w := new(bytes.Buffer) 235 fmt.Fprintf(w, "[") 236 for i, arg := range args { 237 fmt.Fprintf(w, "%v%v", comma(i, ""), arg.Name) 238 } 239 fmt.Fprintf(w, "]") 240 return w.String() 241 } 242 243 func fmtInt(i *Int) string { 244 switch { 245 case i.Ident != "": 246 return i.Ident 247 case i.CExpr != "": 248 return fmt.Sprintf("%v", i.CExpr) 249 default: 250 return FormatInt(i.Value, i.ValueFmt) 251 } 252 } 253 254 func fmtExpressionRec(sb *strings.Builder, t *Type, parentPrio int) { 255 if t.Expression == nil { 256 sb.WriteString(fmtEndType(t)) 257 return 258 } 259 be := t.Expression 260 myPrio := operatorPrio(be.Operator) 261 parentheses := myPrio < parentPrio 262 if parentheses { 263 sb.WriteByte('(') 264 } 265 fmtExpressionRec(sb, be.Left, myPrio) 266 sb.WriteByte(' ') 267 switch be.Operator { 268 case OperatorCompareEq: 269 sb.WriteString("==") 270 case OperatorCompareNeq: 271 sb.WriteString("!=") 272 case OperatorBinaryAnd: 273 sb.WriteString("&") 274 case OperatorOr: 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 }