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