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  }