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 }