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  }