github.com/DQNEO/babygo@v0.0.3/pre/precompiler.go (about) 1 package main 2 3 import ( 4 "os" 5 // "syscall" 6 "unsafe" 7 8 "go/ast" 9 "go/parser" 10 "go/token" 11 12 "github.com/DQNEO/babygo/lib/mylib" 13 "github.com/DQNEO/babygo/lib/path" 14 "github.com/DQNEO/babygo/lib/strconv" 15 "github.com/DQNEO/babygo/lib/strings" 16 17 "github.com/DQNEO/babygo/lib/fmt" 18 ) 19 20 var ProgName string = "pre" 21 22 var __func__ = "__func__" 23 24 func assert(bol bool, msg string, caller string) { 25 if !bol { 26 panic(caller + ": " + msg) 27 } 28 } 29 30 func unexpectedKind(knd TypeKind) { 31 panic("Unexpected Kind: " + string(knd)) 32 } 33 34 var fout *os.File 35 36 func printf(format string, a ...interface{}) { 37 fmt.Fprintf(fout, format, a...) 38 } 39 40 var debugFrontEnd bool 41 42 func logf(format string, a ...interface{}) { 43 if !debugFrontEnd { 44 return 45 } 46 f := "# " + format 47 fmt.Fprintf(fout, f, a...) 48 } 49 50 var debugCodeGen bool 51 52 func emitComment(indent int, format string, a ...interface{}) { 53 if !debugCodeGen { 54 return 55 } 56 var spaces []uint8 57 for i := 0; i < indent; i++ { 58 spaces = append(spaces, ' ') 59 } 60 format2 := string(spaces) + "# " + format 61 printf(format2, a...) 62 } 63 64 func evalInt(expr ast.Expr) int { 65 switch e := expr.(type) { 66 case *ast.BasicLit: 67 return strconv.Atoi(e.Value) 68 } 69 panic("Unknown type") 70 } 71 72 func emitPopPrimitive(comment string) { 73 printf(" popq %%rax # result of %s\n", comment) 74 } 75 76 func emitPopBool(comment string) { 77 printf(" popq %%rax # result of %s\n", comment) 78 } 79 80 func emitPopAddress(comment string) { 81 printf(" popq %%rax # address of %s\n", comment) 82 } 83 84 func emitPopString() { 85 printf(" popq %%rax # string.ptr\n") 86 printf(" popq %%rcx # string.len\n") 87 } 88 89 func emitPopInterFace() { 90 printf(" popq %%rax # eface.dtype\n") 91 printf(" popq %%rcx # eface.data\n") 92 } 93 94 func emitPopSlice() { 95 printf(" popq %%rax # slice.ptr\n") 96 printf(" popq %%rcx # slice.len\n") 97 printf(" popq %%rdx # slice.cap\n") 98 } 99 100 func emitPushStackTop(condType *Type, offset int, comment string) { 101 switch kind(condType) { 102 case T_STRING: 103 printf(" movq %d+8(%%rsp), %%rcx # copy str.len from stack top (%s)\n", offset, comment) 104 printf(" movq %d+0(%%rsp), %%rax # copy str.ptr from stack top (%s)\n", offset, comment) 105 printf(" pushq %%rcx # str.len\n") 106 printf(" pushq %%rax # str.ptr\n") 107 case T_POINTER, T_UINTPTR, T_BOOL, T_INT, T_UINT8, T_UINT16: 108 printf(" movq %d(%%rsp), %%rax # copy stack top value (%s) \n", offset, comment) 109 printf(" pushq %%rax\n") 110 default: 111 unexpectedKind(kind(condType)) 112 } 113 } 114 115 func emitAllocReturnVarsArea(size int) { 116 if size == 0 { 117 return 118 } 119 printf(" subq $%d, %%rsp # alloc return vars area\n", size) 120 } 121 122 func emitFreeParametersArea(size int) { 123 if size == 0 { 124 return 125 } 126 printf(" addq $%d, %%rsp # free parameters area\n", size) 127 } 128 129 func emitAddConst(addValue int, comment string) { 130 emitComment(2, "Add const: %s\n", comment) 131 printf(" popq %%rax\n") 132 printf(" addq $%d, %%rax\n", addValue) 133 printf(" pushq %%rax\n") 134 } 135 136 // "Load" means copy data from memory to registers 137 func emitLoadAndPush(t *Type) { 138 assert(t != nil, "type should not be nil", __func__) 139 emitPopAddress(string(kind(t))) 140 switch kind(t) { 141 case T_SLICE: 142 printf(" movq %d(%%rax), %%rdx\n", 16) 143 printf(" movq %d(%%rax), %%rcx\n", 8) 144 printf(" movq %d(%%rax), %%rax\n", 0) 145 printf(" pushq %%rdx # cap\n") 146 printf(" pushq %%rcx # len\n") 147 printf(" pushq %%rax # ptr\n") 148 case T_STRING: 149 printf(" movq %d(%%rax), %%rdx # len\n", 8) 150 printf(" movq %d(%%rax), %%rax # ptr\n", 0) 151 printf(" pushq %%rdx # len\n") 152 printf(" pushq %%rax # ptr\n") 153 case T_INTERFACE: 154 printf(" movq %d(%%rax), %%rdx # data\n", 8) 155 printf(" movq %d(%%rax), %%rax # dtype\n", 0) 156 printf(" pushq %%rdx # data\n") 157 printf(" pushq %%rax # dtype\n") 158 case T_UINT8: 159 printf(" movzbq %d(%%rax), %%rax # load uint8\n", 0) 160 printf(" pushq %%rax\n") 161 case T_UINT16: 162 printf(" movzwq %d(%%rax), %%rax # load uint16\n", 0) 163 printf(" pushq %%rax\n") 164 case T_INT, T_BOOL, T_UINTPTR, T_POINTER, T_MAP: 165 printf(" movq %d(%%rax), %%rax # load 64\n", 0) 166 printf(" pushq %%rax\n") 167 case T_ARRAY, T_STRUCT: 168 // pure proxy 169 printf(" pushq %%rax\n") 170 default: 171 unexpectedKind(kind(t)) 172 } 173 } 174 175 func emitVariable(variable *Variable) { 176 emitVariableAddr(variable) 177 emitLoadAndPush(variable.Typ) 178 } 179 180 func emitVariableAddr(variable *Variable) { 181 emitComment(2, "emit Addr of variable \"%s\" \n", variable.Name) 182 183 if variable.IsGlobal { 184 printf(" leaq %s(%%rip), %%rax # global variable \"%s\"\n", variable.GlobalSymbol, variable.Name) 185 } else { 186 printf(" leaq %d(%%rbp), %%rax # local variable \"%s\"\n", variable.LocalOffset, variable.Name) 187 } 188 189 printf(" pushq %%rax # variable address\n") 190 } 191 192 func emitListHeadAddr(list ast.Expr) { 193 t := getTypeOfExpr(list) 194 switch kind(t) { 195 case T_ARRAY: 196 emitAddr(list) // array head 197 case T_SLICE: 198 emitExpr(list, nil) 199 emitPopSlice() 200 printf(" pushq %%rax # slice.ptr\n") 201 case T_STRING: 202 emitExpr(list, nil) 203 emitPopString() 204 printf(" pushq %%rax # string.ptr\n") 205 default: 206 unexpectedKind(kind(t)) 207 } 208 } 209 210 func emitAddr(expr ast.Expr) { 211 emitComment(2, "[emitAddr] %T\n", expr) 212 switch e := expr.(type) { 213 case *ast.Ident: 214 if e.Obj == nil { 215 panic("ident.Obj is nil: " + e.Name) 216 } 217 assert(e.Obj.Kind == ast.Var, "should be ast.Var", __func__) 218 vr := e.Obj.Data.(*Variable) 219 emitVariableAddr(vr) 220 case *ast.IndexExpr: 221 list := e.X 222 if kind(getTypeOfExpr(list)) == T_MAP { 223 emitAddrForMapSet(e) 224 } else { 225 elmType := getTypeOfExpr(e) 226 emitExpr(e.Index, nil) // index number 227 emitListElementAddr(list, elmType) 228 } 229 case *ast.StarExpr: 230 emitExpr(e.X, nil) 231 case *ast.SelectorExpr: 232 if isQI(e) { // pkg.SomeType 233 ident := lookupForeignIdent(selector2QI(e)) 234 emitAddr(ident) 235 } else { // (e).field 236 typeOfX := getUnderlyingType(getTypeOfExpr(e.X)) 237 var structTypeLiteral *ast.StructType 238 switch typ := typeOfX.E.(type) { 239 case *ast.StructType: // strct.field 240 structTypeLiteral = typ 241 emitAddr(e.X) 242 case *ast.StarExpr: // ptr.field 243 structTypeLiteral = getUnderlyingStructType(e2t(typ.X)) 244 emitExpr(e.X, nil) 245 default: 246 unexpectedKind(kind(typeOfX)) 247 } 248 249 field := lookupStructField(structTypeLiteral, e.Sel.Name) 250 offset := getStructFieldOffset(field) 251 emitAddConst(offset, "struct head address + struct.field offset") 252 } 253 case *ast.CompositeLit: 254 knd := kind(getTypeOfExpr(e)) 255 switch knd { 256 case T_STRUCT: 257 // result of evaluation of a struct literal is its address 258 emitExpr(e, nil) 259 default: 260 unexpectedKind(knd) 261 } 262 default: 263 throw(expr) 264 } 265 } 266 267 func isType(expr ast.Expr) bool { 268 switch e := expr.(type) { 269 case *ast.ArrayType: 270 return true 271 case *ast.Ident: 272 assert(e.Obj != nil, "e.Obj should not be nil: "+e.Name, __func__) 273 return e.Obj.Kind == ast.Typ 274 case *ast.SelectorExpr: 275 if isQI(e) { 276 qi := selector2QI(e) 277 ident := lookupForeignIdent(qi) 278 if ident.Obj.Kind == ast.Typ { 279 return true 280 } 281 } 282 case *ast.ParenExpr: 283 return isType(e.X) 284 case *ast.StarExpr: 285 return isType(e.X) 286 case *ast.InterfaceType: 287 return true 288 } 289 return false 290 } 291 292 // explicit conversion T(e) 293 func emitConversion(toType *Type, arg0 ast.Expr) { 294 emitComment(2, "[emitConversion]\n") 295 switch to := toType.E.(type) { 296 case *ast.Ident: 297 switch to.Obj { 298 case gString: // string(e) 299 switch kind(getTypeOfExpr(arg0)) { 300 case T_SLICE: // string(slice) 301 emitExpr(arg0, nil) // slice 302 emitPopSlice() 303 printf(" pushq %%rcx # str len\n") 304 printf(" pushq %%rax # str ptr\n") 305 case T_STRING: // string(string) 306 emitExpr(arg0, nil) 307 default: 308 unexpectedKind(kind(getTypeOfExpr(arg0))) 309 } 310 case gInt, gUint8, gUint16, gUintptr: // int(e) 311 emitExpr(arg0, nil) 312 default: 313 if to.Obj.Kind == ast.Typ { 314 ctx := &evalContext{_type: toType} 315 emitExpr(arg0, ctx) 316 } else { 317 throw(to.Obj) 318 } 319 } 320 case *ast.SelectorExpr: 321 // pkg.Type(arg0) 322 qi := selector2QI(to) 323 ff := lookupForeignIdent(qi) 324 assert(ff.Obj.Kind == ast.Typ, "should be ast.Typ", __func__) 325 emitConversion(e2t(ff), arg0) 326 case *ast.ArrayType: // Conversion to slice 327 arrayType := to 328 if arrayType.Len != nil { 329 throw(to) 330 } 331 assert(kind(getTypeOfExpr(arg0)) == T_STRING, "source type should be slice", __func__) 332 emitComment(2, "Conversion of string => slice \n") 333 emitExpr(arg0, nil) 334 emitPopString() 335 printf(" pushq %%rcx # cap\n") 336 printf(" pushq %%rcx # len\n") 337 printf(" pushq %%rax # ptr\n") 338 case *ast.ParenExpr: // (T)(arg0) 339 emitConversion(e2t(to.X), arg0) 340 case *ast.StarExpr: // (*T)(arg0) 341 emitExpr(arg0, nil) 342 case *ast.InterfaceType: 343 emitExpr(arg0, nil) 344 if isInterface(getTypeOfExpr(arg0)) { 345 // do nothing 346 } else { 347 // Convert dynamic value to interface 348 emitConvertToInterface(getTypeOfExpr(arg0)) 349 } 350 default: 351 throw(to) 352 } 353 } 354 355 func emitZeroValue(t *Type) { 356 switch kind(t) { 357 case T_SLICE: 358 printf(" pushq $0 # slice cap\n") 359 printf(" pushq $0 # slice len\n") 360 printf(" pushq $0 # slice ptr\n") 361 case T_STRING: 362 printf(" pushq $0 # string len\n") 363 printf(" pushq $0 # string ptr\n") 364 case T_INTERFACE: 365 printf(" pushq $0 # interface data\n") 366 printf(" pushq $0 # interface dtype\n") 367 case T_INT, T_UINTPTR, T_UINT8, T_POINTER, T_BOOL, T_MAP: 368 printf(" pushq $0 # %s zero value\n", string(kind(t))) 369 case T_STRUCT: 370 structSize := getSizeOfType(t) 371 emitComment(2, "zero value of a struct. size=%d (allocating on heap)\n", structSize) 372 emitCallMalloc(structSize) 373 default: 374 unexpectedKind(kind(t)) 375 } 376 } 377 378 func emitLen(arg ast.Expr) { 379 switch kind(getTypeOfExpr(arg)) { 380 case T_ARRAY: 381 arrayType := getTypeOfExpr(arg).E.(*ast.ArrayType) 382 emitExpr(arrayType.Len, nil) 383 case T_SLICE: 384 emitExpr(arg, nil) 385 emitPopSlice() 386 printf(" pushq %%rcx # len\n") 387 case T_STRING: 388 emitExpr(arg, nil) 389 emitPopString() 390 printf(" pushq %%rcx # len\n") 391 case T_MAP: 392 args := []*Arg{ 393 // len 394 &Arg{ 395 e: arg, 396 paramType: getTypeOfExpr(arg), 397 }, 398 } 399 resultList := &ast.FieldList{ 400 List: []*ast.Field{ 401 &ast.Field{ 402 Type: tInt.E, 403 }, 404 }, 405 } 406 emitCall("runtime.lenMap", args, resultList) 407 408 default: 409 unexpectedKind(kind(getTypeOfExpr(arg))) 410 } 411 } 412 413 func emitCap(arg ast.Expr) { 414 switch kind(getTypeOfExpr(arg)) { 415 case T_ARRAY: 416 arrayType := getTypeOfExpr(arg).E.(*ast.ArrayType) 417 emitExpr(arrayType.Len, nil) 418 case T_SLICE: 419 emitExpr(arg, nil) 420 emitPopSlice() 421 printf(" pushq %%rdx # cap\n") 422 case T_STRING: 423 panic("cap() cannot accept string type") 424 default: 425 unexpectedKind(kind(getTypeOfExpr(arg))) 426 } 427 } 428 429 func emitCallMalloc(size int) { 430 // call malloc and return pointer 431 ff := lookupForeignFunc(newQI("runtime", "malloc")) 432 emitAllocReturnVarsAreaFF(ff) 433 printf(" pushq $%d\n", size) 434 emitCallFF(ff) 435 } 436 437 func emitStructLiteral(e *ast.CompositeLit) { 438 // allocate heap area with zero value 439 emitComment(2, "emitStructLiteral\n") 440 structType := e2t(e.Type) 441 emitZeroValue(structType) // push address of the new storage 442 for _, elm := range e.Elts { 443 kvExpr := elm.(*ast.KeyValueExpr) 444 fieldName := kvExpr.Key.(*ast.Ident) 445 field := lookupStructField(getUnderlyingStructType(structType), fieldName.Name) 446 fieldType := e2t(field.Type) 447 fieldOffset := getStructFieldOffset(field) 448 // push lhs address 449 emitPushStackTop(tUintptr, 0, "address of struct heaad") 450 emitAddConst(fieldOffset, "address of struct field") 451 // push rhs value 452 ctx := &evalContext{ 453 _type: fieldType, 454 } 455 emitExprIfc(kvExpr.Value, ctx) 456 // assign 457 emitStore(fieldType, true, false) 458 } 459 } 460 461 func emitArrayLiteral(arrayType *ast.ArrayType, arrayLen int, elts []ast.Expr) { 462 elmType := e2t(arrayType.Elt) 463 elmSize := getSizeOfType(elmType) 464 memSize := elmSize * arrayLen 465 emitCallMalloc(memSize) // push 466 for i, elm := range elts { 467 // push lhs address 468 emitPushStackTop(tUintptr, 0, "malloced address") 469 emitAddConst(elmSize*i, "malloced address + elmSize * index") 470 // push rhs value 471 ctx := &evalContext{ 472 _type: elmType, 473 } 474 emitExprIfc(elm, ctx) 475 // assign 476 emitStore(elmType, true, false) 477 } 478 } 479 480 func emitInvertBoolValue() { 481 emitPopBool("") 482 printf(" xor $1, %%rax\n") 483 printf(" pushq %%rax\n") 484 } 485 486 func emitTrue() { 487 printf(" pushq $1 # true\n") 488 } 489 490 func emitFalse() { 491 printf(" pushq $0 # false\n") 492 } 493 494 type Arg struct { 495 e ast.Expr 496 paramType *Type // expected type 497 offset int 498 } 499 500 func prepareArgs(funcType *ast.FuncType, receiver ast.Expr, eArgs []ast.Expr, expandElipsis bool) []*Arg { 501 if funcType == nil { 502 panic("no funcType") 503 } 504 var args []*Arg 505 params := funcType.Params.List 506 var variadicArgs []ast.Expr // nil means there is no variadic in func params 507 var variadicElmType ast.Expr 508 var param *ast.Field 509 lenParams := len(params) 510 for argIndex, eArg := range eArgs { 511 if argIndex < lenParams { 512 param = params[argIndex] 513 elp, isEllpsis := param.Type.(*ast.Ellipsis) 514 if isEllpsis { 515 variadicElmType = elp.Elt 516 variadicArgs = make([]ast.Expr, 0, 20) 517 } 518 } 519 if variadicElmType != nil && !expandElipsis { 520 variadicArgs = append(variadicArgs, eArg) 521 continue 522 } 523 524 paramType := e2t(param.Type) 525 arg := &Arg{ 526 e: eArg, 527 paramType: paramType, 528 } 529 args = append(args, arg) 530 } 531 532 if variadicElmType != nil && !expandElipsis { 533 // collect args as a slice 534 sliceType := &ast.ArrayType{ 535 Elt: variadicElmType, 536 } 537 vargsSliceWrapper := &ast.CompositeLit{ 538 Type: sliceType, 539 Elts: variadicArgs, 540 } 541 args = append(args, &Arg{ 542 e: vargsSliceWrapper, 543 paramType: e2t(sliceType), 544 }) 545 } else if len(args) < len(params) { 546 // Add nil as a variadic arg 547 param := params[len(args)] 548 elp := param.Type.(*ast.Ellipsis) 549 args = append(args, &Arg{ 550 e: eNil, 551 paramType: e2t(elp), 552 }) 553 } 554 555 if receiver != nil { // method call 556 var receiverAndArgs []*Arg = []*Arg{ 557 &Arg{ 558 e: receiver, 559 paramType: getTypeOfExpr(receiver), 560 }, 561 } 562 for _, arg := range args { 563 receiverAndArgs = append(receiverAndArgs, arg) 564 } 565 return receiverAndArgs 566 } 567 568 return args 569 } 570 571 // see "ABI of stack layout" in the emitFuncall comment 572 func emitCall(symbol string, args []*Arg, resultList *ast.FieldList) { 573 emitComment(2, "emitArgs len=%d\n", len(args)) 574 575 var totalParamSize int 576 for _, arg := range args { 577 arg.offset = totalParamSize 578 totalParamSize += getSizeOfType(arg.paramType) 579 } 580 581 emitAllocReturnVarsArea(getTotalFieldsSize(resultList)) 582 printf(" subq $%d, %%rsp # alloc parameters area\n", totalParamSize) 583 for _, arg := range args { 584 paramType := arg.paramType 585 ctx := &evalContext{ 586 _type: paramType, 587 } 588 emitExprIfc(arg.e, ctx) 589 emitPop(kind(paramType)) 590 printf(" leaq %d(%%rsp), %%rsi # place to save\n", arg.offset) 591 printf(" pushq %%rsi # place to save\n") 592 emitRegiToMem(paramType) 593 } 594 595 emitCallQ(symbol, totalParamSize, resultList) 596 } 597 598 func emitAllocReturnVarsAreaFF(ff *ForeignFunc) { 599 emitAllocReturnVarsArea(getTotalFieldsSize(ff.decl.Type.Results)) 600 } 601 602 func getTotalFieldsSize(flist *ast.FieldList) int { 603 if flist == nil { 604 return 0 605 } 606 var r int 607 for _, fld := range flist.List { 608 r += getSizeOfType(e2t(fld.Type)) 609 } 610 return r 611 } 612 613 func emitCallFF(ff *ForeignFunc) { 614 totalParamSize := getTotalFieldsSize(ff.decl.Type.Params) 615 emitCallQ(ff.symbol, totalParamSize, ff.decl.Type.Results) 616 } 617 618 func emitCallQ(symbol string, totalParamSize int, resultList *ast.FieldList) { 619 printf(" callq %s\n", symbol) 620 emitFreeParametersArea(totalParamSize) 621 printf("# totalReturnSize=%d\n", getTotalFieldsSize(resultList)) 622 emitFreeAndPushReturnedValue(resultList) 623 } 624 625 // callee 626 func emitReturnStmt(s *ast.ReturnStmt) { 627 meta := getMetaReturnStmt(s) 628 fnc := meta.Fnc 629 if len(fnc.Retvars) != len(s.Results) { 630 panic("length of return and func type do not match") 631 } 632 633 _len := len(s.Results) 634 for i := 0; i < _len; i++ { 635 emitAssignToVar(fnc.Retvars[i], s.Results[i]) 636 } 637 printf(" leave\n") 638 printf(" ret\n") 639 } 640 641 // caller 642 func emitFreeAndPushReturnedValue(resultList *ast.FieldList) { 643 if resultList == nil { 644 return 645 } 646 switch len(resultList.List) { 647 case 0: 648 // do nothing 649 case 1: 650 retval0 := resultList.List[0] 651 knd := kind(e2t(retval0.Type)) 652 switch knd { 653 case T_STRING, T_INTERFACE: 654 case T_UINT8: 655 printf(" movzbq (%%rsp), %%rax # load uint8\n") 656 printf(" addq $%d, %%rsp # free returnvars area\n", 1) 657 printf(" pushq %%rax\n") 658 case T_BOOL, T_INT, T_UINTPTR, T_POINTER, T_MAP: 659 case T_SLICE: 660 default: 661 unexpectedKind(knd) 662 } 663 default: 664 //panic("TBI") 665 } 666 } 667 668 // ABI of stack layout in function call 669 // 670 // string: 671 // str.ptr 672 // str.len 673 // slice: 674 // slc.ptr 675 // slc.len 676 // slc.cap 677 // 678 // ABI of function call 679 // 680 // call f(i1 int, i2 int) (r1 int, r2 int) 681 // -- stack top 682 // i1 683 // i2 684 // r1 685 // r2 686 // 687 // call f(i int, s string, slc []T) int 688 // -- stack top 689 // i 690 // s.ptr 691 // s.len 692 // slc.ptr 693 // slc.len 694 // slc.cap 695 // r 696 // -- 697 func emitFuncall(fun ast.Expr, eArgs []ast.Expr, hasEllissis bool) { 698 var funcType *ast.FuncType 699 var symbol string 700 var receiver ast.Expr 701 switch fn := fun.(type) { 702 case *ast.Ident: 703 // check if it's a builtin func 704 switch fn.Obj { 705 case gLen: 706 emitLen(eArgs[0]) 707 return 708 case gCap: 709 emitCap(eArgs[0]) 710 return 711 case gNew: 712 typeArg := e2t(eArgs[0]) 713 // size to malloc 714 size := getSizeOfType(typeArg) 715 emitCallMalloc(size) 716 return 717 case gMake: 718 typeArg := e2t(eArgs[0]) 719 switch kind(typeArg) { 720 case T_MAP: 721 mapType := getUnderlyingType(typeArg).E.(*ast.MapType) 722 valueSize := newNumberLiteral(getSizeOfType(e2t(mapType.Value))) 723 // A new, empty map value is made using the built-in function make, 724 // which takes the map type and an optional capacity hint as arguments: 725 length := newNumberLiteral(0) 726 args := []*Arg{ 727 &Arg{ 728 e: length, 729 paramType: tUintptr, 730 }, 731 &Arg{ 732 e: valueSize, 733 paramType: tUintptr, 734 }, 735 } 736 resultList := &ast.FieldList{ 737 List: []*ast.Field{ 738 &ast.Field{ 739 Type: tUintptr.E, 740 }, 741 }, 742 } 743 emitCall("runtime.makeMap", args, resultList) 744 return 745 case T_SLICE: 746 // make([]T, ...) 747 arrayType := getUnderlyingType(typeArg).E.(*ast.ArrayType) 748 elmSize := getSizeOfType(e2t(arrayType.Elt)) 749 numlit := newNumberLiteral(elmSize) 750 args := []*Arg{ 751 // elmSize 752 &Arg{ 753 e: numlit, 754 paramType: tInt, 755 }, 756 // len 757 &Arg{ 758 e: eArgs[1], 759 paramType: tInt, 760 }, 761 // cap 762 &Arg{ 763 e: eArgs[2], 764 paramType: tInt, 765 }, 766 } 767 768 resultList := &ast.FieldList{ 769 List: []*ast.Field{ 770 &ast.Field{ 771 Type: generalSlice, 772 }, 773 }, 774 } 775 emitCall("runtime.makeSlice", args, resultList) 776 return 777 default: 778 throw(typeArg) 779 } 780 case gAppend: 781 sliceArg := eArgs[0] 782 elemArg := eArgs[1] 783 elmType := getElementTypeOfCollectionType(getTypeOfExpr(sliceArg)) 784 elmSize := getSizeOfType(elmType) 785 args := []*Arg{ 786 // slice 787 &Arg{ 788 e: sliceArg, 789 paramType: e2t(generalSlice), 790 }, 791 // elm 792 &Arg{ 793 e: elemArg, 794 paramType: elmType, 795 }, 796 } 797 798 var symbol string 799 switch elmSize { 800 case 1: 801 symbol = "runtime.append1" 802 case 8: 803 symbol = "runtime.append8" 804 case 16: 805 symbol = "runtime.append16" 806 case 24: 807 symbol = "runtime.append24" 808 default: 809 throw(elmSize) 810 } 811 resultList := &ast.FieldList{ 812 List: []*ast.Field{ 813 &ast.Field{ 814 Type: generalSlice, 815 }, 816 }, 817 } 818 emitCall(symbol, args, resultList) 819 return 820 case gPanic: 821 symbol = "runtime.panic" 822 _args := []*Arg{&Arg{ 823 e: eArgs[0], 824 paramType: tEface, 825 }} 826 emitCall(symbol, _args, nil) 827 return 828 case gDelete: 829 symbol = "runtime.deleteMap" 830 _args := []*Arg{ 831 &Arg{ 832 e: eArgs[0], 833 paramType: getTypeOfExpr(eArgs[0]), 834 }, 835 &Arg{ 836 e: eArgs[1], 837 paramType: tEface, 838 }, 839 } 840 emitCall(symbol, _args, nil) 841 return 842 } 843 844 if fn.Name == "makeSlice1" || fn.Name == "makeSlice8" || fn.Name == "makeSlice16" || fn.Name == "makeSlice24" { 845 fn.Name = "makeSlice" 846 } 847 // general function call 848 symbol = getPackageSymbol(currentPkg.name, fn.Name) 849 if currentPkg.name == "os" && fn.Name == "runtime_args" { 850 symbol = "runtime.runtime_args" 851 } else if currentPkg.name == "os" && fn.Name == "runtime_getenv" { 852 symbol = "runtime.runtime_getenv" 853 } 854 855 fndecl := fn.Obj.Decl.(*ast.FuncDecl) 856 funcType = fndecl.Type 857 case *ast.SelectorExpr: 858 if isQI(fn) { 859 // pkg.Sel() 860 qi := selector2QI(fn) 861 symbol = string(qi) 862 ff := lookupForeignFunc(qi) 863 funcType = ff.decl.Type 864 } else { 865 // method call 866 receiver = fn.X 867 receiverType := getTypeOfExpr(receiver) 868 method := lookupMethod(receiverType, fn.Sel) 869 funcType = method.FuncType 870 symbol = getMethodSymbol(method) 871 872 if kind(receiverType) == T_POINTER { 873 if method.IsPtrMethod { 874 // p.mp() => as it is 875 } else { 876 // p.mv() 877 panic("TBI") 878 } 879 } else { 880 if method.IsPtrMethod { 881 // v.mp() => (&v).mp() 882 // @TODO we should check addressable 883 receiver = &ast.UnaryExpr{ 884 Op: token.AND, 885 X: receiver, 886 } 887 } else { 888 // v.mv() => as it is 889 } 890 } 891 } 892 case *ast.ParenExpr: 893 panic("[astParenExpr] TBI ") 894 default: 895 throw(fun) 896 } 897 898 args := prepareArgs(funcType, receiver, eArgs, hasEllissis) 899 emitCall(symbol, args, funcType.Results) 900 } 901 902 func emitNil(targetType *Type) { 903 if targetType == nil { 904 panic("Type is required to emit nil") 905 } 906 switch kind(targetType) { 907 case T_SLICE, T_POINTER, T_INTERFACE, T_MAP: 908 emitZeroValue(targetType) 909 default: 910 unexpectedKind(kind(targetType)) 911 } 912 } 913 914 func emitNamedConst(ident *ast.Ident, ctx *evalContext) { 915 valSpec := ident.Obj.Decl.(*ast.ValueSpec) 916 lit := valSpec.Values[0].(*ast.BasicLit) 917 emitExprIfc(lit, ctx) 918 } 919 920 type evalContext struct { 921 okContext bool 922 _type *Type 923 } 924 925 // 1 value 926 func emitIdent(e *ast.Ident, ctx *evalContext) bool { 927 switch e.Obj { 928 case gTrue: // true constant 929 emitTrue() 930 case gFalse: // false constant 931 emitFalse() 932 case gNil: 933 assert(ctx._type != nil, "context of nil is not passed", __func__) 934 emitNil(ctx._type) 935 return true 936 default: 937 assert(e.Obj != nil, "should not be nil", __func__) 938 switch e.Obj.Kind { 939 case ast.Var: 940 emitAddr(e) 941 emitLoadAndPush(getTypeOfExpr(e)) 942 case ast.Con: 943 emitNamedConst(e, ctx) 944 default: 945 panic("Unexpected ident kind:") 946 } 947 } 948 return false 949 } 950 951 // 1 or 2 values 952 func emitIndexExpr(e *ast.IndexExpr, ctx *evalContext) { 953 if kind(getTypeOfExpr(e.X)) == T_MAP { 954 emitMapGet(e, ctx) 955 } else { 956 emitAddr(e) 957 emitLoadAndPush(getTypeOfExpr(e)) 958 } 959 } 960 961 // 1 value 962 func emitStarExpr(e *ast.StarExpr, ctx *evalContext) { 963 emitAddr(e) 964 emitLoadAndPush(getTypeOfExpr(e)) 965 } 966 967 // 1 value X.Sel 968 func emitSelectorExpr(e *ast.SelectorExpr, ctx *evalContext) { 969 // pkg.Ident or strct.field 970 if isQI(e) { 971 ident := lookupForeignIdent(selector2QI(e)) 972 emitExpr(ident, ctx) 973 } else { 974 // strct.field 975 emitAddr(e) 976 emitLoadAndPush(getTypeOfExpr(e)) 977 } 978 } 979 980 // multi values Fun(Args) 981 func emitCallExpr(e *ast.CallExpr, ctx *evalContext) { 982 var fun = e.Fun 983 // check if it's a conversion 984 if isType(fun) { 985 emitConversion(e2t(fun), e.Args[0]) 986 } else { 987 emitFuncall(fun, e.Args, e.Ellipsis != token.NoPos) 988 } 989 } 990 991 // multi values (e) 992 func emitParenExpr(e *ast.ParenExpr, ctx *evalContext) { 993 emitExpr(e.X, ctx) 994 } 995 996 // 1 value 997 func emitBasicLit(e *ast.BasicLit, ctx *evalContext) { 998 switch e.Kind.String() { 999 case "CHAR": 1000 var val = e.Value 1001 var char = val[1] 1002 if val[1] == '\\' { 1003 switch val[2] { 1004 case '\'': 1005 char = '\'' 1006 case 'n': 1007 char = '\n' 1008 case '\\': 1009 char = '\\' 1010 case 't': 1011 char = '\t' 1012 case 'r': 1013 char = '\r' 1014 } 1015 } 1016 printf(" pushq $%d # convert char literal to int\n", int(char)) 1017 case "INT": 1018 ival := strconv.Atoi(e.Value) 1019 printf(" pushq $%d # number literal\n", ival) 1020 case "STRING": 1021 sl := getStringLiteral(e) 1022 if sl.strlen == 0 { 1023 // zero value 1024 emitZeroValue(tString) 1025 } else { 1026 printf(" pushq $%d # str len\n", sl.strlen) 1027 printf(" leaq %s(%%rip), %%rax # str ptr\n", sl.label) 1028 printf(" pushq %%rax # str ptr\n") 1029 } 1030 default: 1031 panic("Unexpected literal kind:" + e.Kind.String()) 1032 } 1033 } 1034 1035 // 1 value 1036 func emitUnaryExpr(e *ast.UnaryExpr, ctx *evalContext) { 1037 switch e.Op.String() { 1038 case "+": 1039 emitExpr(e.X, nil) 1040 case "-": 1041 emitExpr(e.X, nil) 1042 printf(" popq %%rax # e.X\n") 1043 printf(" imulq $-1, %%rax\n") 1044 printf(" pushq %%rax\n") 1045 case "&": 1046 emitAddr(e.X) 1047 case "!": 1048 emitExpr(e.X, nil) 1049 emitInvertBoolValue() 1050 default: 1051 throw(e.Op) 1052 } 1053 } 1054 1055 // 1 value 1056 func emitBinaryExpr(e *ast.BinaryExpr, ctx *evalContext) { 1057 switch e.Op.String() { 1058 case "&&": 1059 labelid++ 1060 labelExitWithFalse := fmt.Sprintf(".L.%d.false", labelid) 1061 labelExit := fmt.Sprintf(".L.%d.exit", labelid) 1062 emitExpr(e.X, nil) // left 1063 emitPopBool("left") 1064 printf(" cmpq $1, %%rax\n") 1065 // exit with false if left is false 1066 printf(" jne %s\n", labelExitWithFalse) 1067 1068 // if left is true, then eval right and exit 1069 emitExpr(e.Y, nil) // right 1070 printf(" jmp %s\n", labelExit) 1071 1072 printf(" %s:\n", labelExitWithFalse) 1073 emitFalse() 1074 printf(" %s:\n", labelExit) 1075 case "||": 1076 labelid++ 1077 labelExitWithTrue := fmt.Sprintf(".L.%d.true", labelid) 1078 labelExit := fmt.Sprintf(".L.%d.exit", labelid) 1079 emitExpr(e.X, nil) // left 1080 emitPopBool("left") 1081 printf(" cmpq $1, %%rax\n") 1082 // exit with true if left is true 1083 printf(" je %s\n", labelExitWithTrue) 1084 1085 // if left is false, then eval right and exit 1086 emitExpr(e.Y, nil) // right 1087 printf(" jmp %s\n", labelExit) 1088 1089 printf(" %s:\n", labelExitWithTrue) 1090 emitTrue() 1091 printf(" %s:\n", labelExit) 1092 case "+": 1093 if kind(getTypeOfExpr(e.X)) == T_STRING { 1094 emitCatStrings(e.X, e.Y) 1095 } else { 1096 emitExpr(e.X, nil) // left 1097 emitExpr(e.Y, nil) // right 1098 printf(" popq %%rcx # right\n") 1099 printf(" popq %%rax # left\n") 1100 printf(" addq %%rcx, %%rax\n") 1101 printf(" pushq %%rax\n") 1102 } 1103 case "-": 1104 emitExpr(e.X, nil) // left 1105 emitExpr(e.Y, nil) // right 1106 printf(" popq %%rcx # right\n") 1107 printf(" popq %%rax # left\n") 1108 printf(" subq %%rcx, %%rax\n") 1109 printf(" pushq %%rax\n") 1110 case "*": 1111 emitExpr(e.X, nil) // left 1112 emitExpr(e.Y, nil) // right 1113 printf(" popq %%rcx # right\n") 1114 printf(" popq %%rax # left\n") 1115 printf(" imulq %%rcx, %%rax\n") 1116 printf(" pushq %%rax\n") 1117 case "%": 1118 emitExpr(e.X, nil) // left 1119 emitExpr(e.Y, nil) // right 1120 printf(" popq %%rcx # right\n") 1121 printf(" popq %%rax # left\n") 1122 printf(" movq $0, %%rdx # init %%rdx\n") 1123 printf(" divq %%rcx\n") 1124 printf(" movq %%rdx, %%rax\n") 1125 printf(" pushq %%rax\n") 1126 case "/": 1127 emitExpr(e.X, nil) // left 1128 emitExpr(e.Y, nil) // right 1129 printf(" popq %%rcx # right\n") 1130 printf(" popq %%rax # left\n") 1131 printf(" movq $0, %%rdx # init %%rdx\n") 1132 printf(" divq %%rcx\n") 1133 printf(" pushq %%rax\n") 1134 case "==": 1135 emitBinaryExprComparison(e.X, e.Y) 1136 case "!=": 1137 emitBinaryExprComparison(e.X, e.Y) 1138 emitInvertBoolValue() 1139 case "<": 1140 emitExpr(e.X, nil) // left 1141 emitExpr(e.Y, nil) // right 1142 emitCompExpr("setl") 1143 case "<=": 1144 emitExpr(e.X, nil) // left 1145 emitExpr(e.Y, nil) // right 1146 emitCompExpr("setle") 1147 case ">": 1148 emitExpr(e.X, nil) // left 1149 emitExpr(e.Y, nil) // right 1150 emitCompExpr("setg") 1151 case ">=": 1152 emitExpr(e.X, nil) // left 1153 emitExpr(e.Y, nil) // right 1154 emitCompExpr("setge") 1155 default: 1156 panic(e.Op.String()) 1157 } 1158 } 1159 1160 // 1 value 1161 func emitCompositeLit(e *ast.CompositeLit, ctx *evalContext) { 1162 // slice , array, map or struct 1163 ut := getUnderlyingType(getTypeOfExpr(e)) 1164 switch kind(ut) { 1165 case T_STRUCT: 1166 emitStructLiteral(e) 1167 case T_ARRAY: 1168 arrayType := ut.E.(*ast.ArrayType) 1169 arrayLen := evalInt(arrayType.Len) 1170 emitArrayLiteral(arrayType, arrayLen, e.Elts) 1171 case T_SLICE: 1172 arrayType := ut.E.(*ast.ArrayType) 1173 length := len(e.Elts) 1174 emitArrayLiteral(arrayType, length, e.Elts) 1175 emitPopAddress("malloc") 1176 printf(" pushq $%d # slice.cap\n", length) 1177 printf(" pushq $%d # slice.len\n", length) 1178 printf(" pushq %%rax # slice.ptr\n") 1179 default: 1180 unexpectedKind(kind(e2t(e.Type))) 1181 } 1182 } 1183 1184 // 1 value list[low:high] 1185 func emitSliceExpr(e *ast.SliceExpr, ctx *evalContext) { 1186 list := e.X 1187 listType := getTypeOfExpr(list) 1188 1189 // For convenience, any of the indices may be omitted. 1190 // A missing low index defaults to zero; 1191 var low ast.Expr 1192 if e.Low != nil { 1193 low = e.Low 1194 } else { 1195 low = eZeroInt 1196 } 1197 1198 switch kind(listType) { 1199 case T_SLICE, T_ARRAY: 1200 if e.Max == nil { 1201 // new cap = cap(operand) - low 1202 emitCap(e.X) 1203 emitExpr(low, nil) 1204 printf(" popq %%rcx # low\n") 1205 printf(" popq %%rax # orig_cap\n") 1206 printf(" subq %%rcx, %%rax # orig_cap - low\n") 1207 printf(" pushq %%rax # new cap\n") 1208 1209 // new len = high - low 1210 if e.High != nil { 1211 emitExpr(e.High, nil) 1212 } else { 1213 // high = len(orig) 1214 emitLen(e.X) 1215 } 1216 emitExpr(low, nil) 1217 printf(" popq %%rcx # low\n") 1218 printf(" popq %%rax # high\n") 1219 printf(" subq %%rcx, %%rax # high - low\n") 1220 printf(" pushq %%rax # new len\n") 1221 } else { 1222 // new cap = max - low 1223 emitExpr(e.Max, nil) 1224 emitExpr(low, nil) 1225 printf(" popq %%rcx # low\n") 1226 printf(" popq %%rax # max\n") 1227 printf(" subq %%rcx, %%rax # new cap = max - low\n") 1228 printf(" pushq %%rax # new cap\n") 1229 // new len = high - low 1230 emitExpr(e.High, nil) 1231 emitExpr(low, nil) 1232 printf(" popq %%rcx # low\n") 1233 printf(" popq %%rax # high\n") 1234 printf(" subq %%rcx, %%rax # new len = high - low\n") 1235 printf(" pushq %%rax # new len\n") 1236 } 1237 case T_STRING: 1238 // new len = high - low 1239 if e.High != nil { 1240 emitExpr(e.High, nil) 1241 } else { 1242 // high = len(orig) 1243 emitLen(e.X) 1244 } 1245 emitExpr(low, nil) 1246 printf(" popq %%rcx # low\n") 1247 printf(" popq %%rax # high\n") 1248 printf(" subq %%rcx, %%rax # high - low\n") 1249 printf(" pushq %%rax # len\n") 1250 // no cap 1251 default: 1252 unexpectedKind(kind(listType)) 1253 } 1254 1255 emitExpr(low, nil) // index number 1256 elmType := getElementTypeOfCollectionType(listType) 1257 emitListElementAddr(list, elmType) 1258 } 1259 1260 // 1 or 2 values 1261 func emitMapGet(e *ast.IndexExpr, ctx *evalContext) { 1262 // MAP GET 1263 valueType := getTypeOfExpr(e) 1264 emitComment(2, "MAP GET for map[string]string\n") 1265 // emit addr of map element 1266 mp := e.X 1267 key := e.Index 1268 1269 args := []*Arg{ 1270 &Arg{ 1271 e: mp, 1272 paramType: tUintptr, 1273 }, 1274 &Arg{ 1275 e: key, 1276 paramType: tEface, 1277 }, 1278 } 1279 resultList := &ast.FieldList{ 1280 List: []*ast.Field{ 1281 &ast.Field{ 1282 Type: tBool.E, 1283 }, 1284 &ast.Field{ 1285 Type: tUintptr.E, 1286 }, 1287 }, 1288 } 1289 emitCall("runtime.getAddrForMapGet", args, resultList) 1290 // return values = [ptr, bool(stack top)] 1291 emitPopBool("map get: ok value") 1292 printf(" cmpq $1, %%rax\n") 1293 labelid++ 1294 labelEnd := fmt.Sprintf(".L.end_map_get.%d", labelid) 1295 labelElse := fmt.Sprintf(".L.not_found.%d", labelid) 1296 printf(" jne %s # jmp if false\n", labelElse) 1297 1298 okContext := ctx != nil && ctx.okContext 1299 1300 // if matched 1301 emitLoadAndPush(valueType) 1302 if okContext { 1303 printf(" pushq $1 # ok = true\n") 1304 } 1305 // exit 1306 printf(" jmp %s\n", labelEnd) 1307 1308 // if not matched 1309 printf(" %s:\n", labelElse) 1310 emitPop(T_POINTER) // destroy nil 1311 emitZeroValue(valueType) 1312 if okContext { 1313 printf(" pushq $0 # ok = false\n") 1314 } 1315 1316 printf(" %s:\n", labelEnd) 1317 } 1318 1319 // 1 or 2 values 1320 func emitTypeAssertExpr(e *ast.TypeAssertExpr, ctx *evalContext) { 1321 emitExpr(e.X, nil) 1322 emitDtypeLabelAddr(e2t(e.Type)) 1323 emitCompareDtypes() 1324 1325 emitPopBool("type assertion ok value") 1326 printf(" cmpq $1, %%rax\n") 1327 1328 labelid++ 1329 labelEnd := fmt.Sprintf(".L.end_type_assertion.%d", labelid) 1330 labelElse := fmt.Sprintf(".L.unmatch.%d", labelid) 1331 printf(" jne %s # jmp if false\n", labelElse) 1332 1333 okContext := ctx != nil && ctx.okContext 1334 // if matched 1335 emitLoadAndPush(e2t(e.Type)) // load dynamic data 1336 if okContext { 1337 printf(" pushq $1 # ok = true\n") 1338 } 1339 // exit 1340 printf(" jmp %s\n", labelEnd) 1341 // if not matched 1342 printf(" %s:\n", labelElse) 1343 printf(" popq %%rax # drop ifc.data\n") 1344 emitZeroValue(e2t(e.Type)) 1345 if okContext { 1346 printf(" pushq $0 # ok = false\n") 1347 } 1348 1349 printf(" %s:\n", labelEnd) 1350 } 1351 1352 // targetType is the type of someone who receives the expr value. 1353 // There are various forms: 1354 // Assignment: x = expr 1355 // Function call: x(expr) 1356 // Return: return expr 1357 // CompositeLiteral: T{key:expr} 1358 // targetType is used when: 1359 // - the expr is nil 1360 // - the target type is interface and expr is not. 1361 func emitExpr(expr ast.Expr, ctx *evalContext) bool { 1362 emitComment(2, "[emitExpr] dtype=%T\n", expr) 1363 switch e := expr.(type) { 1364 case *ast.Ident: 1365 return emitIdent(e, ctx) // 1 value 1366 case *ast.IndexExpr: 1367 emitIndexExpr(e, ctx) // 1 or 2 values 1368 case *ast.StarExpr: 1369 emitStarExpr(e, ctx) // 1 value 1370 case *ast.SelectorExpr: 1371 emitSelectorExpr(e, ctx) // 1 value X.Sel 1372 case *ast.CallExpr: 1373 emitCallExpr(e, ctx) // multi values Fun(Args) 1374 case *ast.ParenExpr: 1375 emitParenExpr(e, ctx) // multi values (e) 1376 case *ast.BasicLit: 1377 emitBasicLit(e, ctx) // 1 value 1378 case *ast.UnaryExpr: 1379 emitUnaryExpr(e, ctx) // 1 value 1380 case *ast.BinaryExpr: 1381 emitBinaryExpr(e, ctx) // 1 value 1382 case *ast.CompositeLit: 1383 emitCompositeLit(e, ctx) // 1 value 1384 case *ast.SliceExpr: 1385 emitSliceExpr(e, ctx) // 1 value list[low:high] 1386 case *ast.TypeAssertExpr: 1387 emitTypeAssertExpr(e, ctx) // 1 or 2 values 1388 default: 1389 throw(expr) 1390 } 1391 return false 1392 } 1393 1394 // convert stack top value to interface 1395 func emitConvertToInterface(fromType *Type) { 1396 emitComment(2, "ConversionToInterface\n") 1397 memSize := getSizeOfType(fromType) 1398 // copy data to heap 1399 emitCallMalloc(memSize) 1400 emitStore(fromType, false, true) // heap addr pushed 1401 // push dtype label's address 1402 emitDtypeLabelAddr(fromType) 1403 } 1404 1405 func emitExprIfc(expr ast.Expr, ctx *evalContext) { 1406 isNilObj := emitExpr(expr, ctx) 1407 if !isNilObj && ctx != nil && ctx._type != nil && isInterface(ctx._type) && !isInterface(getTypeOfExpr(expr)) { 1408 emitConvertToInterface(getTypeOfExpr(expr)) 1409 } 1410 } 1411 1412 type dtypeEntry struct { 1413 id int 1414 pkgname string 1415 serialized string 1416 label string 1417 } 1418 1419 var typeId int 1420 var typesMap map[string]*dtypeEntry 1421 1422 // "**[1][]*int" => "dtype.8" 1423 func getDtypeLabel(pkg *PkgContainer, serializedType string) string { 1424 s := pkg.name + ":" + serializedType 1425 ent, ok := typesMap[s] 1426 if ok { 1427 return ent.label 1428 } else { 1429 id := typeId 1430 ent = &dtypeEntry{ 1431 id: id, 1432 pkgname: pkg.name, 1433 serialized: serializedType, 1434 label: pkg.name + "." + "dtype." + strconv.Itoa(id), 1435 } 1436 typesMap[s] = ent 1437 typeId++ 1438 } 1439 1440 return ent.label 1441 } 1442 1443 // Check type identity by comparing its serialization, not id or address of dtype label. 1444 // pop pop, compare and push 1(match) or 0(not match) 1445 func emitCompareDtypes() { 1446 labelid++ 1447 labelTrue := fmt.Sprintf(".L.cmpdtypes.%d.true", labelid) 1448 labelFalse := fmt.Sprintf(".L.cmpdtypes.%d.false", labelid) 1449 labelEnd := fmt.Sprintf(".L.cmpdtypes.%d.end", labelid) 1450 labelCmp := fmt.Sprintf(".L.cmpdtypes.%d.cmp", labelid) 1451 printf(" popq %%rdx # dtype label address A\n") 1452 printf(" popq %%rcx # dtype label address B\n") 1453 1454 printf(" cmpq %%rcx, %%rdx\n") 1455 printf(" je %s # jump if match\n", labelTrue) 1456 1457 printf(" cmpq $0, %%rdx # check if A is nil\n") 1458 printf(" je %s # jump if nil\n", labelFalse) 1459 1460 printf(" cmpq $0, %%rcx # check if B is nil\n") 1461 printf(" je %s # jump if nil\n", labelFalse) 1462 1463 printf(" jmp %s # jump to end\n", labelCmp) 1464 1465 printf("%s:\n", labelTrue) 1466 printf(" pushq $1\n") 1467 printf(" jmp %s # jump to end\n", labelEnd) 1468 1469 printf("%s:\n", labelFalse) 1470 printf(" pushq $0\n") 1471 printf(" jmp %s # jump to end\n", labelEnd) 1472 1473 printf("%s:\n", labelCmp) 1474 emitAllocReturnVarsArea(SizeOfInt) // for bool 1475 1476 // push len, push ptr 1477 printf(" movq 16(%%rax), %%rdx # str.len of dtype A\n") 1478 printf(" pushq %%rdx\n") 1479 printf(" movq 8(%%rax), %%rdx # str.ptr of dtype A\n") 1480 printf(" pushq %%rdx\n") 1481 1482 // push len, push ptr 1483 printf(" movq 16(%%rcx), %%rdx # str.len of dtype B\n") 1484 printf(" pushq %%rdx\n") 1485 printf(" movq 8(%%rcx), %%rdx # str.ptr of dtype B\n") 1486 printf(" pushq %%rdx\n") 1487 1488 printf(" callq %s\n", "runtime.cmpstrings") 1489 emitFreeParametersArea(16 * 2) 1490 printf("%s:\n", labelEnd) 1491 } 1492 1493 func emitDtypeLabelAddr(t *Type) { 1494 serializedType := serializeType(t) 1495 dtypeLabel := getDtypeLabel(currentPkg, serializedType) 1496 printf(" leaq %s(%%rip), %%rax # dtype label address \"%s\"\n", dtypeLabel, serializedType) 1497 printf(" pushq %%rax # dtype label address\n") 1498 } 1499 1500 func newNumberLiteral(x int) *ast.BasicLit { 1501 e := &ast.BasicLit{ 1502 Kind: token.INT, 1503 Value: strconv.Itoa(x), 1504 } 1505 return e 1506 } 1507 1508 func emitAddrForMapSet(indexExpr *ast.IndexExpr) { 1509 // alloc heap for map value 1510 //size := getSizeOfType(elmType) 1511 emitComment(2, "[emitAddrForMapSet]\n") 1512 mp := indexExpr.X 1513 key := indexExpr.Index 1514 1515 args := []*Arg{ 1516 &Arg{ 1517 e: mp, 1518 paramType: tUintptr, 1519 }, 1520 &Arg{ 1521 e: key, 1522 paramType: tEface, 1523 }, 1524 } 1525 resultList := &ast.FieldList{ 1526 List: []*ast.Field{ 1527 &ast.Field{ 1528 Type: tUintptr.E, 1529 }, 1530 }, 1531 } 1532 emitCall("runtime.getAddrForMapSet", args, resultList) 1533 } 1534 1535 func emitListElementAddr(list ast.Expr, elmType *Type) { 1536 emitListHeadAddr(list) 1537 emitPopAddress("list head") 1538 printf(" popq %%rcx # index id\n") 1539 printf(" movq $%d, %%rdx # elm size\n", getSizeOfType(elmType)) 1540 printf(" imulq %%rdx, %%rcx\n") 1541 printf(" addq %%rcx, %%rax\n") 1542 printf(" pushq %%rax # addr of element\n") 1543 } 1544 1545 func emitCatStrings(left ast.Expr, right ast.Expr) { 1546 args := []*Arg{ 1547 &Arg{ 1548 e: left, 1549 paramType: tString, 1550 }, 1551 &Arg{ 1552 e: right, 1553 paramType: tString, 1554 }, 1555 } 1556 resultList := &ast.FieldList{ 1557 List: []*ast.Field{ 1558 &ast.Field{ 1559 Type: tString.E, 1560 }, 1561 }, 1562 } 1563 emitCall("runtime.catstrings", args, resultList) 1564 } 1565 1566 func emitCompStrings(left ast.Expr, right ast.Expr) { 1567 args := []*Arg{ 1568 &Arg{ 1569 e: left, 1570 paramType: tString, 1571 offset: 0, 1572 }, 1573 &Arg{ 1574 e: right, 1575 paramType: tString, 1576 offset: 0, 1577 }, 1578 } 1579 resultList := &ast.FieldList{ 1580 List: []*ast.Field{ 1581 &ast.Field{ 1582 Type: tBool.E, 1583 }, 1584 }, 1585 } 1586 emitCall("runtime.cmpstrings", args, resultList) 1587 } 1588 1589 func emitBinaryExprComparison(left ast.Expr, right ast.Expr) { 1590 if kind(getTypeOfExpr(left)) == T_STRING { 1591 emitCompStrings(left, right) 1592 } else if kind(getTypeOfExpr(left)) == T_INTERFACE { 1593 var t = getTypeOfExpr(left) 1594 ff := lookupForeignFunc(newQI("runtime", "cmpinterface")) 1595 emitAllocReturnVarsAreaFF(ff) 1596 emitExpr(left, nil) // left 1597 ctx := &evalContext{_type: t} 1598 emitExprIfc(right, ctx) // right 1599 emitCallFF(ff) 1600 } else { 1601 var t = getTypeOfExpr(left) 1602 emitExpr(left, nil) // left 1603 ctx := &evalContext{_type: t} 1604 emitExprIfc(right, ctx) // right 1605 emitCompExpr("sete") 1606 } 1607 } 1608 1609 //@TODO handle larger types than int 1610 func emitCompExpr(inst string) { 1611 printf(" popq %%rcx # right\n") 1612 printf(" popq %%rax # left\n") 1613 printf(" cmpq %%rcx, %%rax\n") 1614 printf(" %s %%al\n", inst) 1615 printf(" movzbq %%al, %%rax\n") // true:1, false:0 1616 printf(" pushq %%rax\n") 1617 } 1618 1619 func emitPop(knd TypeKind) { 1620 switch knd { 1621 case T_SLICE: 1622 emitPopSlice() 1623 case T_STRING: 1624 emitPopString() 1625 case T_INTERFACE: 1626 emitPopInterFace() 1627 case T_INT, T_BOOL, T_UINTPTR, T_POINTER, T_MAP: 1628 emitPopPrimitive(string(knd)) 1629 case T_UINT16: 1630 emitPopPrimitive(string(knd)) 1631 case T_UINT8: 1632 emitPopPrimitive(string(knd)) 1633 case T_STRUCT, T_ARRAY: 1634 emitPopPrimitive(string(knd)) 1635 default: 1636 unexpectedKind(knd) 1637 } 1638 } 1639 1640 func emitStore(t *Type, rhsTop bool, pushLhs bool) { 1641 knd := kind(t) 1642 emitComment(2, "emitStore(%s)\n", knd) 1643 if rhsTop { 1644 emitPop(knd) // rhs 1645 printf(" popq %%rsi # lhs addr\n") 1646 } else { 1647 printf(" popq %%rsi # lhs addr\n") 1648 emitPop(knd) // rhs 1649 } 1650 if pushLhs { 1651 printf(" pushq %%rsi # lhs addr\n") 1652 } 1653 1654 printf(" pushq %%rsi # place to save\n") 1655 emitRegiToMem(t) 1656 } 1657 1658 func emitRegiToMem(t *Type) { 1659 printf(" popq %%rsi # place to save\n") 1660 k := kind(t) 1661 switch k { 1662 case T_SLICE: 1663 printf(" movq %%rax, %d(%%rsi) # ptr to ptr\n", 0) 1664 printf(" movq %%rcx, %d(%%rsi) # len to len\n", 8) 1665 printf(" movq %%rdx, %d(%%rsi) # cap to cap\n", 16) 1666 case T_STRING: 1667 printf(" movq %%rax, %d(%%rsi) # ptr to ptr\n", 0) 1668 printf(" movq %%rcx, %d(%%rsi) # len to len\n", 8) 1669 case T_INTERFACE: 1670 printf(" movq %%rax, %d(%%rsi) # store dtype\n", 0) 1671 printf(" movq %%rcx, %d(%%rsi) # store data\n", 8) 1672 case T_INT, T_BOOL, T_UINTPTR, T_POINTER, T_MAP: 1673 printf(" movq %%rax, %d(%%rsi) # assign\n", 0) 1674 case T_UINT16: 1675 printf(" movw %%ax, %d(%%rsi) # assign word\n", 0) 1676 case T_UINT8: 1677 printf(" movb %%al, %d(%%rsi) # assign byte\n", 0) 1678 case T_STRUCT, T_ARRAY: 1679 printf(" pushq $%d # size\n", getSizeOfType(t)) 1680 printf(" pushq %%rsi # dst lhs\n") 1681 printf(" pushq %%rax # src rhs\n") 1682 ff := lookupForeignFunc(newQI("runtime", "memcopy")) 1683 emitCallFF(ff) 1684 default: 1685 unexpectedKind(k) 1686 } 1687 } 1688 1689 func isBlankIdentifier(e ast.Expr) bool { 1690 ident, isIdent := e.(*ast.Ident) 1691 if !isIdent { 1692 return false 1693 } 1694 return ident.Name == "_" 1695 } 1696 1697 func emitAssignToVar(vr *Variable, rhs ast.Expr) { 1698 emitComment(2, "Assignment: emitAddr(lhs)\n") 1699 emitVariableAddr(vr) 1700 emitComment(2, "Assignment: emitExpr(rhs)\n") 1701 ctx := &evalContext{ 1702 _type: vr.Typ, 1703 } 1704 emitExprIfc(rhs, ctx) 1705 emitComment(2, "Assignment: emitStore(getTypeOfExpr(lhs))\n") 1706 emitStore(vr.Typ, true, false) 1707 } 1708 1709 func emitAssign(lhs ast.Expr, rhs ast.Expr) { 1710 emitComment(2, "Assignment: emitAddr(lhs)\n") 1711 emitAddr(lhs) 1712 emitComment(2, "Assignment: emitExpr(rhs)\n") 1713 ctx := &evalContext{ 1714 _type: getTypeOfExpr(lhs), 1715 } 1716 emitExprIfc(rhs, ctx) 1717 emitStore(getTypeOfExpr(lhs), true, false) 1718 } 1719 1720 func emitBlockStmt(s *ast.BlockStmt) { 1721 for _, s := range s.List { 1722 emitStmt(s) 1723 } 1724 } 1725 func emitExprStmt(s *ast.ExprStmt) { 1726 emitExpr(s.X, nil) 1727 } 1728 func emitDeclStmt(s *ast.DeclStmt) { 1729 genDecl := s.Decl.(*ast.GenDecl) 1730 declSpec := genDecl.Specs[0] 1731 switch spec := declSpec.(type) { 1732 case *ast.ValueSpec: 1733 valSpec := spec 1734 t := e2t(valSpec.Type) 1735 lhs := valSpec.Names[0] 1736 if len(valSpec.Values) == 0 { 1737 emitComment(2, "lhs addresss\n") 1738 emitAddr(lhs) 1739 emitComment(2, "emitZeroValue\n") 1740 emitZeroValue(t) 1741 emitComment(2, "Assignment: zero value\n") 1742 emitStore(t, true, false) 1743 } else if len(valSpec.Values) == 1 { 1744 // assignment 1745 rhs := valSpec.Values[0] 1746 emitAssign(lhs, rhs) 1747 } else { 1748 panic("TBI") 1749 } 1750 default: 1751 throw(declSpec) 1752 } 1753 } 1754 func emitAssignStmt(s *ast.AssignStmt) { 1755 switch s.Tok.String() { 1756 case "=", ":=": 1757 rhs0 := s.Rhs[0] 1758 _, isTypeAssertion := rhs0.(*ast.TypeAssertExpr) 1759 indexExpr, isIndexExpr := rhs0.(*ast.IndexExpr) 1760 var isOKSytax bool 1761 if len(s.Lhs) == 2 && isTypeAssertion { 1762 isOKSytax = true 1763 } 1764 if len(s.Lhs) == 2 && isIndexExpr && kind(getTypeOfExpr(indexExpr.X)) == T_MAP { 1765 isOKSytax = true 1766 } 1767 if isOKSytax { 1768 emitComment(2, "Assignment: emitAssignWithOK rhs\n") 1769 ctx := &evalContext{ 1770 okContext: true, 1771 } 1772 emitExprIfc(rhs0, ctx) // {push data}, {push bool} 1773 lhsOK := s.Lhs[1] 1774 if isBlankIdentifier(lhsOK) { 1775 emitPop(T_BOOL) 1776 } else { 1777 emitComment(2, "Assignment: ok variable\n") 1778 emitAddr(lhsOK) 1779 emitStore(getTypeOfExpr(lhsOK), false, false) 1780 } 1781 1782 lhsMain := s.Lhs[0] 1783 if isBlankIdentifier(lhsMain) { 1784 emitPop(kind(getTypeOfExpr(rhs0))) 1785 } else { 1786 emitAddr(lhsMain) 1787 emitComment(2, "Assignment: emitStore(getTypeOfExpr(lhs))\n") 1788 emitStore(getTypeOfExpr(lhsMain), false, false) 1789 } 1790 } else { 1791 if len(s.Lhs) == 1 && len(s.Rhs) == 1 { 1792 // 1 to 1 assignment 1793 // x = e 1794 lhs0 := s.Lhs[0] 1795 ident, isIdent := lhs0.(*ast.Ident) 1796 if isIdent && ident.Name == "_" { 1797 panic(" _ is not supported yet") 1798 } 1799 emitAssign(lhs0, rhs0) 1800 } else if len(s.Lhs) >= 1 && len(s.Rhs) == 1 { 1801 // multi-values expr 1802 // a, b, c = f() 1803 emitExpr(rhs0, nil) // @TODO interface conversion 1804 callExpr := rhs0.(*ast.CallExpr) 1805 returnTypes := getCallResultTypes(callExpr) 1806 printf("# len lhs=%d\n", len(s.Lhs)) 1807 printf("# returnTypes=%d\n", len(returnTypes)) 1808 assert(len(returnTypes) == len(s.Lhs), fmt.Sprintf("length unmatches %d <=> %d", len(s.Lhs), len(returnTypes)), __func__) 1809 length := len(returnTypes) 1810 for i := 0; i < length; i++ { 1811 lhs := s.Lhs[i] 1812 rhsType := returnTypes[i] 1813 if isBlankIdentifier(lhs) { 1814 emitPop(kind(rhsType)) 1815 } else { 1816 switch kind(rhsType) { 1817 case T_UINT8: 1818 // repush stack top 1819 printf(" movzbq (%%rsp), %%rax # load uint8\n") 1820 printf(" addq $%d, %%rsp # free returnvars area\n", 1) 1821 printf(" pushq %%rax\n") 1822 } 1823 emitAddr(lhs) 1824 emitStore(getTypeOfExpr(lhs), false, false) 1825 } 1826 } 1827 1828 } 1829 } 1830 case "+=": 1831 binaryExpr := &ast.BinaryExpr{ 1832 X: s.Lhs[0], 1833 Op: token.ADD, 1834 Y: s.Rhs[0], 1835 } 1836 emitAssign(s.Lhs[0], binaryExpr) 1837 case "-=": 1838 binaryExpr := &ast.BinaryExpr{ 1839 X: s.Lhs[0], 1840 Op: token.SUB, 1841 Y: s.Rhs[0], 1842 } 1843 emitAssign(s.Lhs[0], binaryExpr) 1844 default: 1845 panic("TBI: assignment of " + s.Tok.String()) 1846 } 1847 } 1848 func emitIfStmt(s *ast.IfStmt) { 1849 emitComment(2, "if\n") 1850 1851 labelid++ 1852 labelEndif := fmt.Sprintf(".L.endif.%d", labelid) 1853 labelElse := fmt.Sprintf(".L.else.%d", labelid) 1854 1855 emitExpr(s.Cond, nil) 1856 emitPopBool("if condition") 1857 printf(" cmpq $1, %%rax\n") 1858 if s.Else != nil { 1859 printf(" jne %s # jmp if false\n", labelElse) 1860 emitStmt(s.Body) // then 1861 printf(" jmp %s\n", labelEndif) 1862 printf(" %s:\n", labelElse) 1863 emitStmt(s.Else) // then 1864 } else { 1865 printf(" jne %s # jmp if false\n", labelEndif) 1866 emitStmt(s.Body) // then 1867 } 1868 printf(" %s:\n", labelEndif) 1869 emitComment(2, "end if\n") 1870 } 1871 1872 func emitForStmt(s *ast.ForStmt) { 1873 meta := getMetaForStmt(s) 1874 labelid++ 1875 labelCond := fmt.Sprintf(".L.for.cond.%d", labelid) 1876 labelPost := fmt.Sprintf(".L.for.post.%d", labelid) 1877 labelExit := fmt.Sprintf(".L.for.exit.%d", labelid) 1878 1879 meta.LabelPost = labelPost 1880 meta.LabelExit = labelExit 1881 1882 if s.Init != nil { 1883 emitStmt(s.Init) 1884 } 1885 1886 printf(" %s:\n", labelCond) 1887 if s.Cond != nil { 1888 emitExpr(s.Cond, nil) 1889 emitPopBool("for condition") 1890 printf(" cmpq $1, %%rax\n") 1891 printf(" jne %s # jmp if false\n", labelExit) 1892 } 1893 emitStmt(s.Body) 1894 printf(" %s:\n", labelPost) // used for "continue" 1895 if s.Post != nil { 1896 emitStmt(s.Post) 1897 } 1898 printf(" jmp %s\n", labelCond) 1899 printf(" %s:\n", labelExit) 1900 } 1901 1902 func emitRangeMap(s *ast.RangeStmt, meta *MetaForStmt) { 1903 labelid++ 1904 labelCond := fmt.Sprintf(".L.range.cond.%d", labelid) 1905 labelPost := fmt.Sprintf(".L.range.post.%d", labelid) 1906 labelExit := fmt.Sprintf(".L.range.exit.%d", labelid) 1907 1908 meta.LabelPost = labelPost 1909 meta.LabelExit = labelExit 1910 1911 // Overall design: 1912 // _mp := EXPR 1913 // if _mp == nil then exit 1914 // for _item = _mp.first; _item != nil; item = item.next { 1915 // ... 1916 // } 1917 1918 emitComment(2, "ForRange map Initialization\n") 1919 1920 // _mp = EXPR 1921 emitAssignToVar(meta.ForRange.MapVar, s.X) 1922 1923 // if _mp == nil then exit 1924 emitVariable(meta.ForRange.MapVar) // value of _mp 1925 printf(" popq %%rax\n") 1926 printf(" cmpq $0, %%rax\n") 1927 printf(" je %s # exit if nil\n", labelExit) 1928 1929 // item = mp.first 1930 emitVariableAddr(meta.ForRange.ItemVar) 1931 emitVariable(meta.ForRange.MapVar) // value of _mp 1932 emitLoadAndPush(tUintptr) // value of _mp.first 1933 emitStore(tUintptr, true, false) // assign 1934 1935 // Condition 1936 // if item != nil; then 1937 // execute body 1938 // else 1939 // exit 1940 emitComment(2, "ForRange Condition\n") 1941 printf(" %s:\n", labelCond) 1942 1943 emitVariable(meta.ForRange.ItemVar) 1944 printf(" popq %%rax\n") 1945 printf(" cmpq $0, %%rax\n") 1946 printf(" je %s # exit if nil\n", labelExit) 1947 1948 emitComment(2, "assign key value to variables\n") 1949 1950 // assign key 1951 if s.Key != nil { 1952 keyIdent := s.Key.(*ast.Ident) 1953 if keyIdent.Name != "_" { 1954 emitAddr(s.Key) // lhs 1955 // emit value of item.key 1956 //type item struct { 1957 // next *item 1958 // key_dtype uintptr 1959 // key_data uintptr <-- this 1960 // value uintptr 1961 //} 1962 emitVariable(meta.ForRange.ItemVar) 1963 printf(" popq %%rax\n") // &item{....} 1964 printf(" movq 16(%%rax), %%rcx\n") // item.key_data 1965 printf(" pushq %%rcx\n") 1966 emitLoadAndPush(getTypeOfExpr(s.Key)) // load dynamic data 1967 emitStore(getTypeOfExpr(s.Key), true, false) 1968 } 1969 } 1970 1971 // assign value 1972 if s.Value != nil { 1973 valueIdent := s.Value.(*ast.Ident) 1974 if valueIdent.Name != "_" { 1975 emitAddr(s.Value) // lhs 1976 // emit value of item 1977 //type item struct { 1978 // next *item 1979 // key_dtype uintptr 1980 // key_data uintptr 1981 // value uintptr <-- this 1982 //} 1983 emitVariable(meta.ForRange.ItemVar) 1984 printf(" popq %%rax\n") // &item{....} 1985 printf(" movq 24(%%rax), %%rcx\n") // item.key_data 1986 printf(" pushq %%rcx\n") 1987 emitLoadAndPush(getTypeOfExpr(s.Value)) // load dynamic data 1988 emitStore(getTypeOfExpr(s.Value), true, false) 1989 } 1990 } 1991 1992 // Body 1993 emitComment(2, "ForRange Body\n") 1994 emitStmt(s.Body) 1995 1996 // Post statement 1997 // item = item.next 1998 emitComment(2, "ForRange Post statement\n") 1999 printf(" %s:\n", labelPost) // used for "continue" 2000 emitVariableAddr(meta.ForRange.ItemVar) // lhs 2001 emitVariable(meta.ForRange.ItemVar) // item 2002 emitLoadAndPush(tUintptr) // item.next 2003 emitStore(tUintptr, true, false) 2004 2005 printf(" jmp %s\n", labelCond) 2006 2007 printf(" %s:\n", labelExit) 2008 } 2009 2010 // only for array and slice for now 2011 func emitRangeStmt(s *ast.RangeStmt) { 2012 meta := getMetaForStmt(s) 2013 if meta.ForRange.IsMap { 2014 emitRangeMap(s, meta) 2015 return 2016 } 2017 labelid++ 2018 labelCond := fmt.Sprintf(".L.range.cond.%d", labelid) 2019 labelPost := fmt.Sprintf(".L.range.post.%d", labelid) 2020 labelExit := fmt.Sprintf(".L.range.exit.%d", labelid) 2021 2022 meta.LabelPost = labelPost 2023 meta.LabelExit = labelExit 2024 // initialization: store len(rangeexpr) 2025 emitComment(2, "ForRange Initialization\n") 2026 emitComment(2, " assign length to lenvar\n") 2027 // lenvar = len(s.X) 2028 emitVariableAddr(meta.ForRange.LenVar) 2029 emitLen(s.X) 2030 emitStore(tInt, true, false) 2031 2032 emitComment(2, " assign 0 to indexvar\n") 2033 // indexvar = 0 2034 emitVariableAddr(meta.ForRange.Indexvar) 2035 emitZeroValue(tInt) 2036 emitStore(tInt, true, false) 2037 2038 // init key variable with 0 2039 if s.Key != nil { 2040 keyIdent := s.Key.(*ast.Ident) 2041 if keyIdent.Name != "_" { 2042 emitAddr(s.Key) // lhs 2043 emitZeroValue(tInt) 2044 emitStore(tInt, true, false) 2045 } 2046 } 2047 2048 // Condition 2049 // if (indexvar < lenvar) then 2050 // execute body 2051 // else 2052 // exit 2053 emitComment(2, "ForRange Condition\n") 2054 printf(" %s:\n", labelCond) 2055 2056 emitVariableAddr(meta.ForRange.Indexvar) 2057 emitLoadAndPush(tInt) 2058 emitVariableAddr(meta.ForRange.LenVar) 2059 emitLoadAndPush(tInt) 2060 emitCompExpr("setl") 2061 emitPopBool(" indexvar < lenvar") 2062 printf(" cmpq $1, %%rax\n") 2063 printf(" jne %s # jmp if false\n", labelExit) 2064 2065 emitComment(2, "assign list[indexvar] value variables\n") 2066 elemType := getTypeOfExpr(s.Value) 2067 emitAddr(s.Value) // lhs 2068 2069 emitVariableAddr(meta.ForRange.Indexvar) 2070 emitLoadAndPush(tInt) // index value 2071 emitListElementAddr(s.X, elemType) 2072 2073 emitLoadAndPush(elemType) 2074 emitStore(elemType, true, false) 2075 2076 // Body 2077 emitComment(2, "ForRange Body\n") 2078 emitStmt(s.Body) 2079 2080 // Post statement: Increment indexvar and go next 2081 emitComment(2, "ForRange Post statement\n") 2082 printf(" %s:\n", labelPost) // used for "continue" 2083 emitVariableAddr(meta.ForRange.Indexvar) // lhs 2084 emitVariableAddr(meta.ForRange.Indexvar) // rhs 2085 emitLoadAndPush(tInt) 2086 emitAddConst(1, "indexvar value ++") 2087 emitStore(tInt, true, false) 2088 2089 // incr key variable 2090 if s.Key != nil { 2091 keyIdent := s.Key.(*ast.Ident) 2092 if keyIdent.Name != "_" { 2093 emitAddr(s.Key) // lhs 2094 emitVariableAddr(meta.ForRange.Indexvar) // rhs 2095 emitLoadAndPush(tInt) 2096 emitStore(tInt, true, false) 2097 } 2098 } 2099 2100 printf(" jmp %s\n", labelCond) 2101 2102 printf(" %s:\n", labelExit) 2103 } 2104 func emitIncDecStmt(s *ast.IncDecStmt) { 2105 var addValue int 2106 switch s.Tok.String() { 2107 case "++": 2108 addValue = 1 2109 case "--": 2110 addValue = -1 2111 default: 2112 panic("Unexpected Tok=" + s.Tok.String()) 2113 } 2114 emitAddr(s.X) 2115 emitExpr(s.X, nil) 2116 emitAddConst(addValue, "rhs ++ or --") 2117 emitStore(getTypeOfExpr(s.X), true, false) 2118 } 2119 func emitSwitchStmt(s *ast.SwitchStmt) { 2120 labelid++ 2121 labelEnd := fmt.Sprintf(".L.switch.%d.exit", labelid) 2122 if s.Init != nil { 2123 panic("TBI") 2124 } 2125 if s.Tag == nil { 2126 panic("Omitted tag is not supported yet") 2127 } 2128 emitExpr(s.Tag, nil) 2129 condType := getTypeOfExpr(s.Tag) 2130 cases := s.Body.List 2131 var labels = make([]string, len(cases), len(cases)) 2132 var defaultLabel string 2133 emitComment(2, "Start comparison with cases\n") 2134 for i, c := range cases { 2135 cc := c.(*ast.CaseClause) 2136 labelid++ 2137 labelCase := fmt.Sprintf(".L.case.%d", labelid) 2138 labels[i] = labelCase 2139 if len(cc.List) == 0 { 2140 defaultLabel = labelCase 2141 continue 2142 } 2143 for _, e := range cc.List { 2144 assert(getSizeOfType(condType) <= 8 || kind(condType) == T_STRING, "should be one register size or string", __func__) 2145 switch kind(condType) { 2146 case T_STRING: 2147 ff := lookupForeignFunc(newQI("runtime", "cmpstrings")) 2148 emitAllocReturnVarsAreaFF(ff) 2149 2150 emitPushStackTop(condType, SizeOfInt, "switch expr") 2151 emitExpr(e, nil) 2152 2153 emitCallFF(ff) 2154 case T_INTERFACE: 2155 ff := lookupForeignFunc(newQI("runtime", "cmpinterface")) 2156 2157 emitAllocReturnVarsAreaFF(ff) 2158 2159 emitPushStackTop(condType, SizeOfInt, "switch expr") 2160 emitExpr(e, nil) 2161 2162 emitCallFF(ff) 2163 case T_INT, T_UINT8, T_UINT16, T_UINTPTR, T_POINTER: 2164 emitPushStackTop(condType, 0, "switch expr") 2165 emitExpr(e, nil) 2166 emitCompExpr("sete") 2167 default: 2168 unexpectedKind(kind(condType)) 2169 } 2170 2171 emitPopBool(" of switch-case comparison") 2172 printf(" cmpq $1, %%rax\n") 2173 printf(" je %s # jump if match\n", labelCase) 2174 } 2175 } 2176 emitComment(2, "End comparison with cases\n") 2177 2178 // if no case matches, then jump to 2179 if defaultLabel != "" { 2180 // default 2181 printf(" jmp %s\n", defaultLabel) 2182 } else { 2183 // exit 2184 printf(" jmp %s\n", labelEnd) 2185 } 2186 2187 emitRevertStackTop(condType) 2188 for i, c := range cases { 2189 cc := c.(*ast.CaseClause) 2190 printf("%s:\n", labels[i]) 2191 for _, _s := range cc.Body { 2192 emitStmt(_s) 2193 } 2194 printf(" jmp %s\n", labelEnd) 2195 } 2196 printf("%s:\n", labelEnd) 2197 } 2198 func emitTypeSwitchStmt(s *ast.TypeSwitchStmt) { 2199 meta := getMetaTypeSwitchStmt(s) 2200 labelid++ 2201 labelEnd := fmt.Sprintf(".L.typeswitch.%d.exit", labelid) 2202 2203 // subjectVariable = subject 2204 emitVariableAddr(meta.SubjectVariable) 2205 emitExpr(meta.Subject, nil) 2206 emitStore(tEface, true, false) 2207 2208 cases := s.Body.List 2209 var labels = make([]string, len(cases), len(cases)) 2210 var defaultLabel string 2211 emitComment(2, "Start comparison with cases\n") 2212 for i, c := range cases { 2213 cc := c.(*ast.CaseClause) 2214 labelid++ 2215 labelCase := ".L.case." + strconv.Itoa(labelid) 2216 labels[i] = labelCase 2217 if len(cc.List) == 0 { 2218 defaultLabel = labelCase 2219 continue 2220 } 2221 for _, e := range cc.List { 2222 emitVariableAddr(meta.SubjectVariable) 2223 emitPopAddress("type switch subject") 2224 printf(" movq (%%rax), %%rax # dtype label addr\n") 2225 printf(" pushq %%rax # dtype label addr\n") 2226 2227 if isNil(cc.List[0]) { // case nil: 2228 printf(" pushq $0 # nil\n") 2229 } else { // case T: 2230 emitDtypeLabelAddr(e2t(e)) 2231 } 2232 emitCompareDtypes() 2233 emitPopBool(" of switch-case comparison") 2234 2235 printf(" cmpq $1, %%rax\n") 2236 printf(" je %s # jump if match\n", labelCase) 2237 } 2238 } 2239 emitComment(2, "End comparison with cases\n") 2240 2241 // if no case matches, then jump to 2242 if defaultLabel != "" { 2243 // default 2244 printf(" jmp %s\n", defaultLabel) 2245 } else { 2246 // exit 2247 printf(" jmp %s\n", labelEnd) 2248 } 2249 2250 for i, typeSwitchCaseClose := range meta.Cases { 2251 // Injecting variable and type to the subject 2252 if typeSwitchCaseClose.Variable != nil { 2253 setVariable(meta.AssignIdent.Obj, typeSwitchCaseClose.Variable) 2254 } 2255 printf("%s:\n", labels[i]) 2256 2257 cc := typeSwitchCaseClose.Orig 2258 var _isNil bool 2259 for _, typ := range cc.List { 2260 if isNil(typ) { 2261 _isNil = true 2262 } 2263 } 2264 for _, _s := range cc.Body { 2265 if typeSwitchCaseClose.Variable != nil { 2266 // do assignment 2267 if _isNil { 2268 // @TODO: assign nil to the AssignIdent of interface type 2269 } else { 2270 emitAddr(meta.AssignIdent) // push lhs 2271 2272 // push rhs 2273 emitVariableAddr(meta.SubjectVariable) 2274 emitLoadAndPush(tEface) 2275 printf(" popq %%rax # ifc.dtype\n") 2276 printf(" popq %%rcx # ifc.data\n") 2277 printf(" pushq %%rcx # ifc.data\n") 2278 emitLoadAndPush(typeSwitchCaseClose.VariableType) 2279 2280 // assign 2281 emitStore(typeSwitchCaseClose.VariableType, true, false) 2282 } 2283 } 2284 2285 emitStmt(_s) 2286 } 2287 printf(" jmp %s\n", labelEnd) 2288 } 2289 printf("%s:\n", labelEnd) 2290 } 2291 func emitBranchStmt(s *ast.BranchStmt) { 2292 meta := getMetaBranchStmt(s) 2293 containerFor := meta.containerForStmt 2294 switch s.Tok.String() { 2295 case "continue": 2296 printf("jmp %s # continue\n", containerFor.LabelPost) 2297 case "break": 2298 printf("jmp %s # break\n", containerFor.LabelExit) 2299 default: 2300 throw(s.Tok) 2301 } 2302 } 2303 2304 func emitStmt(stmt ast.Stmt) { 2305 emitComment(2, "== Statement %T ==\n", stmt) 2306 switch s := stmt.(type) { 2307 case *ast.BlockStmt: 2308 emitBlockStmt(s) 2309 case *ast.ExprStmt: 2310 emitExprStmt(s) 2311 case *ast.DeclStmt: 2312 emitDeclStmt(s) 2313 case *ast.AssignStmt: 2314 emitAssignStmt(s) 2315 case *ast.ReturnStmt: 2316 emitReturnStmt(s) 2317 case *ast.IfStmt: 2318 emitIfStmt(s) 2319 case *ast.ForStmt: 2320 emitForStmt(s) 2321 case *ast.RangeStmt: 2322 emitRangeStmt(s) // only for array and slice 2323 case *ast.IncDecStmt: 2324 emitIncDecStmt(s) 2325 case *ast.SwitchStmt: 2326 emitSwitchStmt(s) 2327 case *ast.TypeSwitchStmt: 2328 emitTypeSwitchStmt(s) 2329 case *ast.BranchStmt: 2330 emitBranchStmt(s) 2331 default: 2332 throw(stmt) 2333 } 2334 } 2335 2336 func emitRevertStackTop(t *Type) { 2337 printf(" addq $%d, %%rsp # revert stack top\n", getSizeOfType(t)) 2338 } 2339 2340 var labelid int 2341 2342 func getMethodSymbol(method *Method) string { 2343 rcvTypeName := method.RcvNamedType 2344 var subsymbol string 2345 if method.IsPtrMethod { 2346 subsymbol = "$" + rcvTypeName.Name + "." + method.Name // pointer 2347 } else { 2348 subsymbol = rcvTypeName.Name + "." + method.Name // value 2349 } 2350 2351 return getPackageSymbol(method.PkgName, subsymbol) 2352 } 2353 2354 func getPackageSymbol(pkgName string, subsymbol string) string { 2355 return pkgName + "." + subsymbol 2356 } 2357 2358 func emitFuncDecl(pkgName string, fnc *Func) { 2359 printf("# emitFuncDecl\n") 2360 if len(fnc.Params) > 0 { 2361 for i := 0; i < len(fnc.Params); i++ { 2362 v := fnc.Params[i] 2363 logf(" # params %d %d \"%s\" %s\n", v.LocalOffset, getSizeOfType(v.Typ), v.Name, string(kind(v.Typ))) 2364 } 2365 } 2366 if len(fnc.Retvars) > 0 { 2367 for i := 0; i < len(fnc.Retvars); i++ { 2368 v := fnc.Retvars[i] 2369 logf(" # retvars %d %d \"%s\" %s\n", v.LocalOffset, getSizeOfType(v.Typ), v.Name, string(kind(v.Typ))) 2370 } 2371 } 2372 2373 var symbol string 2374 if fnc.Method != nil { 2375 symbol = getMethodSymbol(fnc.Method) 2376 } else { 2377 symbol = getPackageSymbol(pkgName, fnc.Name) 2378 } 2379 printf("%s: # args %d, locals %d\n", symbol, fnc.Argsarea, fnc.Localarea) 2380 printf(" pushq %%rbp\n") 2381 printf(" movq %%rsp, %%rbp\n") 2382 if len(fnc.LocalVars) > 0 { 2383 for i := len(fnc.LocalVars) - 1; i >= 0; i-- { 2384 v := fnc.LocalVars[i] 2385 logf(" # -%d(%%rbp) local variable %d \"%s\"\n", -v.LocalOffset, getSizeOfType(v.Typ), v.Name) 2386 } 2387 } 2388 logf(" # 0(%%rbp) previous rbp\n") 2389 logf(" # 8(%%rbp) return address\n") 2390 2391 if fnc.Localarea != 0 { 2392 printf(" subq $%d, %%rsp # local area\n", -fnc.Localarea) 2393 } 2394 for _, stmt := range fnc.Stmts { 2395 emitStmt(stmt) 2396 } 2397 printf(" leave\n") 2398 printf(" ret\n") 2399 } 2400 2401 func emitGlobalVariableComplex(name *ast.Ident, t *Type, val ast.Expr) { 2402 typeKind := kind(t) 2403 switch typeKind { 2404 case T_POINTER: 2405 printf("# init global %s:\n", name.Name) 2406 emitAssign(name, val) 2407 case T_MAP: 2408 emitAssign(name, val) 2409 case T_INTERFACE: 2410 emitAssign(name, val) 2411 } 2412 } 2413 2414 func emitGlobalVariable(pkg *PkgContainer, name *ast.Ident, t *Type, val ast.Expr) { 2415 typeKind := kind(t) 2416 printf("%s.%s: # T %s\n", pkg.name, name.Name, string(typeKind)) 2417 switch typeKind { 2418 case T_STRING: 2419 switch vl := val.(type) { 2420 case nil: 2421 printf(" .quad 0\n") 2422 printf(" .quad 0\n") 2423 case *ast.BasicLit: 2424 sl := getStringLiteral(vl) 2425 printf(" .quad %s\n", sl.label) 2426 printf(" .quad %d\n", sl.strlen) 2427 default: 2428 panic("Unsupported global string value") 2429 } 2430 case T_BOOL: 2431 switch vl := val.(type) { 2432 case nil: 2433 printf(" .quad 0 # bool zero value\n") 2434 case *ast.Ident: 2435 switch vl.Obj { 2436 case gTrue: 2437 printf(" .quad 1 # bool true\n") 2438 case gFalse: 2439 printf(" .quad 0 # bool false\n") 2440 default: 2441 throw(val) 2442 } 2443 default: 2444 throw(val) 2445 } 2446 case T_INT: 2447 switch vl := val.(type) { 2448 case nil: 2449 printf(" .quad 0\n") 2450 case *ast.BasicLit: 2451 printf(" .quad %s\n", vl.Value) 2452 default: 2453 throw(val) 2454 } 2455 case T_UINT8: 2456 switch vl := val.(type) { 2457 case nil: 2458 printf(" .byte 0\n") 2459 case *ast.BasicLit: 2460 printf(" .byte %s\n", vl.Value) 2461 default: 2462 throw(val) 2463 } 2464 case T_UINT16: 2465 switch vl := val.(type) { 2466 case nil: 2467 printf(" .word 0\n") 2468 case *ast.BasicLit: 2469 printf(" .word %s\n", vl.Value) 2470 default: 2471 throw(val) 2472 } 2473 case T_UINTPTR: 2474 // only zero value 2475 if val != nil { 2476 panic("Unsupported global value") 2477 } 2478 printf(" .quad 0\n") 2479 case T_SLICE: 2480 // only zero value 2481 if val != nil { 2482 panic("Unsupported global value") 2483 } 2484 printf(" .quad 0 # ptr\n") 2485 printf(" .quad 0 # len\n") 2486 printf(" .quad 0 # cap\n") 2487 case T_ARRAY: 2488 // only zero value 2489 if val != nil { 2490 panic("Unsupported global value") 2491 } 2492 arrayType := t.E.(*ast.ArrayType) 2493 assert(arrayType.Len != nil, "slice type is not expected", __func__) 2494 length := evalInt(arrayType.Len) 2495 var zeroValue string 2496 knd := kind(e2t(arrayType.Elt)) 2497 switch knd { 2498 case T_INT: 2499 zeroValue = " .quad 0 # int zero value\n" 2500 case T_UINT8: 2501 zeroValue = " .byte 0 # uint8 zero value\n" 2502 case T_STRING: 2503 zeroValue = " .quad 0 # string zero value (ptr)\n" 2504 zeroValue += " .quad 0 # string zero value (len)\n" 2505 case T_INTERFACE: 2506 zeroValue = " .quad 0 # eface zero value (dtype)\n" 2507 zeroValue += " .quad 0 # eface zero value (data)\n" 2508 default: 2509 unexpectedKind(knd) 2510 } 2511 for i := 0; i < length; i++ { 2512 printf(zeroValue) 2513 } 2514 case T_POINTER: 2515 // will be set in the initGlobal func 2516 printf(" .quad 0\n") 2517 case T_MAP: 2518 // will be set in the initGlobal func 2519 printf(" .quad 0\n") 2520 case T_INTERFACE: 2521 // will be set in the initGlobal func 2522 printf(" .quad 0\n") 2523 printf(" .quad 0\n") 2524 default: 2525 unexpectedKind(typeKind) 2526 } 2527 } 2528 2529 func generateCode(pkg *PkgContainer) { 2530 printf("#===================== generateCode %s =====================\n", pkg.name) 2531 printf(".data\n") 2532 for _, con := range pkg.stringLiterals { 2533 emitComment(0, "string literals\n") 2534 printf("%s:\n", con.sl.label) 2535 printf(" .string %s\n", con.sl.value) 2536 } 2537 2538 for _, spec := range pkg.vars { 2539 var val ast.Expr 2540 if len(spec.Values) > 0 { 2541 val = spec.Values[0] 2542 } 2543 var t *Type 2544 if spec.Type != nil { 2545 t = e2t(spec.Type) 2546 } else { 2547 t = getTypeOfExpr(val) 2548 } 2549 if t == nil { 2550 panic("type cannot be nil for global variable: " + spec.Names[0].Name) 2551 } 2552 emitGlobalVariable(pkg, spec.Names[0], t, val) 2553 } 2554 printf("\n") 2555 printf(".text\n") 2556 printf("%s.__initGlobals:\n", pkg.name) 2557 for _, spec := range pkg.vars { 2558 if len(spec.Values) == 0 { 2559 continue 2560 } 2561 val := spec.Values[0] 2562 var t *Type 2563 if spec.Type != nil { 2564 t = e2t(spec.Type) 2565 } 2566 emitGlobalVariableComplex(spec.Names[0], t, val) 2567 } 2568 printf(" ret\n") 2569 2570 for _, fnc := range pkg.funcs { 2571 emitFuncDecl(pkg.name, fnc) 2572 } 2573 2574 emitDynamicTypes(typesMap) 2575 printf("\n") 2576 2577 for _, file := range pkg.files { 2578 if strings.HasSuffix(file, ".s") { 2579 printf("# === static assembly %s ====\n", file) 2580 asmContents, err := os.ReadFile(file) 2581 if err != nil { 2582 panic(err) 2583 } 2584 printf("%s", string(asmContents)) 2585 } 2586 } 2587 } 2588 2589 func emitDynamicTypes(mapDtypes map[string]*dtypeEntry) { 2590 printf("# ------- Dynamic Types ------\n") 2591 printf(".data\n") 2592 2593 sliceTypeMap := make([]string, len(mapDtypes)+1, len(mapDtypes)+1) 2594 2595 // sort map in order to assure the deterministic results 2596 for key, ent := range mapDtypes { 2597 sliceTypeMap[ent.id] = key 2598 } 2599 2600 // skip id=0 2601 for id := 1; id < len(sliceTypeMap); id++ { 2602 key := sliceTypeMap[id] 2603 ent := mapDtypes[key] 2604 2605 printf("%s: # %s\n", ent.label, key) 2606 printf(" .quad %d\n", id) 2607 printf(" .quad .%s.S.dtype.%d\n", ent.pkgname, id) 2608 printf(" .quad %d\n", len(ent.serialized)) 2609 printf(".%s.S.dtype.%d:\n", ent.pkgname, id) 2610 printf(" .string \"%s\"\n", ent.serialized) 2611 } 2612 printf("\n") 2613 } 2614 2615 // --- type --- 2616 type Type struct { 2617 E ast.Expr // original 2618 } 2619 2620 type TypeKind string 2621 2622 const T_STRING TypeKind = "T_STRING" 2623 const T_INTERFACE TypeKind = "T_INTERFACE" 2624 const T_SLICE TypeKind = "T_SLICE" 2625 const T_BOOL TypeKind = "T_BOOL" 2626 const T_INT TypeKind = "T_INT" 2627 const T_INT32 TypeKind = "T_INT32" 2628 const T_UINT8 TypeKind = "T_UINT8" 2629 const T_UINT16 TypeKind = "T_UINT16" 2630 const T_UINTPTR TypeKind = "T_UINTPTR" 2631 const T_ARRAY TypeKind = "T_ARRAY" 2632 const T_STRUCT TypeKind = "T_STRUCT" 2633 const T_POINTER TypeKind = "T_POINTER" 2634 const T_MAP TypeKind = "T_MAP" 2635 2636 // types of an expr in single value context 2637 func getTypeOfExpr(expr ast.Expr) *Type { 2638 switch e := expr.(type) { 2639 case *ast.Ident: 2640 assert(e.Obj != nil, "Obj is nil in ident '"+e.Name+"'", __func__) 2641 switch e.Obj.Kind { 2642 case ast.Var: 2643 // injected type is the 1st priority 2644 // this use case happens in type switch with short decl var 2645 // switch ident := x.(type) { 2646 // case T: 2647 // y := ident // <= type of ident cannot be associated directly with ident 2648 // 2649 variable, isVariable := e.Obj.Data.(*Variable) 2650 if isVariable { 2651 return variable.Typ 2652 } 2653 switch dcl := e.Obj.Decl.(type) { 2654 case *ast.ValueSpec: 2655 return e2t(dcl.Type) 2656 case *ast.Field: 2657 return e2t(dcl.Type) 2658 case *ast.AssignStmt: // var lhs = rhs | lhs := rhs 2659 return getTypeOfExpr(dcl.Rhs[0]) 2660 default: 2661 panic("Unknown type") 2662 } 2663 case ast.Con: 2664 switch e.Obj { 2665 case gTrue, gFalse: 2666 return tBool 2667 default: 2668 switch decl2 := e.Obj.Decl.(type) { 2669 case *ast.ValueSpec: 2670 return e2t(decl2.Type) 2671 default: 2672 panic("cannot decide type of cont =" + e.Obj.Name) 2673 } 2674 } 2675 default: 2676 panic("Obj=" + e.Obj.Name + e.Obj.Kind.String()) 2677 } 2678 case *ast.BasicLit: 2679 // The default type of an untyped constant is bool, rune, int, float64, complex128 or string respectively, 2680 // depending on whether it is a boolean, rune, integer, floating-point, complex, or string constant. 2681 switch e.Kind.String() { 2682 case "STRING": 2683 return tString 2684 case "INT": 2685 return tInt 2686 case "CHAR": 2687 return tInt32 2688 default: 2689 panic(e.Kind.String()) 2690 } 2691 case *ast.UnaryExpr: 2692 switch e.Op.String() { 2693 case "+": 2694 return getTypeOfExpr(e.X) 2695 case "-": 2696 return getTypeOfExpr(e.X) 2697 case "!": 2698 return tBool 2699 case "&": 2700 t := getTypeOfExpr(e.X) 2701 starExpr := &ast.StarExpr{ 2702 X: t.E, 2703 } 2704 return e2t(starExpr) 2705 case "range": 2706 listType := getTypeOfExpr(e.X) 2707 elmType := getElementTypeOfCollectionType(listType) 2708 return elmType 2709 default: 2710 panic(e.Op.String()) 2711 } 2712 case *ast.BinaryExpr: 2713 switch e.Op.String() { 2714 case "==", "!=", "<", ">", "<=", ">=": 2715 return tBool 2716 default: 2717 return getTypeOfExpr(e.X) 2718 } 2719 case *ast.IndexExpr: 2720 list := e.X 2721 return getElementTypeOfCollectionType(getTypeOfExpr(list)) 2722 case *ast.CallExpr: // funcall or conversion 2723 types := getCallResultTypes(e) 2724 assert(len(types) == 1, "single value is expected", __func__) 2725 return types[0] 2726 case *ast.SliceExpr: 2727 underlyingCollectionType := getTypeOfExpr(e.X) 2728 if kind(underlyingCollectionType) == T_STRING { 2729 // str2 = str1[n:m] 2730 return tString 2731 } 2732 var elementTyp ast.Expr 2733 switch colType := underlyingCollectionType.E.(type) { 2734 case *ast.ArrayType: 2735 elementTyp = colType.Elt 2736 } 2737 r := &ast.ArrayType{ 2738 Len: nil, 2739 Elt: elementTyp, 2740 } 2741 return e2t(r) 2742 case *ast.StarExpr: 2743 t := getTypeOfExpr(e.X) 2744 ptrType := t.E.(*ast.StarExpr) 2745 return e2t(ptrType.X) 2746 case *ast.SelectorExpr: 2747 if isQI(e) { // pkg.SomeType 2748 ident := lookupForeignIdent(selector2QI(e)) 2749 return getTypeOfExpr(ident) 2750 } else { // (e).field 2751 ut := getUnderlyingType(getTypeOfExpr(e.X)) 2752 var structTypeLiteral *ast.StructType 2753 switch typ := ut.E.(type) { 2754 case *ast.StructType: // strct.field 2755 structTypeLiteral = typ 2756 case *ast.StarExpr: // ptr.field 2757 structType := e2t(typ.X) 2758 structTypeLiteral = getUnderlyingStructType(structType) 2759 } 2760 field := lookupStructField(structTypeLiteral, e.Sel.Name) 2761 return e2t(field.Type) 2762 } 2763 case *ast.CompositeLit: 2764 return e2t(e.Type) 2765 case *ast.ParenExpr: 2766 return getTypeOfExpr(e.X) 2767 case *ast.TypeAssertExpr: 2768 return e2t(e.Type) 2769 } 2770 panic("bad type\n") 2771 } 2772 2773 func fieldList2Types(fldlist *ast.FieldList) []*Type { 2774 var r []*Type 2775 for _, e2 := range fldlist.List { 2776 t := e2t(e2.Type) 2777 r = append(r, t) 2778 } 2779 return r 2780 } 2781 2782 func getCallResultTypes(e *ast.CallExpr) []*Type { 2783 switch fn := e.Fun.(type) { 2784 case *ast.Ident: 2785 if fn.Obj == nil { 2786 throw(fn) 2787 } 2788 switch fn.Obj.Kind { 2789 case ast.Typ: // conversion 2790 return []*Type{e2t(fn)} 2791 case ast.Fun: 2792 switch fn.Obj { 2793 case gLen, gCap: 2794 return []*Type{tInt} 2795 case gNew: 2796 starExpr := &ast.StarExpr{ 2797 X: e.Args[0], 2798 } 2799 return []*Type{e2t(starExpr)} 2800 case gMake: 2801 return []*Type{e2t(e.Args[0])} 2802 case gAppend: 2803 return []*Type{e2t(e.Args[0])} 2804 } 2805 decl := fn.Obj.Decl 2806 if decl == nil { 2807 panic("decl of function " + fn.Name + " should not nil") 2808 } 2809 switch dcl := decl.(type) { 2810 case *ast.FuncDecl: 2811 return fieldList2Types(dcl.Type.Results) 2812 default: 2813 throw(decl) 2814 } 2815 } 2816 case *ast.ParenExpr: // (X)(e) funcall or conversion 2817 if isType(fn.X) { 2818 return []*Type{e2t(fn.X)} 2819 } else { 2820 panic("TBI: what should we do ?") 2821 } 2822 case *ast.ArrayType: // conversion [n]T(e) or []T(e) 2823 return []*Type{e2t(fn)} 2824 case *ast.SelectorExpr: 2825 if isType(fn) { 2826 return []*Type{e2t(fn)} 2827 } 2828 if isQI(fn) { // pkg.Sel() 2829 ff := lookupForeignFunc(selector2QI(fn)) 2830 return fieldList2Types(ff.decl.Type.Results) 2831 } else { // obj.method() 2832 rcvType := getTypeOfExpr(fn.X) 2833 method := lookupMethod(rcvType, fn.Sel) 2834 return fieldList2Types(method.FuncType.Results) 2835 } 2836 case *ast.InterfaceType: 2837 return []*Type{tEface} 2838 } 2839 2840 throw(e) 2841 return nil 2842 } 2843 2844 func e2t(typeExpr ast.Expr) *Type { 2845 if typeExpr == nil { 2846 panic("nil is not allowed") 2847 } 2848 return &Type{ 2849 E: typeExpr, 2850 } 2851 } 2852 2853 func serializeType(t *Type) string { 2854 if t == nil { 2855 panic("nil type is not expected") 2856 } 2857 if t.E == generalSlice { 2858 panic("TBD: generalSlice") 2859 } 2860 2861 switch e := t.E.(type) { 2862 case *ast.Ident: 2863 if e.Obj == nil { 2864 panic("Unresolved identifier:" + e.Name) 2865 } 2866 if e.Obj.Kind == ast.Var { 2867 throw(e.Obj) 2868 } else if e.Obj.Kind == ast.Typ { 2869 switch e.Obj { 2870 case gUintptr: 2871 return "uintptr" 2872 case gInt: 2873 return "int" 2874 case gString: 2875 return "string" 2876 case gUint8: 2877 return "uint8" 2878 case gUint16: 2879 return "uint16" 2880 case gBool: 2881 return "bool" 2882 default: 2883 // named type 2884 decl := e.Obj.Decl 2885 typeSpec := decl.(*ast.TypeSpec) 2886 pkgName := typeSpec.Name.Obj.Data.(string) 2887 return pkgName + "." + typeSpec.Name.Name 2888 } 2889 } 2890 case *ast.StructType: 2891 return "struct" 2892 case *ast.ArrayType: 2893 if e.Len == nil { 2894 if e.Elt == nil { 2895 panic(e) 2896 } 2897 return "[]" + serializeType(e2t(e.Elt)) 2898 } else { 2899 return "[" + strconv.Itoa(evalInt(e.Len)) + "]" + serializeType(e2t(e.Elt)) 2900 } 2901 case *ast.StarExpr: 2902 return "*" + serializeType(e2t(e.X)) 2903 case *ast.Ellipsis: // x ...T 2904 panic("TBD: Ellipsis") 2905 case *ast.InterfaceType: 2906 return "interface" 2907 case *ast.MapType: 2908 return "map[" + serializeType(e2t(e.Key)) + "]" + serializeType(e2t(e.Value)) 2909 case *ast.SelectorExpr: 2910 qi := selector2QI(e) 2911 return string(qi) 2912 default: 2913 throw(t) 2914 } 2915 return "" 2916 } 2917 2918 func getUnderlyingStructType(t *Type) *ast.StructType { 2919 ut := getUnderlyingType(t) 2920 return ut.E.(*ast.StructType) 2921 } 2922 2923 func getUnderlyingType(t *Type) *Type { 2924 if t == nil { 2925 panic("nil type is not expected") 2926 } 2927 if t.E == generalSlice { 2928 return t 2929 } 2930 2931 switch e := t.E.(type) { 2932 case *ast.StructType, *ast.ArrayType, *ast.StarExpr, *ast.Ellipsis, *ast.MapType, *ast.InterfaceType: 2933 // type literal 2934 return t 2935 case *ast.Ident: 2936 assert(e.Obj.Kind == ast.Typ, "should be ast.Typ : "+e.Obj.Name, __func__) 2937 if isPredeclaredType(e.Obj) { 2938 return t 2939 } 2940 // defined type or alias 2941 typeSpec := e.Obj.Decl.(*ast.TypeSpec) 2942 // get RHS in its type definition recursively 2943 return getUnderlyingType(e2t(typeSpec.Type)) 2944 case *ast.SelectorExpr: 2945 ident := lookupForeignIdent(selector2QI(e)) 2946 return getUnderlyingType(e2t(ident)) 2947 case *ast.ParenExpr: 2948 return getUnderlyingType(e2t(e.X)) 2949 } 2950 panic("should not reach here") 2951 } 2952 2953 func kind(t *Type) TypeKind { 2954 if t == nil { 2955 panic("nil type is not expected") 2956 } 2957 2958 ut := getUnderlyingType(t) 2959 if ut.E == generalSlice { 2960 return T_SLICE 2961 } 2962 2963 switch e := ut.E.(type) { 2964 case *ast.Ident: 2965 assert(e.Obj.Kind == ast.Typ, "should be ast.Typ", __func__) 2966 switch e.Obj { 2967 case gUintptr: 2968 return T_UINTPTR 2969 case gInt: 2970 return T_INT 2971 case gInt32: 2972 return T_INT32 2973 case gString: 2974 return T_STRING 2975 case gUint8: 2976 return T_UINT8 2977 case gUint16: 2978 return T_UINT16 2979 case gBool: 2980 return T_BOOL 2981 default: 2982 panic("Unexpected type") 2983 } 2984 case *ast.StructType: 2985 return T_STRUCT 2986 case *ast.ArrayType: 2987 if e.Len == nil { 2988 return T_SLICE 2989 } else { 2990 return T_ARRAY 2991 } 2992 case *ast.StarExpr: 2993 return T_POINTER 2994 case *ast.Ellipsis: // x ...T 2995 return T_SLICE // @TODO is this right ? 2996 case *ast.MapType: 2997 return T_MAP 2998 case *ast.InterfaceType: 2999 return T_INTERFACE 3000 } 3001 panic("should not reach here") 3002 } 3003 3004 func isInterface(t *Type) bool { 3005 return kind(t) == T_INTERFACE 3006 } 3007 3008 func getElementTypeOfCollectionType(t *Type) *Type { 3009 ut := getUnderlyingType(t) 3010 switch kind(ut) { 3011 case T_SLICE, T_ARRAY: 3012 switch e := ut.E.(type) { 3013 case *ast.ArrayType: 3014 return e2t(e.Elt) 3015 case *ast.Ellipsis: 3016 return e2t(e.Elt) 3017 default: 3018 throw(t.E) 3019 } 3020 case T_STRING: 3021 return tUint8 3022 case T_MAP: 3023 mapType := ut.E.(*ast.MapType) 3024 return e2t(mapType.Value) 3025 default: 3026 unexpectedKind(kind(t)) 3027 } 3028 return nil 3029 } 3030 3031 func getKeyTypeOfCollectionType(t *Type) *Type { 3032 ut := getUnderlyingType(t) 3033 switch kind(ut) { 3034 case T_SLICE, T_ARRAY, T_STRING: 3035 return tInt 3036 case T_MAP: 3037 mapType := ut.E.(*ast.MapType) 3038 return e2t(mapType.Key) 3039 default: 3040 unexpectedKind(kind(t)) 3041 } 3042 return nil 3043 } 3044 3045 const SizeOfSlice int = 24 3046 const SizeOfString int = 16 3047 const SizeOfInt int = 8 3048 const SizeOfUint8 int = 1 3049 const SizeOfUint16 int = 2 3050 const SizeOfPtr int = 8 3051 const SizeOfInterface int = 16 3052 3053 func getSizeOfType(t *Type) int { 3054 ut := getUnderlyingType(t) 3055 switch kind(ut) { 3056 case T_SLICE: 3057 return SizeOfSlice 3058 case T_STRING: 3059 return SizeOfString 3060 case T_INT: 3061 return SizeOfInt 3062 case T_UINTPTR, T_POINTER, T_MAP: 3063 return SizeOfPtr 3064 case T_UINT8: 3065 return SizeOfUint8 3066 case T_UINT16: 3067 return SizeOfUint16 3068 case T_BOOL: 3069 return SizeOfInt 3070 case T_INTERFACE: 3071 return SizeOfInterface 3072 case T_ARRAY: 3073 arrayType := ut.E.(*ast.ArrayType) 3074 elmSize := getSizeOfType(e2t(arrayType.Elt)) 3075 return elmSize * evalInt(arrayType.Len) 3076 case T_STRUCT: 3077 return calcStructSizeAndSetFieldOffset(ut.E.(*ast.StructType)) 3078 default: 3079 unexpectedKind(kind(t)) 3080 } 3081 return 0 3082 } 3083 3084 func lookupStructField(structType *ast.StructType, selName string) *ast.Field { 3085 for _, field := range structType.Fields.List { 3086 if field.Names[0].Name == selName { 3087 return field 3088 } 3089 } 3090 panic("Unexpected flow: struct field not found:" + selName) 3091 } 3092 3093 func calcStructSizeAndSetFieldOffset(structType *ast.StructType) int { 3094 var offset int = 0 3095 for _, field := range structType.Fields.List { 3096 setStructFieldOffset(field, offset) 3097 size := getSizeOfType(e2t(field.Type)) 3098 offset += size 3099 } 3100 return offset 3101 } 3102 3103 // --- walk --- 3104 type sliteral struct { 3105 label string 3106 strlen int 3107 value string // raw value 3108 } 3109 3110 type stringLiteralsContainer struct { 3111 lit *ast.BasicLit 3112 sl *sliteral 3113 } 3114 3115 func registerParamVariable(fnc *Func, name string, t *Type) *Variable { 3116 vr := newLocalVariable(name, fnc.Argsarea, t) 3117 size := getSizeOfType(t) 3118 fnc.Argsarea += size 3119 fnc.Params = append(fnc.Params, vr) 3120 return vr 3121 } 3122 3123 func registerReturnVariable(fnc *Func, name string, t *Type) *Variable { 3124 vr := newLocalVariable(name, fnc.Argsarea, t) 3125 size := getSizeOfType(t) 3126 fnc.Argsarea += size 3127 fnc.Retvars = append(fnc.Retvars, vr) 3128 return vr 3129 } 3130 3131 func registerLocalVariable(fnc *Func, name string, t *Type) *Variable { 3132 assert(t != nil && t.E != nil, "type of local var should not be nil", __func__) 3133 fnc.Localarea -= getSizeOfType(t) 3134 vr := newLocalVariable(name, currentFunc.Localarea, t) 3135 fnc.LocalVars = append(fnc.LocalVars, vr) 3136 return vr 3137 } 3138 3139 var currentFor *MetaForStmt 3140 var currentFunc *Func 3141 3142 func getStringLiteral(lit *ast.BasicLit) *sliteral { 3143 for _, container := range currentPkg.stringLiterals { 3144 if container.lit == lit { 3145 return container.sl 3146 } 3147 } 3148 3149 panic("string literal not found:" + lit.Value) 3150 } 3151 3152 func registerStringLiteral(lit *ast.BasicLit) { 3153 if currentPkg.name == "" { 3154 panic("no pkgName") 3155 } 3156 3157 var strlen int 3158 for _, c := range []uint8(lit.Value) { 3159 if c != '\\' { 3160 strlen++ 3161 } 3162 } 3163 3164 label := fmt.Sprintf(".%s.S%d", currentPkg.name, currentPkg.stringIndex) 3165 currentPkg.stringIndex++ 3166 3167 sl := &sliteral{ 3168 label: label, 3169 strlen: strlen - 2, 3170 value: lit.Value, 3171 } 3172 cont := &stringLiteralsContainer{ 3173 sl: sl, 3174 lit: lit, 3175 } 3176 currentPkg.stringLiterals = append(currentPkg.stringLiterals, cont) 3177 } 3178 3179 func newGlobalVariable(pkgName string, name string, t *Type) *Variable { 3180 return &Variable{ 3181 Name: name, 3182 IsGlobal: true, 3183 GlobalSymbol: pkgName + "." + name, 3184 Typ: t, 3185 } 3186 } 3187 3188 func newLocalVariable(name string, localoffset int, t *Type) *Variable { 3189 return &Variable{ 3190 Name: name, 3191 IsGlobal: false, 3192 LocalOffset: localoffset, 3193 Typ: t, 3194 } 3195 } 3196 3197 type QualifiedIdent string 3198 3199 func newQI(pkg string, ident string) QualifiedIdent { 3200 return QualifiedIdent(pkg + "." + ident) 3201 } 3202 3203 func isQI(e *ast.SelectorExpr) bool { 3204 ident, isIdent := e.X.(*ast.Ident) 3205 if !isIdent { 3206 return false 3207 } 3208 return ident.Obj.Kind == ast.Pkg 3209 } 3210 3211 func selector2QI(e *ast.SelectorExpr) QualifiedIdent { 3212 pkgName := e.X.(*ast.Ident) 3213 assert(pkgName.Obj.Kind == ast.Pkg, "should be ast.Pkg", __func__) 3214 return newQI(pkgName.Name, e.Sel.Name) 3215 } 3216 3217 func newMethod(pkgName string, funcDecl *ast.FuncDecl) *Method { 3218 rcvType := funcDecl.Recv.List[0].Type 3219 rcvPointerType, isPtr := rcvType.(*ast.StarExpr) 3220 if isPtr { 3221 rcvType = rcvPointerType.X 3222 } 3223 rcvNamedType := rcvType.(*ast.Ident) 3224 method := &Method{ 3225 PkgName: pkgName, 3226 RcvNamedType: rcvNamedType, 3227 IsPtrMethod: isPtr, 3228 Name: funcDecl.Name.Name, 3229 FuncType: funcDecl.Type, 3230 } 3231 return method 3232 } 3233 3234 // https://golang.org/ref/spec#Method_sets 3235 // @TODO map key should be a QI ? 3236 var MethodSets = make(map[unsafe.Pointer]*NamedType) 3237 3238 type NamedType struct { 3239 methodSet map[string]*Method 3240 } 3241 3242 func registerMethod(method *Method) { 3243 key := unsafe.Pointer(method.RcvNamedType.Obj) 3244 namedType, ok := MethodSets[key] 3245 if !ok { 3246 namedType = &NamedType{ 3247 methodSet: make(map[string]*Method), 3248 } 3249 MethodSets[key] = namedType 3250 } 3251 namedType.methodSet[method.Name] = method 3252 } 3253 3254 func lookupMethod(rcvT *Type, methodName *ast.Ident) *Method { 3255 rcvType := rcvT.E 3256 rcvPointerType, isPtr := rcvType.(*ast.StarExpr) 3257 if isPtr { 3258 rcvType = rcvPointerType.X 3259 } 3260 var typeObj *ast.Object 3261 switch typ := rcvType.(type) { 3262 case *ast.Ident: 3263 typeObj = typ.Obj 3264 case *ast.SelectorExpr: 3265 t := lookupForeignIdent(selector2QI(typ)) 3266 typeObj = t.Obj 3267 default: 3268 panic(rcvType) 3269 } 3270 3271 namedType, ok := MethodSets[unsafe.Pointer(typeObj)] 3272 if !ok { 3273 panic(typeObj.Name + " has no methodSet") 3274 } 3275 method, ok := namedType.methodSet[methodName.Name] 3276 if !ok { 3277 panic("method not found") 3278 } 3279 return method 3280 } 3281 3282 func walkExprStmt(s *ast.ExprStmt) { 3283 walkExpr(s.X) 3284 } 3285 func walkDeclStmt(s *ast.DeclStmt) { 3286 genDecl := s.Decl.(*ast.GenDecl) 3287 declSpec := genDecl.Specs[0] 3288 switch spec := declSpec.(type) { 3289 case *ast.ValueSpec: 3290 if spec.Type == nil { // var x = e 3291 if len(spec.Values) == 0 { 3292 panic("invalid syntax") 3293 } 3294 // infer type from rhs 3295 val := spec.Values[0] 3296 logf("inferring type of variable %s\n", spec.Names[0].Name) 3297 typ := getTypeOfExpr(val) 3298 if typ == nil || typ.E == nil { 3299 panic("rhs should have a type") 3300 } 3301 spec.Type = typ.E 3302 } 3303 t := e2t(spec.Type) 3304 obj := spec.Names[0].Obj 3305 setVariable(obj, registerLocalVariable(currentFunc, obj.Name, t)) 3306 for _, v := range spec.Values { 3307 walkExpr(v) 3308 } 3309 } 3310 } 3311 func walkAssignStmt(s *ast.AssignStmt) { 3312 walkExpr(s.Lhs[0]) 3313 if s.Tok.String() == ":=" { 3314 rhs0 := s.Rhs[0] 3315 walkExpr(rhs0) 3316 var isMultiValuedContext bool 3317 if len(s.Lhs) > 1 && len(s.Rhs) == 1 { 3318 isMultiValuedContext = true 3319 } 3320 3321 if isMultiValuedContext { 3322 // a, b, c := rhs0 3323 // infer type 3324 var types []*Type 3325 switch rhs := rhs0.(type) { 3326 case *ast.CallExpr: 3327 types = getCallResultTypes(rhs) 3328 case *ast.TypeAssertExpr: // v, ok := x.(T) 3329 typ0 := getTypeOfExpr(rhs0) 3330 types = []*Type{typ0, tBool} 3331 case *ast.IndexExpr: // v, ok := m[k] 3332 typ0 := getTypeOfExpr(rhs0) 3333 types = []*Type{typ0, tBool} 3334 default: 3335 throw(rhs0) 3336 } 3337 for i, lhs := range s.Lhs { 3338 obj := lhs.(*ast.Ident).Obj 3339 setVariable(obj, registerLocalVariable(currentFunc, obj.Name, types[i])) 3340 } 3341 } else { 3342 for i, lhs := range s.Lhs { 3343 obj := lhs.(*ast.Ident).Obj 3344 rhs := s.Rhs[i] 3345 walkExpr(rhs) 3346 rhsType := getTypeOfExpr(s.Rhs[i]) 3347 setVariable(obj, registerLocalVariable(currentFunc, obj.Name, rhsType)) 3348 } 3349 } 3350 } else { 3351 for _, rhs := range s.Rhs { 3352 walkExpr(rhs) 3353 } 3354 } 3355 } 3356 3357 func walkReturnStmt(s *ast.ReturnStmt) { 3358 setMetaReturnStmt(s, &MetaReturnStmt{ 3359 Fnc: currentFunc, 3360 }) 3361 for _, r := range s.Results { 3362 walkExpr(r) 3363 } 3364 } 3365 func walkIfStmt(s *ast.IfStmt) { 3366 if s.Init != nil { 3367 walkStmt(s.Init) 3368 } 3369 walkExpr(s.Cond) 3370 walkStmt(s.Body) 3371 if s.Else != nil { 3372 walkStmt(s.Else) 3373 } 3374 } 3375 func walkBlockStmt(s *ast.BlockStmt) { 3376 for _, stmt := range s.List { 3377 walkStmt(stmt) 3378 } 3379 } 3380 3381 func walkForStmt(s *ast.ForStmt) { 3382 meta := &MetaForStmt{ 3383 Outer: currentFor, 3384 } 3385 currentFor = meta 3386 setMetaForStmt(s, meta) 3387 if s.Init != nil { 3388 walkStmt(s.Init) 3389 } 3390 if s.Cond != nil { 3391 walkExpr(s.Cond) 3392 } 3393 if s.Post != nil { 3394 walkStmt(s.Post) 3395 } 3396 walkStmt(s.Body) 3397 currentFor = meta.Outer 3398 } 3399 func walkRangeStmt(s *ast.RangeStmt) { 3400 meta := &MetaForStmt{ 3401 Outer: currentFor, 3402 } 3403 currentFor = meta 3404 setMetaForStmt(s, meta) 3405 walkExpr(s.X) 3406 walkStmt(s.Body) 3407 3408 collectionType := getUnderlyingType(getTypeOfExpr(s.X)) 3409 keyType := getKeyTypeOfCollectionType(collectionType) 3410 elmType := getElementTypeOfCollectionType(collectionType) 3411 switch kind(collectionType) { 3412 case T_SLICE, T_ARRAY: 3413 meta.ForRange = &MetaForRange{ 3414 IsMap: false, 3415 LenVar: registerLocalVariable(currentFunc, ".range.len", tInt), 3416 Indexvar: registerLocalVariable(currentFunc, ".range.index", tInt), 3417 } 3418 case T_MAP: 3419 meta.ForRange = &MetaForRange{ 3420 IsMap: true, 3421 MapVar: registerLocalVariable(currentFunc, ".range.map", tUintptr), 3422 ItemVar: registerLocalVariable(currentFunc, ".range.item", tUintptr), 3423 } 3424 default: 3425 throw(collectionType) 3426 } 3427 if s.Tok.String() == ":=" { 3428 // declare local variables 3429 keyIdent := s.Key.(*ast.Ident) 3430 setVariable(keyIdent.Obj, registerLocalVariable(currentFunc, keyIdent.Name, keyType)) 3431 3432 valueIdent := s.Value.(*ast.Ident) 3433 setVariable(valueIdent.Obj, registerLocalVariable(currentFunc, valueIdent.Name, elmType)) 3434 } 3435 currentFor = meta.Outer 3436 } 3437 func walkIncDecStmt(s *ast.IncDecStmt) { 3438 walkExpr(s.X) 3439 } 3440 func walkSwitchStmt(s *ast.SwitchStmt) { 3441 if s.Init != nil { 3442 walkStmt(s.Init) 3443 } 3444 if s.Tag != nil { 3445 walkExpr(s.Tag) 3446 } 3447 walkStmt(s.Body) 3448 } 3449 func walkTypeSwitchStmt(s *ast.TypeSwitchStmt) { 3450 typeSwitch := &MetaTypeSwitchStmt{} 3451 setMetaTypeSwitchStmt(s, typeSwitch) 3452 var assignIdent *ast.Ident 3453 switch assign := s.Assign.(type) { 3454 case *ast.ExprStmt: 3455 typeAssertExpr := assign.X.(*ast.TypeAssertExpr) 3456 typeSwitch.Subject = typeAssertExpr.X 3457 walkExpr(typeAssertExpr.X) 3458 case *ast.AssignStmt: 3459 lhs := assign.Lhs[0] 3460 assignIdent = lhs.(*ast.Ident) 3461 typeSwitch.AssignIdent = assignIdent 3462 // ident will be a new local variable in each case clause 3463 typeAssertExpr := assign.Rhs[0].(*ast.TypeAssertExpr) 3464 typeSwitch.Subject = typeAssertExpr.X 3465 walkExpr(typeAssertExpr.X) 3466 default: 3467 throw(s.Assign) 3468 } 3469 3470 typeSwitch.SubjectVariable = registerLocalVariable(currentFunc, ".switch_expr", tEface) 3471 for _, _case := range s.Body.List { 3472 cc := _case.(*ast.CaseClause) 3473 tscc := &MetaTypeSwitchCaseClose{ 3474 Orig: cc, 3475 } 3476 typeSwitch.Cases = append(typeSwitch.Cases, tscc) 3477 if assignIdent != nil && len(cc.List) > 0 { 3478 var varType *Type 3479 if isNil(cc.List[0]) { 3480 varType = getTypeOfExpr(typeSwitch.Subject) 3481 } else { 3482 varType = e2t(cc.List[0]) 3483 } 3484 // inject a variable of that type 3485 vr := registerLocalVariable(currentFunc, assignIdent.Name, varType) 3486 tscc.Variable = vr 3487 tscc.VariableType = varType 3488 setVariable(assignIdent.Obj, vr) 3489 } 3490 3491 for _, stmt := range cc.Body { 3492 walkStmt(stmt) 3493 } 3494 if assignIdent != nil { 3495 setVariable(assignIdent.Obj, nil) 3496 } 3497 } 3498 } 3499 func isNil(e ast.Expr) bool { 3500 ident, ok := e.(*ast.Ident) 3501 if !ok { 3502 return false 3503 } 3504 return ident.Obj == gNil 3505 } 3506 3507 func walkCaseClause(s *ast.CaseClause) { 3508 for _, e := range s.List { 3509 walkExpr(e) 3510 } 3511 for _, stmt := range s.Body { 3512 walkStmt(stmt) 3513 } 3514 } 3515 func walkBranchStmt(s *ast.BranchStmt) { 3516 assert(currentFor != nil, "break or continue should be in for body", __func__) 3517 setMetaBranchStmt(s, &MetaBranchStmt{ 3518 containerForStmt: currentFor, 3519 }) 3520 } 3521 3522 func walkStmt(stmt ast.Stmt) { 3523 switch s := stmt.(type) { 3524 case *ast.ExprStmt: 3525 walkExprStmt(s) 3526 case *ast.DeclStmt: 3527 walkDeclStmt(s) 3528 case *ast.AssignStmt: 3529 walkAssignStmt(s) 3530 case *ast.ReturnStmt: 3531 walkReturnStmt(s) 3532 case *ast.IfStmt: 3533 walkIfStmt(s) 3534 case *ast.BlockStmt: 3535 walkBlockStmt(s) 3536 case *ast.ForStmt: 3537 walkForStmt(s) 3538 case *ast.RangeStmt: 3539 walkRangeStmt(s) 3540 case *ast.IncDecStmt: 3541 walkIncDecStmt(s) 3542 case *ast.SwitchStmt: 3543 walkSwitchStmt(s) 3544 case *ast.TypeSwitchStmt: 3545 walkTypeSwitchStmt(s) 3546 case *ast.CaseClause: 3547 walkCaseClause(s) 3548 case *ast.BranchStmt: 3549 walkBranchStmt(s) 3550 default: 3551 throw(stmt) 3552 } 3553 } 3554 3555 func walkIdent(e *ast.Ident) { 3556 // what to do ? 3557 } 3558 func walkSelectorExpr(e *ast.SelectorExpr) { 3559 walkExpr(e.X) 3560 } 3561 func walkCallExpr(e *ast.CallExpr) { 3562 walkExpr(e.Fun) 3563 // Replace __func__ ident by a string literal 3564 for i, arg := range e.Args { 3565 ident, ok := arg.(*ast.Ident) 3566 if ok { 3567 if ident.Name == "__func__" && ident.Obj.Kind == ast.Var { 3568 basicLit := &ast.BasicLit{ 3569 Kind: token.STRING, 3570 Value: "\"" + currentFunc.Name + "\"", 3571 } 3572 arg = basicLit 3573 e.Args[i] = arg 3574 } 3575 } 3576 walkExpr(arg) 3577 } 3578 } 3579 func walkParenExpr(e *ast.ParenExpr) { 3580 walkExpr(e.X) 3581 } 3582 func walkBasicLit(e *ast.BasicLit) { 3583 switch e.Kind.String() { 3584 case "INT": 3585 case "CHAR": 3586 case "STRING": 3587 registerStringLiteral(e) 3588 default: 3589 panic("Unexpected literal kind:" + e.Kind.String()) 3590 } 3591 } 3592 func walkCompositeLit(e *ast.CompositeLit) { 3593 for _, v := range e.Elts { 3594 walkExpr(v) 3595 } 3596 } 3597 func walkUnaryExpr(e *ast.UnaryExpr) { 3598 walkExpr(e.X) 3599 } 3600 func walkBinaryExpr(e *ast.BinaryExpr) { 3601 walkExpr(e.X) // left 3602 walkExpr(e.Y) // right 3603 } 3604 func walkIndexExpr(e *ast.IndexExpr) { 3605 walkExpr(e.Index) 3606 walkExpr(e.X) 3607 } 3608 func walkSliceExpr(e *ast.SliceExpr) { 3609 if e.Low != nil { 3610 walkExpr(e.Low) 3611 } 3612 if e.High != nil { 3613 walkExpr(e.High) 3614 } 3615 if e.Max != nil { 3616 walkExpr(e.Max) 3617 } 3618 walkExpr(e.X) 3619 } 3620 3621 // []T(e) 3622 func walkArrayType(e *ast.ArrayType) { 3623 // first argument of builtin func 3624 // do nothing 3625 } 3626 func walkMapType(e *ast.MapType) { 3627 // first argument of builtin func 3628 // do nothing 3629 } 3630 func walkStarExpr(e *ast.StarExpr) { 3631 walkExpr(e.X) 3632 } 3633 func walkKeyValueExpr(e *ast.KeyValueExpr) { 3634 walkExpr(e.Key) 3635 walkExpr(e.Value) 3636 } 3637 func walkInterfaceType(e *ast.InterfaceType) { 3638 // interface{}(e) conversion. Nothing to do. 3639 } 3640 func walkTypeAssertExpr(e *ast.TypeAssertExpr) { 3641 walkExpr(e.X) 3642 } 3643 func walkExpr(expr ast.Expr) { 3644 switch e := expr.(type) { 3645 case *ast.Ident: 3646 walkIdent(e) 3647 case *ast.SelectorExpr: 3648 walkSelectorExpr(e) 3649 case *ast.CallExpr: 3650 walkCallExpr(e) 3651 case *ast.ParenExpr: 3652 walkParenExpr(e) 3653 case *ast.BasicLit: 3654 walkBasicLit(e) 3655 case *ast.CompositeLit: 3656 walkCompositeLit(e) 3657 case *ast.UnaryExpr: 3658 walkUnaryExpr(e) 3659 case *ast.BinaryExpr: 3660 walkBinaryExpr(e) 3661 case *ast.IndexExpr: 3662 walkIndexExpr(e) 3663 case *ast.ArrayType: 3664 walkArrayType(e) // []T(e) 3665 case *ast.MapType: 3666 walkMapType(e) 3667 case *ast.SliceExpr: 3668 walkSliceExpr(e) 3669 case *ast.StarExpr: 3670 walkStarExpr(e) 3671 case *ast.KeyValueExpr: 3672 walkKeyValueExpr(e) 3673 case *ast.InterfaceType: 3674 walkInterfaceType(e) 3675 case *ast.TypeAssertExpr: 3676 walkTypeAssertExpr(e) 3677 default: 3678 throw(expr) 3679 } 3680 } 3681 3682 var ExportedQualifiedIdents = make(map[string]*ast.Ident) 3683 3684 func lookupForeignIdent(qi QualifiedIdent) *ast.Ident { 3685 ident, ok := ExportedQualifiedIdents[string(qi)] 3686 if !ok { 3687 panic(qi + " Not found in ExportedQualifiedIdents") 3688 } 3689 return ident 3690 } 3691 3692 type ForeignFunc struct { 3693 symbol string 3694 decl *ast.FuncDecl 3695 } 3696 3697 func lookupForeignFunc(qi QualifiedIdent) *ForeignFunc { 3698 ident := lookupForeignIdent(qi) 3699 assert(ident.Obj.Kind == ast.Fun, "should be Fun", __func__) 3700 decl := ident.Obj.Decl.(*ast.FuncDecl) 3701 return &ForeignFunc{ 3702 symbol: string(qi), 3703 decl: decl, 3704 } 3705 } 3706 3707 // Purpose of walk: 3708 // Global: 3709 // - collect methods 3710 // - collect string literals 3711 // - collect global variables 3712 // - determine struct size and field offset 3713 // Local: 3714 // - collect string literals 3715 // - collect local variables and set offset 3716 // - determine types of variable declarations 3717 func walk(pkg *PkgContainer) { 3718 var typeSpecs []*ast.TypeSpec 3719 var funcDecls []*ast.FuncDecl 3720 var varSpecs []*ast.ValueSpec 3721 var constSpecs []*ast.ValueSpec 3722 3723 // grouping declarations by type 3724 for _, decl := range pkg.Decls { 3725 switch dcl := decl.(type) { 3726 case *ast.GenDecl: 3727 specInterface := dcl.Specs[0] 3728 switch spec := specInterface.(type) { 3729 case *ast.TypeSpec: 3730 typeSpecs = append(typeSpecs, spec) 3731 case *ast.ValueSpec: 3732 nameIdent := spec.Names[0] 3733 switch nameIdent.Obj.Kind { 3734 case ast.Var: 3735 varSpecs = append(varSpecs, spec) 3736 case ast.Con: 3737 constSpecs = append(constSpecs, spec) 3738 default: 3739 panic("Unexpected") 3740 } 3741 } 3742 case *ast.FuncDecl: 3743 funcDecls = append(funcDecls, dcl) 3744 default: 3745 panic("Unexpected") 3746 } 3747 } 3748 3749 for _, typeSpec := range typeSpecs { 3750 typeSpec.Name.Obj.Data = pkg.name // package to which the type belongs to 3751 t := e2t(typeSpec.Type) 3752 switch kind(t) { 3753 case T_STRUCT: 3754 structType := getUnderlyingType(t) 3755 calcStructSizeAndSetFieldOffset(structType.E.(*ast.StructType)) 3756 } 3757 ExportedQualifiedIdents[string(newQI(pkg.name, typeSpec.Name.Name))] = typeSpec.Name 3758 } 3759 3760 // collect methods in advance 3761 for _, funcDecl := range funcDecls { 3762 if funcDecl.Recv == nil { // non-method function 3763 qi := newQI(pkg.name, funcDecl.Name.Name) 3764 ExportedQualifiedIdents[string(qi)] = funcDecl.Name 3765 } else { // is method 3766 if funcDecl.Body != nil { 3767 method := newMethod(pkg.name, funcDecl) 3768 registerMethod(method) 3769 } 3770 } 3771 } 3772 3773 for _, constSpec := range constSpecs { 3774 for _, v := range constSpec.Values { 3775 walkExpr(v) 3776 } 3777 } 3778 3779 for _, varSpec := range varSpecs { 3780 nameIdent := varSpec.Names[0] 3781 assert(nameIdent.Obj.Kind == ast.Var, "should be Var", __func__) 3782 if varSpec.Type == nil { 3783 // Infer type 3784 val := varSpec.Values[0] 3785 t := getTypeOfExpr(val) 3786 if t == nil { 3787 panic("variable type is not determined : " + nameIdent.Name) 3788 } 3789 varSpec.Type = t.E 3790 } 3791 variable := newGlobalVariable(pkg.name, nameIdent.Obj.Name, e2t(varSpec.Type)) 3792 setVariable(nameIdent.Obj, variable) 3793 pkg.vars = append(pkg.vars, varSpec) 3794 ExportedQualifiedIdents[string(newQI(pkg.name, nameIdent.Name))] = nameIdent 3795 for _, v := range varSpec.Values { 3796 // mainly to collect string literals 3797 walkExpr(v) 3798 } 3799 } 3800 3801 for _, funcDecl := range funcDecls { 3802 fnc := &Func{ 3803 Name: funcDecl.Name.Name, 3804 FuncType: funcDecl.Type, 3805 Localarea: 0, 3806 Argsarea: 16, // return address + previous rbp 3807 } 3808 currentFunc = fnc 3809 logf("funcdef %s\n", funcDecl.Name.Name) 3810 3811 var paramFields []*ast.Field 3812 var resultFields []*ast.Field 3813 3814 if funcDecl.Recv != nil { // Method 3815 paramFields = append(paramFields, funcDecl.Recv.List[0]) 3816 } 3817 for _, field := range funcDecl.Type.Params.List { 3818 paramFields = append(paramFields, field) 3819 } 3820 3821 if funcDecl.Type.Results != nil { 3822 for _, field := range funcDecl.Type.Results.List { 3823 resultFields = append(resultFields, field) 3824 } 3825 } 3826 3827 for _, field := range paramFields { 3828 obj := field.Names[0].Obj 3829 setVariable(obj, registerParamVariable(fnc, obj.Name, e2t(field.Type))) 3830 } 3831 3832 for i, field := range resultFields { 3833 if len(field.Names) == 0 { 3834 // unnamed retval 3835 registerReturnVariable(fnc, ".r"+strconv.Itoa(i), e2t(field.Type)) 3836 } else { 3837 panic("TBI: named return variable is not supported") 3838 } 3839 } 3840 3841 if funcDecl.Body != nil { 3842 fnc.Stmts = funcDecl.Body.List 3843 for _, stmt := range fnc.Stmts { 3844 walkStmt(stmt) 3845 } 3846 3847 if funcDecl.Recv != nil { // is Method 3848 fnc.Method = newMethod(pkg.name, funcDecl) 3849 } 3850 pkg.funcs = append(pkg.funcs, fnc) 3851 } 3852 } 3853 } 3854 3855 // --- universe --- 3856 var gNil = &ast.Object{ 3857 Kind: ast.Con, // is nil a constant ? 3858 Name: "nil", 3859 } 3860 3861 var eNil = &ast.Ident{ 3862 Obj: gNil, 3863 Name: "nil", 3864 } 3865 3866 var eZeroInt = &ast.BasicLit{ 3867 Value: "0", 3868 Kind: token.INT, 3869 } 3870 3871 var gTrue = &ast.Object{ 3872 Kind: ast.Con, 3873 Name: "true", 3874 } 3875 var gFalse = &ast.Object{ 3876 Kind: ast.Con, 3877 Name: "false", 3878 } 3879 3880 var gString = &ast.Object{ 3881 Kind: ast.Typ, 3882 Name: "string", 3883 } 3884 3885 var gUintptr = &ast.Object{ 3886 Kind: ast.Typ, 3887 Name: "uintptr", 3888 } 3889 var gBool = &ast.Object{ 3890 Kind: ast.Typ, 3891 Name: "bool", 3892 } 3893 var gInt = &ast.Object{ 3894 Kind: ast.Typ, 3895 Name: "int", 3896 } 3897 3898 var gInt32 = &ast.Object{ 3899 Kind: ast.Typ, 3900 Name: "int32", 3901 } 3902 3903 var gUint8 = &ast.Object{ 3904 Kind: ast.Typ, 3905 Name: "uint8", 3906 } 3907 3908 var gUint16 = &ast.Object{ 3909 Kind: ast.Typ, 3910 Name: "uint16", 3911 } 3912 3913 var gNew = &ast.Object{ 3914 Kind: ast.Fun, 3915 Name: "new", 3916 } 3917 3918 var gMake = &ast.Object{ 3919 Kind: ast.Fun, 3920 Name: "make", 3921 } 3922 var gAppend = &ast.Object{ 3923 Kind: ast.Fun, 3924 Name: "append", 3925 } 3926 3927 var gLen = &ast.Object{ 3928 Kind: ast.Fun, 3929 Name: "len", 3930 } 3931 3932 var gCap = &ast.Object{ 3933 Kind: ast.Fun, 3934 Name: "cap", 3935 } 3936 var gPanic = &ast.Object{ 3937 Kind: ast.Fun, 3938 Name: "panic", 3939 } 3940 var gDelete = &ast.Object{ 3941 Kind: ast.Fun, 3942 Name: "delete", 3943 } 3944 3945 var tBool *Type = &Type{ 3946 E: &ast.Ident{ 3947 Name: "bool", 3948 Obj: gBool, 3949 }, 3950 } 3951 3952 var tInt *Type = &Type{ 3953 E: &ast.Ident{ 3954 Name: "int", 3955 Obj: gInt, 3956 }, 3957 } 3958 3959 // Rune 3960 var tInt32 *Type = &Type{ 3961 E: &ast.Ident{ 3962 Name: "int32", 3963 Obj: gInt32, 3964 }, 3965 } 3966 3967 var tUintptr *Type = &Type{ 3968 E: &ast.Ident{ 3969 Name: "uintptr", 3970 Obj: gUintptr, 3971 }, 3972 } 3973 var tUint8 *Type = &Type{ 3974 E: &ast.Ident{ 3975 Name: "uint8", 3976 Obj: gUint8, 3977 }, 3978 } 3979 3980 var tUint16 *Type = &Type{ 3981 E: &ast.Ident{ 3982 Name: "uint16", 3983 Obj: gUint16, 3984 }, 3985 } 3986 var tString *Type = &Type{ 3987 E: &ast.Ident{ 3988 Name: "string", 3989 Obj: gString, 3990 }, 3991 } 3992 3993 var tEface *Type = &Type{ 3994 E: &ast.InterfaceType{}, 3995 } 3996 3997 var generalSlice ast.Expr = &ast.Ident{} 3998 3999 func isPredeclaredType(obj *ast.Object) bool { 4000 switch obj { 4001 case gUintptr, gInt, gInt32, gString, gUint8, gUint16, gBool: 4002 return true 4003 } 4004 return false 4005 } 4006 4007 func createUniverse() *ast.Scope { 4008 universe := ast.NewScope(nil) 4009 objects := []*ast.Object{ 4010 gNil, 4011 // constants 4012 gTrue, gFalse, 4013 // types 4014 gString, gUintptr, gBool, gInt, gUint8, gUint16, 4015 // funcs 4016 gNew, gMake, gAppend, gLen, gCap, gPanic, gDelete, 4017 } 4018 for _, obj := range objects { 4019 universe.Insert(obj) 4020 } 4021 4022 // setting aliases 4023 universe.Objects["byte"] = gUint8 4024 4025 return universe 4026 } 4027 4028 // --- builder --- 4029 var currentPkg *PkgContainer 4030 4031 type PkgContainer struct { 4032 path string 4033 name string 4034 files []string 4035 astFiles []*ast.File 4036 vars []*ast.ValueSpec 4037 funcs []*Func 4038 stringLiterals []*stringLiteralsContainer 4039 stringIndex int 4040 Decls []ast.Decl 4041 } 4042 4043 func resolveImports(file *ast.File) { 4044 mapImports := make(map[string]bool) 4045 for _, imprt := range file.Imports { 4046 // unwrap double quote "..." 4047 rawValue := imprt.Path.Value 4048 pth := rawValue[1 : len(rawValue)-1] 4049 base := path.Base(pth) 4050 mapImports[base] = true 4051 } 4052 for _, ident := range file.Unresolved { 4053 // lookup imported package name 4054 _, ok := mapImports[ident.Name] 4055 if ok { 4056 ident.Obj = &ast.Object{ 4057 Kind: ast.Pkg, 4058 Name: ident.Name, 4059 } 4060 logf("# resolved: %s\n", ident.Name) 4061 } 4062 } 4063 } 4064 4065 // "some/dir" => []string{"a.go", "b.go"} 4066 func findFilesInDir(dir string) []string { 4067 dirents := mylib.GetDirents(dir) 4068 var r []string 4069 for _, dirent := range dirents { 4070 if dirent == "." || dirent == ".." { 4071 continue 4072 } 4073 if dirent == "_.s" { 4074 continue 4075 } 4076 if strings.HasSuffix(dirent, ".go") || strings.HasSuffix(dirent, ".s") { 4077 r = append(r, dirent) 4078 } 4079 } 4080 return r 4081 } 4082 4083 func isStdLib(pth string) bool { 4084 return !strings.Contains(pth, "/") 4085 } 4086 4087 func getImportPathsFromFile(file string) []string { 4088 fset := &token.FileSet{} 4089 astFile0 := parseImports(fset, file) 4090 var paths []string 4091 for _, importSpec := range astFile0.Imports { 4092 rawValue := importSpec.Path.Value 4093 logf("import %s\n", rawValue) 4094 pth := rawValue[1 : len(rawValue)-1] 4095 paths = append(paths, pth) 4096 } 4097 return paths 4098 } 4099 4100 func removeNode(tree DependencyTree, node string) { 4101 for _, paths := range tree { 4102 delete(paths, node) 4103 } 4104 4105 delete(tree, node) 4106 } 4107 4108 func getKeys(tree DependencyTree) []string { 4109 var keys []string 4110 for k, _ := range tree { 4111 keys = append(keys, k) 4112 } 4113 return keys 4114 } 4115 4116 type DependencyTree map[string]map[string]bool 4117 4118 // Do topological sort 4119 // In the result list, the independent (lowest level) packages come first. 4120 func sortTopologically(tree DependencyTree) []string { 4121 var sorted []string 4122 for len(tree) > 0 { 4123 keys := getKeys(tree) 4124 mylib.SortStrings(keys) 4125 for _, _path := range keys { 4126 children, ok := tree[_path] 4127 if !ok { 4128 panic("not found in tree") 4129 } 4130 if len(children) == 0 { 4131 // collect leaf node 4132 sorted = append(sorted, _path) 4133 removeNode(tree, _path) 4134 } 4135 } 4136 } 4137 return sorted 4138 } 4139 4140 func getPackageDir(importPath string) string { 4141 if isStdLib(importPath) { 4142 return prjSrcPath + "/" + importPath 4143 } else { 4144 return srcPath + "/" + importPath 4145 } 4146 } 4147 4148 func collectDependency(tree DependencyTree, paths map[string]bool) { 4149 for pkgPath, _ := range paths { 4150 if pkgPath == "unsafe" || pkgPath == "runtime" { 4151 continue 4152 } 4153 packageDir := getPackageDir(pkgPath) 4154 fnames := findFilesInDir(packageDir) 4155 children := make(map[string]bool) 4156 for _, fname := range fnames { 4157 _paths := getImportPathsFromFile(packageDir + "/" + fname) 4158 for _, pth := range _paths { 4159 if pth == "unsafe" || pth == "runtime" { 4160 continue 4161 } 4162 children[pth] = true 4163 } 4164 } 4165 tree[pkgPath] = children 4166 collectDependency(tree, children) 4167 } 4168 } 4169 4170 var srcPath string 4171 var prjSrcPath string 4172 4173 func collectAllPackages(inputFiles []string) []string { 4174 directChildren := collectDirectDependents(inputFiles) 4175 tree := make(DependencyTree) 4176 collectDependency(tree, directChildren) 4177 sortedPaths := sortTopologically(tree) 4178 4179 // sort packages by this order 4180 // 1: pseudo 4181 // 2: stdlib 4182 // 3: external 4183 paths := []string{"unsafe", "runtime"} 4184 for _, pth := range sortedPaths { 4185 if isStdLib(pth) { 4186 paths = append(paths, pth) 4187 } 4188 } 4189 for _, pth := range sortedPaths { 4190 if !isStdLib(pth) { 4191 paths = append(paths, pth) 4192 } 4193 } 4194 return paths 4195 } 4196 4197 func collectDirectDependents(inputFiles []string) map[string]bool { 4198 importPaths := make(map[string]bool) 4199 for _, inputFile := range inputFiles { 4200 logf("input file: \"%s\"\n", inputFile) 4201 logf("Parsing imports\n") 4202 paths := getImportPathsFromFile(inputFile) 4203 for _, pth := range paths { 4204 importPaths[pth] = true 4205 } 4206 } 4207 return importPaths 4208 } 4209 4210 func collectSourceFiles(pkgDir string) []string { 4211 fnames := findFilesInDir(pkgDir) 4212 var files []string 4213 for _, fname := range fnames { 4214 logf("fname: %s\n", fname) 4215 srcFile := pkgDir + "/" + fname 4216 files = append(files, srcFile) 4217 } 4218 return files 4219 } 4220 4221 func parseImports(fset *token.FileSet, filename string) *ast.File { 4222 f, err := parserParseFile(fset, filename, nil, parserImportsOnly) 4223 if err != nil { 4224 panic(filename + ":" + err.Error()) 4225 } 4226 return f 4227 } 4228 4229 func parseFile(fset *token.FileSet, filename string) *ast.File { 4230 f, err := parserParseFile(fset, filename, nil, 0) 4231 if err != nil { 4232 panic(err.Error()) 4233 } 4234 return f 4235 } 4236 4237 func buildPackage(_pkg *PkgContainer, universe *ast.Scope) { 4238 typesMap = make(map[string]*dtypeEntry) 4239 typeId = 1 4240 4241 logf("Building package : %s\n", _pkg.path) 4242 fset := &token.FileSet{} 4243 pkgScope := ast.NewScope(universe) 4244 for _, file := range _pkg.files { 4245 if strings.HasSuffix(file, ".s") { 4246 continue 4247 } 4248 logf("Parsing file: %s\n", file) 4249 astFile := parseFile(fset, file) 4250 _pkg.name = astFile.Name.Name 4251 _pkg.astFiles = append(_pkg.astFiles, astFile) 4252 for name, obj := range astFile.Scope.Objects { 4253 pkgScope.Objects[name] = obj 4254 } 4255 } 4256 for _, astFile := range _pkg.astFiles { 4257 resolveImports(astFile) 4258 var unresolved []*ast.Ident 4259 for _, ident := range astFile.Unresolved { 4260 obj := pkgScope.Lookup(ident.Name) 4261 if obj != nil { 4262 ident.Obj = obj 4263 } else { 4264 logf("# unresolved: %s\n", ident.Name) 4265 obj := universe.Lookup(ident.Name) 4266 if obj != nil { 4267 ident.Obj = obj 4268 } else { 4269 // we should allow unresolved for now. 4270 // e.g foo in X{foo:bar,} 4271 logf("Unresolved (maybe struct field name in composite literal): " + ident.Name) 4272 unresolved = append(unresolved, ident) 4273 } 4274 } 4275 } 4276 for _, dcl := range astFile.Decls { 4277 _pkg.Decls = append(_pkg.Decls, dcl) 4278 } 4279 } 4280 logf("Walking package: %s\n", _pkg.name) 4281 walk(_pkg) 4282 generateCode(_pkg) 4283 } 4284 4285 // --- main --- 4286 func showHelp() { 4287 fmt.Printf("Usage:\n") 4288 fmt.Printf(" %s version: show version\n", ProgName) 4289 fmt.Printf(" %s [-DF] [-DG] filename\n", ProgName) 4290 } 4291 4292 func main() { 4293 srcPath = os.Getenv("GOPATH") + "/src" 4294 prjSrcPath = srcPath + "/github.com/DQNEO/babygo/src" 4295 4296 if len(os.Args) == 1 { 4297 showHelp() 4298 return 4299 } 4300 4301 if os.Args[1] == "version" { 4302 fmt.Printf("babygo version 0.0.2 linux/amd64\n") 4303 return 4304 } else if os.Args[1] == "help" { 4305 showHelp() 4306 return 4307 } else if os.Args[1] == "panic" { 4308 panicVersion := strconv.Itoa(mylib.Sum(1, 1)) 4309 panic("I am panic version " + panicVersion) 4310 } 4311 4312 workdir := os.Getenv("WORKDIR") 4313 if workdir == "" { 4314 workdir = "/tmp" 4315 } 4316 initAsm, err := os.Create(workdir + "/a.s") 4317 if err != nil { 4318 panic(err) 4319 } 4320 fout = initAsm 4321 logf("Build start\n") 4322 4323 var inputFiles []string 4324 for _, arg := range os.Args[1:] { 4325 switch arg { 4326 case "-DF": 4327 debugFrontEnd = true 4328 case "-DG": 4329 debugCodeGen = true 4330 default: 4331 inputFiles = append(inputFiles, arg) 4332 } 4333 } 4334 4335 paths := collectAllPackages(inputFiles) 4336 var packagesToBuild []*PkgContainer 4337 for _, _path := range paths { 4338 files := collectSourceFiles(getPackageDir(_path)) 4339 packagesToBuild = append(packagesToBuild, &PkgContainer{ 4340 name: path.Base(_path), 4341 path: _path, 4342 files: files, 4343 }) 4344 } 4345 4346 packagesToBuild = append(packagesToBuild, &PkgContainer{ 4347 name: "main", 4348 files: inputFiles, 4349 }) 4350 4351 var universe = createUniverse() 4352 for _, _pkg := range packagesToBuild { 4353 currentPkg = _pkg 4354 if _pkg.name == "" { 4355 panic("empty pkg name") 4356 } 4357 pgkAsm, err := os.Create(fmt.Sprintf("%s/%s.s", workdir, _pkg.name)) 4358 if err != nil { 4359 panic(err) 4360 } 4361 fout = pgkAsm 4362 buildPackage(_pkg, universe) 4363 pgkAsm.Close() 4364 } 4365 initAsm.Close() 4366 } 4367 4368 func setVariable(obj *ast.Object, vr *Variable) { 4369 if vr == nil { 4370 obj.Data = nil 4371 } else { 4372 obj.Data = vr 4373 } 4374 } 4375 4376 // --- AST meta data --- 4377 var mapMeta = make(map[unsafe.Pointer]interface{}) 4378 4379 type MetaReturnStmt struct { 4380 Fnc *Func 4381 } 4382 4383 type MetaForRange struct { 4384 IsMap bool 4385 LenVar *Variable 4386 Indexvar *Variable 4387 MapVar *Variable // map 4388 ItemVar *Variable // map element 4389 } 4390 4391 type MetaForStmt struct { 4392 LabelPost string // for continue 4393 LabelExit string // for break 4394 Outer *MetaForStmt 4395 ForRange *MetaForRange // for array or slice 4396 } 4397 4398 type MetaBranchStmt struct { 4399 containerForStmt *MetaForStmt 4400 } 4401 4402 type MetaTypeSwitchStmt struct { 4403 Subject ast.Expr 4404 SubjectVariable *Variable 4405 AssignIdent *ast.Ident 4406 Cases []*MetaTypeSwitchCaseClose 4407 } 4408 4409 type MetaTypeSwitchCaseClose struct { 4410 Variable *Variable 4411 VariableType *Type 4412 Orig *ast.CaseClause 4413 } 4414 type Func struct { 4415 Name string 4416 Stmts []ast.Stmt 4417 Localarea int 4418 Argsarea int 4419 LocalVars []*Variable 4420 Params []*Variable 4421 Retvars []*Variable 4422 FuncType *ast.FuncType 4423 Method *Method 4424 } 4425 type Method struct { 4426 PkgName string 4427 RcvNamedType *ast.Ident 4428 IsPtrMethod bool 4429 Name string 4430 FuncType *ast.FuncType 4431 } 4432 type Variable struct { 4433 Name string 4434 IsGlobal bool 4435 GlobalSymbol string 4436 LocalOffset int 4437 Typ *Type 4438 } 4439 4440 func getStructFieldOffset(field *ast.Field) int { 4441 return mapMeta[unsafe.Pointer(field)].(int) 4442 } 4443 4444 func setStructFieldOffset(field *ast.Field, offset int) { 4445 mapMeta[unsafe.Pointer(field)] = offset 4446 } 4447 4448 func getMetaReturnStmt(s *ast.ReturnStmt) *MetaReturnStmt { 4449 return mapMeta[unsafe.Pointer(s)].(*MetaReturnStmt) 4450 } 4451 4452 func setMetaReturnStmt(s *ast.ReturnStmt, meta *MetaReturnStmt) { 4453 mapMeta[unsafe.Pointer(s)] = meta 4454 } 4455 4456 func getMetaForStmt(stmt ast.Stmt) *MetaForStmt { 4457 switch s := stmt.(type) { 4458 case *ast.ForStmt: 4459 return mapMeta[unsafe.Pointer(s)].(*MetaForStmt) 4460 case *ast.RangeStmt: 4461 return mapMeta[unsafe.Pointer(s)].(*MetaForStmt) 4462 default: 4463 panic(stmt) 4464 } 4465 } 4466 4467 func setMetaForStmt(stmt ast.Stmt, meta *MetaForStmt) { 4468 switch s := stmt.(type) { 4469 case *ast.ForStmt: 4470 mapMeta[unsafe.Pointer(s)] = meta 4471 case *ast.RangeStmt: 4472 mapMeta[unsafe.Pointer(s)] = meta 4473 default: 4474 panic(stmt) 4475 } 4476 } 4477 4478 func getMetaBranchStmt(s *ast.BranchStmt) *MetaBranchStmt { 4479 return mapMeta[unsafe.Pointer(s)].(*MetaBranchStmt) 4480 } 4481 4482 func setMetaBranchStmt(s *ast.BranchStmt, meta *MetaBranchStmt) { 4483 mapMeta[unsafe.Pointer(s)] = meta 4484 } 4485 4486 func getMetaTypeSwitchStmt(s *ast.TypeSwitchStmt) *MetaTypeSwitchStmt { 4487 return mapMeta[unsafe.Pointer(s)].(*MetaTypeSwitchStmt) 4488 } 4489 4490 func setMetaTypeSwitchStmt(s *ast.TypeSwitchStmt, meta *MetaTypeSwitchStmt) { 4491 mapMeta[unsafe.Pointer(s)] = meta 4492 } 4493 4494 func throw(x interface{}) { 4495 panic(x) 4496 } 4497 4498 // tweak to reduce diff with main.go 4499 const parserImportsOnly = parser.ImportsOnly 4500 4501 func parserParseFile(fset *token.FileSet, filename string, src interface{}, mode parser.Mode) (*ast.File, error) { 4502 return parser.ParseFile(fset, filename, src, mode) 4503 }