github.com/gotranspile/cxgo@v0.3.8-0.20240118201721-29871598a6a2/go_types.go (about)

     1  package cxgo
     2  
     3  import (
     4  	"go/ast"
     5  	"go/token"
     6  	"strconv"
     7  	"strings"
     8  )
     9  
    10  type GoExpr = ast.Expr
    11  type GoStmt = ast.Stmt
    12  type GoDecl = ast.Decl
    13  type GoType = ast.Expr
    14  
    15  type GoField = ast.Field
    16  
    17  func ident(name string) *ast.Ident {
    18  	return &ast.Ident{Name: name}
    19  }
    20  
    21  func boolLit(v bool) GoExpr {
    22  	if v {
    23  		return ident("true")
    24  	}
    25  	return ident("false")
    26  }
    27  
    28  func intLit(v int) GoExpr {
    29  	return &ast.BasicLit{
    30  		Kind:  token.INT,
    31  		Value: strconv.Itoa(v),
    32  	}
    33  }
    34  
    35  func formatInt(v int64, base int) string {
    36  	neg := v < 0
    37  	if neg {
    38  		v = -v
    39  	}
    40  	s := formatUint(uint64(v), base)
    41  	if neg {
    42  		s = "-" + s
    43  	}
    44  	return s
    45  }
    46  
    47  func formatUint(v uint64, base int) string {
    48  	s := strconv.FormatUint(v, base)
    49  	switch base {
    50  	case 2:
    51  		s = "0b" + s
    52  	case 8:
    53  		s = "0o" + s
    54  	case 16:
    55  		s = "0x" + strings.ToUpper(s)
    56  	}
    57  	return s
    58  }
    59  
    60  func intLit64(v int64, base int) GoExpr {
    61  	if base <= 0 {
    62  		base = 10
    63  	}
    64  	return &ast.BasicLit{
    65  		Kind:  token.INT,
    66  		Value: formatInt(v, base),
    67  	}
    68  }
    69  
    70  func uintLit64(v uint64, base int) GoExpr {
    71  	if base > 0 {
    72  		return &ast.BasicLit{
    73  			Kind:  token.INT,
    74  			Value: formatUint(v, base),
    75  		}
    76  	}
    77  	s10 := strconv.FormatUint(v, 10)
    78  	s := s10
    79  	if len(s) > 4 {
    80  		s16 := strconv.FormatUint(v, 16)
    81  		if len(strings.Trim(s10, "0")) > len(strings.Trim(s16, "0")) {
    82  			s = "0x" + strings.ToUpper(s16)
    83  		}
    84  	}
    85  	return &ast.BasicLit{
    86  		Kind:  token.INT,
    87  		Value: s,
    88  	}
    89  }
    90  
    91  func noFields() *ast.FieldList {
    92  	return &ast.FieldList{}
    93  }
    94  
    95  func fields(arr []*GoField) *ast.FieldList {
    96  	return &ast.FieldList{List: arr}
    97  }
    98  
    99  func fieldTypes(arr ...GoType) *ast.FieldList {
   100  	var out []*GoField
   101  	for _, t := range arr {
   102  		out = append(out, &ast.Field{Type: t})
   103  	}
   104  	return fields(out)
   105  }
   106  
   107  func funcTypeRet(ret GoType) *ast.FuncType {
   108  	var fret *ast.FieldList
   109  	if ret != nil {
   110  		fret = fieldTypes(ret)
   111  	}
   112  	return &ast.FuncType{
   113  		Params:  noFields(),
   114  		Results: fret,
   115  	}
   116  }
   117  
   118  func fixLabels(stmts []GoStmt) []GoStmt {
   119  	for i := 0; i < len(stmts); i++ {
   120  		l, ok := stmts[i].(*ast.LabeledStmt)
   121  		if !ok {
   122  			continue
   123  		}
   124  		switch l.Stmt.(type) {
   125  		case nil, *ast.EmptyStmt:
   126  			if i == len(stmts)-1 {
   127  				l.Stmt = &ast.EmptyStmt{Implicit: true}
   128  			} else {
   129  				l.Stmt = stmts[i+1]
   130  				switch l.Stmt.(type) {
   131  				case *ast.CaseClause:
   132  					l.Stmt = &ast.EmptyStmt{Implicit: true}
   133  					continue
   134  				}
   135  				stmts = append(stmts[:i+1], stmts[i+2:]...)
   136  			}
   137  		}
   138  	}
   139  	return stmts
   140  }
   141  
   142  func mergeDecls(stmts []GoStmt) []GoStmt {
   143  	if len(stmts) < 2 {
   144  		return stmts
   145  	}
   146  	d1, ok := stmts[0].(*ast.DeclStmt)
   147  	if !ok {
   148  		return stmts
   149  	}
   150  	g1, ok := d1.Decl.(*ast.GenDecl)
   151  	if !ok {
   152  		return stmts
   153  	}
   154  	j := 0
   155  	for i := 0; i < len(stmts); i++ {
   156  		if i == 0 {
   157  			continue
   158  		}
   159  		d2, ok := stmts[i].(*ast.DeclStmt)
   160  		if !ok {
   161  			break
   162  		}
   163  		g2, ok := d2.Decl.(*ast.GenDecl)
   164  		if !ok || g2.Tok != g1.Tok {
   165  			break
   166  		}
   167  		g1.Specs = append(g1.Specs, g2.Specs...)
   168  		g2.Specs = nil
   169  		j = i
   170  	}
   171  	if j == 0 {
   172  		return stmts
   173  	}
   174  	return append([]GoStmt{d1}, stmts[j+1:]...)
   175  }
   176  
   177  func block(stmts ...GoStmt) *ast.BlockStmt {
   178  	if len(stmts) == 1 {
   179  		if b, ok := stmts[0].(*ast.BlockStmt); ok {
   180  			return b
   181  		}
   182  	}
   183  	stmts = fixLabels(stmts)
   184  	stmts = mergeDecls(stmts)
   185  	return &ast.BlockStmt{List: stmts}
   186  }
   187  
   188  func ifelse(cond GoExpr, then, els []GoStmt) *ast.IfStmt {
   189  	s := &ast.IfStmt{
   190  		Cond: cond,
   191  		Body: block(then...),
   192  	}
   193  	if len(els) != 0 {
   194  		if len(els) == 1 {
   195  			if s2, ok := els[0].(*ast.IfStmt); ok {
   196  				s.Else = s2
   197  			} else {
   198  				s.Else = block(els...)
   199  			}
   200  		} else {
   201  			s.Else = block(els...)
   202  		}
   203  	}
   204  	return s
   205  }
   206  
   207  func returnStmt(expr ...GoExpr) *ast.ReturnStmt {
   208  	return &ast.ReturnStmt{Results: expr}
   209  }
   210  
   211  func call(fnc GoExpr, args ...GoExpr) *ast.CallExpr {
   212  	for i, a := range args {
   213  		if p, ok := a.(*ast.ParenExpr); ok {
   214  			args[i] = p.X
   215  		}
   216  	}
   217  	return &ast.CallExpr{
   218  		Fun:  fnc,
   219  		Args: args,
   220  	}
   221  }
   222  
   223  func callVari(fnc GoExpr, args ...GoExpr) *ast.CallExpr {
   224  	e := call(fnc, args...)
   225  	e.Ellipsis = 1
   226  	return e
   227  }
   228  
   229  func callLambda(ret GoType, stmts ...GoStmt) *ast.CallExpr {
   230  	return call(&ast.FuncLit{
   231  		Type: funcTypeRet(ret),
   232  		Body: block(stmts...),
   233  	})
   234  }
   235  
   236  func assignTok(x GoExpr, tok token.Token, y GoExpr) *ast.AssignStmt {
   237  	return &ast.AssignStmt{
   238  		Tok: tok,
   239  		Lhs: []GoExpr{x},
   240  		Rhs: []GoExpr{y},
   241  	}
   242  }
   243  
   244  func assign(x, y GoExpr) *ast.AssignStmt {
   245  	return assignTok(x, token.ASSIGN, y)
   246  }
   247  
   248  func define(x, y GoExpr) *ast.AssignStmt {
   249  	return assignTok(x, token.DEFINE, y)
   250  }
   251  
   252  func addr(x GoExpr) GoExpr {
   253  	if e1, ok := x.(*ast.StarExpr); ok {
   254  		return e1.X
   255  	}
   256  	return &ast.UnaryExpr{
   257  		Op: token.AND,
   258  		X:  x,
   259  	}
   260  }
   261  
   262  func deref(x GoExpr) *ast.StarExpr {
   263  	return &ast.StarExpr{
   264  		X: x,
   265  	}
   266  }
   267  
   268  func index(x, ind GoExpr) *ast.IndexExpr {
   269  	return &ast.IndexExpr{
   270  		X: x, Index: ind,
   271  	}
   272  }
   273  
   274  func exprStmt(x GoExpr) GoStmt {
   275  	return &ast.ExprStmt{
   276  		X: x,
   277  	}
   278  }
   279  
   280  func paren(x GoExpr) *ast.ParenExpr {
   281  	if p, ok := x.(*ast.ParenExpr); ok {
   282  		return p
   283  	}
   284  	return &ast.ParenExpr{
   285  		X: x,
   286  	}
   287  }
   288  
   289  func unsafePtr() GoType {
   290  	return ident("unsafe.Pointer")
   291  }
   292  
   293  func typAssert(x GoExpr, t GoType) GoExpr {
   294  	return &ast.TypeAssertExpr{
   295  		X:    x,
   296  		Type: t,
   297  	}
   298  }