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  }