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