github.com/DQNEO/babygo@v0.0.3/pre/precompiler.go (about)

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