github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/compiler/codegen/gen_expr.go (about)

     1  package codegen
     2  
     3  import (
     4  	"github.com/hirochachacha/plua/compiler/ast"
     5  	"github.com/hirochachacha/plua/compiler/token"
     6  	"github.com/hirochachacha/plua/internal/version"
     7  	"github.com/hirochachacha/plua/object"
     8  	"github.com/hirochachacha/plua/opcode"
     9  	"github.com/hirochachacha/plua/position"
    10  )
    11  
    12  type genType uint
    13  
    14  const (
    15  	genR    genType = 0         // normal register number
    16  	genK    genType = 1 << iota // constant number
    17  	genMove                     // copied register number
    18  	genKey                      // if expr is *ast.Name, then return constant number of it'g name
    19  )
    20  
    21  // load or resolve
    22  func (g *generator) genExpr(expr ast.Expr, typ genType) (rk int) {
    23  	switch expr := expr.(type) {
    24  	case *ast.BadExpr:
    25  		panic("bad expr")
    26  	case *ast.Name:
    27  		rk = g.genName(expr, typ)
    28  	case *ast.Vararg:
    29  		rk = g.genVarargN(expr, 1)
    30  	case *ast.BasicLit:
    31  		rk = g.genBasicLit(expr, typ)
    32  	case *ast.FuncLit:
    33  		rk = g.genFuncLit(expr)
    34  	case *ast.TableLit:
    35  		rk = g.genTableLit(expr)
    36  	case *ast.ParenExpr:
    37  		rk = g.genExpr(expr.X, typ)
    38  	case *ast.SelectorExpr:
    39  		rk = g.genSelectorExpr(expr)
    40  	case *ast.IndexExpr:
    41  		rk = g.genIndexExpr(expr)
    42  	case *ast.CallExpr:
    43  		rk = g.genCallExprN(expr, 1, false)
    44  	case *ast.UnaryExpr:
    45  		// const folding
    46  		if val, ok := g.foldUnary(expr); ok {
    47  			rk = g.genConst(val, typ)
    48  		} else {
    49  			rk = g.genUnaryExpr(expr, typ)
    50  		}
    51  	case *ast.BinaryExpr:
    52  		// const folding
    53  		if val, ok := g.foldBinary(expr); ok {
    54  			rk = g.genConst(val, typ)
    55  		} else {
    56  			rk = g.genBinaryExpr(expr, typ)
    57  		}
    58  	case *ast.KeyValueExpr:
    59  		panic("unexpected")
    60  	default:
    61  		panic("unreachable")
    62  	}
    63  	return
    64  }
    65  
    66  func (g *generator) genExprN(expr ast.Expr, nrets int) (isvar bool) {
    67  	locktmp := g.locktmp
    68  
    69  	g.locktmp = true
    70  
    71  	switch expr := expr.(type) {
    72  	case *ast.BadExpr:
    73  		panic("bad expr")
    74  	case *ast.Name:
    75  		g.genName(expr, genMove)
    76  	case *ast.Vararg:
    77  		g.genVarargN(expr, nrets)
    78  
    79  		isvar = true
    80  	case *ast.BasicLit:
    81  		g.genBasicLit(expr, genMove)
    82  	case *ast.FuncLit:
    83  		g.genFuncLit(expr)
    84  	case *ast.TableLit:
    85  		g.genTableLit(expr)
    86  	case *ast.ParenExpr:
    87  		g.genExpr(expr.X, genMove)
    88  	case *ast.SelectorExpr:
    89  		g.genSelectorExpr(expr)
    90  	case *ast.IndexExpr:
    91  		g.genIndexExpr(expr)
    92  	case *ast.CallExpr:
    93  		g.genCallExprN(expr, nrets, false)
    94  
    95  		isvar = true
    96  	case *ast.UnaryExpr:
    97  		// const folding
    98  		if val, ok := g.foldUnary(expr); ok {
    99  			g.genConst(val, genMove)
   100  		} else {
   101  			g.genUnaryExpr(expr, genMove)
   102  		}
   103  	case *ast.BinaryExpr:
   104  		// const folding
   105  		if val, ok := g.foldBinary(expr); ok {
   106  			g.genConst(val, genMove)
   107  		} else {
   108  			g.genBinaryExpr(expr, genMove)
   109  		}
   110  	case *ast.KeyValueExpr:
   111  		panic("unexpected")
   112  	default:
   113  		panic("unreachable")
   114  	}
   115  
   116  	if !isvar {
   117  		if nrets > 1 {
   118  			g.pushInst(opcode.AB(opcode.LOADNIL, g.sp, nrets-2))
   119  
   120  			g.addSP(nrets - 1)
   121  		}
   122  
   123  		if nrets == 0 {
   124  			g.addSP(-1)
   125  		}
   126  	}
   127  
   128  	g.locktmp = locktmp
   129  
   130  	return
   131  }
   132  
   133  // resolve or move
   134  func (g *generator) genName(expr *ast.Name, typ genType) (rk int) {
   135  	g.tokLine = expr.Pos().Line
   136  
   137  	if typ&genKey != 0 {
   138  		return g.markRK(g.constant(object.String(expr.Name)), true)
   139  	}
   140  
   141  	l, ok := g.resolveName(expr)
   142  	if !ok {
   143  		return g.genGetGlobal(expr)
   144  	}
   145  
   146  	switch l.kind {
   147  	case linkUpval:
   148  		g.pushInst(opcode.AB(opcode.GETUPVAL, g.sp, l.index))
   149  
   150  		rk = g.sp
   151  
   152  		g.nextSP()
   153  	case linkLocal:
   154  		if typ&genMove == 0 {
   155  			return l.index
   156  		}
   157  
   158  		rk = g.sp
   159  
   160  		g.pushInst(opcode.AB(opcode.MOVE, g.sp, l.index))
   161  
   162  		g.nextSP()
   163  	default:
   164  		panic("unreachable")
   165  	}
   166  
   167  	return
   168  }
   169  
   170  func (g *generator) genVarargN(expr *ast.Vararg, nrets int) (r int) {
   171  	g.tokLine = expr.Pos().Line
   172  
   173  	sp := g.sp
   174  
   175  	g.pushInst(opcode.AB(opcode.VARARG, g.sp, nrets+1))
   176  
   177  	r = g.sp
   178  
   179  	if nrets < 0 {
   180  		// just update maxstacksize
   181  		if g.sp+1 > g.MaxStackSize {
   182  			g.MaxStackSize = g.sp + 1
   183  		}
   184  
   185  		return
   186  	}
   187  
   188  	g.setSP(sp + nrets)
   189  
   190  	return
   191  }
   192  
   193  func (g *generator) genBasicLit(expr *ast.BasicLit, typ genType) (rk int) {
   194  	g.tokLine = expr.Pos().Line
   195  
   196  	var val object.Value
   197  
   198  	tok := expr.Token
   199  
   200  	switch tok.Type {
   201  	case token.NIL:
   202  		g.pushInst(opcode.AB(opcode.LOADNIL, g.sp, 0))
   203  
   204  		rk = g.sp
   205  
   206  		g.nextSP()
   207  
   208  		return
   209  	case token.FALSE:
   210  		g.pushInst(opcode.ABC(opcode.LOADBOOL, g.sp, 0, 0))
   211  
   212  		rk = g.sp
   213  
   214  		g.nextSP()
   215  
   216  		return
   217  	case token.TRUE:
   218  		g.pushInst(opcode.ABC(opcode.LOADBOOL, g.sp, 1, 0))
   219  
   220  		rk = g.sp
   221  
   222  		g.nextSP()
   223  
   224  		return
   225  	case token.INT:
   226  		if i, ok := g.parseInteger(tok, false); ok {
   227  			val = i
   228  		} else {
   229  			val = g.parseNumber(tok, false)
   230  		}
   231  	case token.FLOAT:
   232  		val = g.parseNumber(tok, false)
   233  	case token.STRING:
   234  		val = object.String(g.unquoteString(tok))
   235  	default:
   236  		panic("unreachable")
   237  	}
   238  
   239  	return g.genConst(val, typ)
   240  }
   241  
   242  func (g *generator) genFuncLit(expr *ast.FuncLit) (r int) {
   243  	g.tokLine = expr.Pos().Line
   244  
   245  	body := expr.Body
   246  
   247  	endLine := expr.End().Line
   248  
   249  	p := g.proto(body, false, endLine)
   250  
   251  	g.pushInstLine(opcode.ABx(opcode.CLOSURE, g.sp, p), endLine)
   252  
   253  	r = g.sp
   254  
   255  	g.nextSP()
   256  
   257  	return
   258  }
   259  
   260  func (g *generator) genTableLit(expr *ast.TableLit) (r int) {
   261  	g.tokLine = expr.Pos().Line
   262  
   263  	var a []ast.Expr
   264  	var m []*ast.KeyValueExpr
   265  	for _, e := range expr.Fields {
   266  		if keyval, ok := e.(*ast.KeyValueExpr); ok {
   267  			m = append(m, keyval)
   268  		} else {
   269  			a = append(a, e)
   270  		}
   271  	}
   272  
   273  	var skipped bool
   274  	for len(a) > 0 {
   275  		if lit, ok := a[len(a)-1].(*ast.BasicLit); ok && lit.Token.Type == token.NIL {
   276  			a = a[:len(a)-1]
   277  
   278  			skipped = true
   279  
   280  			continue
   281  		}
   282  
   283  		break
   284  	}
   285  
   286  	g.pushInst(opcode.ABC(opcode.NEWTABLE, g.sp, opcode.IntToLog(len(a)), opcode.IntToLog(len(m))))
   287  
   288  	tp := g.sp
   289  
   290  	g.nextSP()
   291  
   292  	for _, e := range m {
   293  		sp := g.sp
   294  		if e.Lbrack != position.NoPos {
   295  			x := g.genExpr(e.Key, genR|genK)
   296  			y := g.genExpr(e.Value, genR|genK)
   297  
   298  			g.pushInst(opcode.ABC(opcode.SETTABLE, tp, x, y))
   299  		} else {
   300  			x := g.genExpr(e.Key, genR|genK|genKey)
   301  			y := g.genExpr(e.Value, genR|genK)
   302  
   303  			g.pushInst(opcode.ABC(opcode.SETTABLE, tp, x, y))
   304  		}
   305  		g.sp = sp
   306  	}
   307  
   308  	if len(a) > 0 {
   309  		locktmp := g.locktmp
   310  
   311  		g.locktmp = true
   312  
   313  		sp := g.sp
   314  
   315  		i := 1
   316  		for {
   317  			if len(a) < version.LUA_FPF {
   318  				if len(a) == 0 {
   319  					break
   320  				}
   321  
   322  				var isVar bool
   323  
   324  				if skipped {
   325  					for _, e := range a {
   326  						g.genExpr(e, genMove)
   327  					}
   328  				} else {
   329  					for _, e := range a[:len(a)-1] {
   330  						g.genExpr(e, genMove)
   331  					}
   332  
   333  					isVar = g.genExprN(a[len(a)-1], -1)
   334  				}
   335  
   336  				n := len(a)
   337  				if isVar {
   338  					n = 0
   339  				}
   340  
   341  				if i > opcode.MaxC {
   342  					g.pushInst(opcode.ABC(opcode.SETLIST, tp, n, 0))
   343  					g.pushInst(opcode.Ax(opcode.EXTRAARG, i))
   344  				} else {
   345  					g.pushInst(opcode.ABC(opcode.SETLIST, tp, n, i))
   346  				}
   347  
   348  				// recover sp
   349  				g.sp = sp
   350  
   351  				break
   352  			}
   353  
   354  			for _, e := range a[:version.LUA_FPF] {
   355  				g.genExpr(e, genMove)
   356  			}
   357  
   358  			if i > opcode.MaxC {
   359  				g.pushInst(opcode.ABC(opcode.SETLIST, tp, version.LUA_FPF, 0))
   360  				g.pushInst(opcode.Ax(opcode.EXTRAARG, i))
   361  			} else {
   362  				g.pushInst(opcode.ABC(opcode.SETLIST, tp, version.LUA_FPF, i))
   363  			}
   364  
   365  			// recover sp
   366  			g.sp = sp
   367  
   368  			a = a[version.LUA_FPF:]
   369  			i++
   370  		}
   371  
   372  		g.locktmp = locktmp
   373  	}
   374  
   375  	r = tp
   376  
   377  	return
   378  }
   379  
   380  func (g *generator) genSelectorExpr(expr *ast.SelectorExpr) (r int) {
   381  	g.tokLine = expr.Pos().Line
   382  
   383  	sp := g.sp
   384  
   385  	x := g.genExpr(expr.X, genR)
   386  	y := g.genName(expr.Sel, genKey)
   387  
   388  	g.pushInst(opcode.ABC(opcode.GETTABLE, sp, x, y))
   389  
   390  	r = sp
   391  
   392  	// recover sp
   393  	g.setSP(sp + 1)
   394  
   395  	return
   396  }
   397  
   398  func (g *generator) genIndexExpr(expr *ast.IndexExpr) (r int) {
   399  	g.tokLine = expr.Pos().Line
   400  
   401  	sp := g.sp
   402  
   403  	x := g.genExpr(expr.X, genR)
   404  	y := g.genExpr(expr.Index, genR|genK)
   405  
   406  	g.pushInst(opcode.ABC(opcode.GETTABLE, sp, x, y))
   407  
   408  	r = sp
   409  
   410  	// recover sp
   411  	g.setSP(sp + 1)
   412  
   413  	return
   414  }
   415  
   416  func (g *generator) genCallExprN(expr *ast.CallExpr, nrets int, isTail bool) (r int) {
   417  	g.tokLine = expr.Pos().Line
   418  
   419  	sp := g.sp
   420  
   421  	var fn int
   422  
   423  	nargs := len(expr.Args)
   424  
   425  	locktmp := g.locktmp
   426  
   427  	if expr.Colon != position.NoPos {
   428  		self := g.genExpr(expr.X, genR)
   429  
   430  		name := g.genName(expr.Name, genKey)
   431  
   432  		g.pushInst(opcode.ABC(opcode.SELF, sp, self, name))
   433  
   434  		nargs++
   435  
   436  		fn = sp
   437  
   438  		g.setSP(sp + 2)
   439  
   440  		g.locktmp = true
   441  	} else {
   442  		g.locktmp = true
   443  
   444  		fn = g.genExpr(expr.X, genMove)
   445  	}
   446  
   447  	var isVar bool
   448  	if len(expr.Args) != 0 {
   449  		for _, e := range expr.Args[:len(expr.Args)-1] {
   450  			g.genExpr(e, genMove)
   451  		}
   452  
   453  		isVar = g.genExprN(expr.Args[len(expr.Args)-1], -1)
   454  	}
   455  
   456  	g.locktmp = locktmp
   457  
   458  	if isTail {
   459  		if isVar {
   460  			g.pushInst(opcode.ABC(opcode.TAILCALL, fn, 0, 0))
   461  		} else {
   462  			g.pushInst(opcode.ABC(opcode.TAILCALL, fn, nargs+1, 0))
   463  		}
   464  
   465  		r = fn
   466  
   467  		// recover sp
   468  		g.setSP(sp)
   469  
   470  		return
   471  	}
   472  
   473  	if isVar {
   474  		g.pushInst(opcode.ABC(opcode.CALL, fn, 0, nrets+1))
   475  	} else {
   476  		g.pushInst(opcode.ABC(opcode.CALL, fn, nargs+1, nrets+1))
   477  	}
   478  
   479  	r = fn
   480  
   481  	if nrets < 0 {
   482  		// just update maxstacksize
   483  		if g.sp+1 > g.MaxStackSize {
   484  			g.MaxStackSize = g.sp + 1
   485  		}
   486  
   487  		return
   488  	}
   489  
   490  	// recover sp
   491  	g.setSP(sp + nrets)
   492  
   493  	return
   494  }
   495  
   496  func (g *generator) genUnaryExpr(expr *ast.UnaryExpr, typ genType) (r int) {
   497  	g.tokLine = expr.Pos().Line
   498  
   499  	if expr.Op == token.UNM {
   500  		if x, ok := expr.X.(*ast.BasicLit); ok {
   501  			tok := x.Token
   502  
   503  			switch tok.Type {
   504  			case token.INT:
   505  				var val object.Value
   506  
   507  				if i, ok := g.parseInteger(tok, true); ok {
   508  					val = i
   509  				} else {
   510  					val = g.parseNumber(tok, true)
   511  				}
   512  
   513  				return g.genConst(val, typ)
   514  			case token.FLOAT:
   515  				val := g.parseNumber(tok, true)
   516  
   517  				return g.genConst(val, typ)
   518  			}
   519  		}
   520  	}
   521  
   522  	sp := g.sp
   523  
   524  	x := g.genExpr(expr.X, genR)
   525  
   526  	switch expr.Op {
   527  	case token.UNM:
   528  		g.pushInst(opcode.AB(opcode.UNM, sp, x))
   529  	case token.BNOT:
   530  		g.pushInst(opcode.AB(opcode.BNOT, sp, x))
   531  	case token.NOT:
   532  		g.pushInst(opcode.AB(opcode.NOT, sp, x))
   533  	case token.LEN:
   534  		g.pushInst(opcode.AB(opcode.LEN, sp, x))
   535  	default:
   536  		panic("unreachable")
   537  	}
   538  
   539  	r = sp
   540  
   541  	// recover sp
   542  	g.setSP(sp + 1)
   543  
   544  	return
   545  }
   546  
   547  func (g *generator) genBinaryExpr(expr *ast.BinaryExpr, typ genType) (r int) {
   548  	g.tokLine = expr.Pos().Line
   549  
   550  	sp := g.sp
   551  
   552  	switch expr.Op {
   553  	case token.EQ:
   554  		x := g.genExpr(expr.X, genR|genK)
   555  		y := g.genExpr(expr.Y, genR|genK)
   556  
   557  		g.pushInst(opcode.ABC(opcode.EQ, 1, x, y))
   558  		g.pushInst(opcode.AsBx(opcode.JMP, 0, 1))
   559  		g.pushInst(opcode.ABC(opcode.LOADBOOL, sp, 0, 1))
   560  		g.pushInst(opcode.ABC(opcode.LOADBOOL, sp, 1, 0))
   561  
   562  		g.lockpeep = true
   563  	case token.NE:
   564  		x := g.genExpr(expr.X, genR|genK)
   565  		y := g.genExpr(expr.Y, genR|genK)
   566  
   567  		g.pushInst(opcode.ABC(opcode.EQ, 0, x, y))
   568  		g.pushInst(opcode.AsBx(opcode.JMP, 0, 1))
   569  		g.pushInst(opcode.ABC(opcode.LOADBOOL, sp, 0, 1))
   570  		g.pushInst(opcode.ABC(opcode.LOADBOOL, sp, 1, 0))
   571  
   572  		g.lockpeep = true
   573  	case token.LT:
   574  		x := g.genExpr(expr.X, genR|genK)
   575  		y := g.genExpr(expr.Y, genR|genK)
   576  
   577  		g.pushInst(opcode.ABC(opcode.LT, 1, x, y))
   578  		g.pushInst(opcode.AsBx(opcode.JMP, 0, 1))
   579  		g.pushInst(opcode.ABC(opcode.LOADBOOL, sp, 0, 1))
   580  		g.pushInst(opcode.ABC(opcode.LOADBOOL, sp, 1, 0))
   581  
   582  		g.lockpeep = true
   583  	case token.LE:
   584  		x := g.genExpr(expr.X, genR|genK)
   585  		y := g.genExpr(expr.Y, genR|genK)
   586  
   587  		g.pushInst(opcode.ABC(opcode.LE, 1, x, y))
   588  		g.pushInst(opcode.AsBx(opcode.JMP, 0, 1))
   589  		g.pushInst(opcode.ABC(opcode.LOADBOOL, sp, 0, 1))
   590  		g.pushInst(opcode.ABC(opcode.LOADBOOL, sp, 1, 0))
   591  
   592  		g.lockpeep = true
   593  	case token.GT:
   594  		x := g.genExpr(expr.X, genR|genK)
   595  		y := g.genExpr(expr.Y, genR|genK)
   596  
   597  		g.pushInst(opcode.ABC(opcode.LT, 1, y, x))
   598  		g.pushInst(opcode.AsBx(opcode.JMP, 0, 1))
   599  		g.pushInst(opcode.ABC(opcode.LOADBOOL, sp, 0, 1))
   600  		g.pushInst(opcode.ABC(opcode.LOADBOOL, sp, 1, 0))
   601  
   602  		g.lockpeep = true
   603  	case token.GE:
   604  		x := g.genExpr(expr.X, genR|genK)
   605  		y := g.genExpr(expr.Y, genR|genK)
   606  
   607  		g.pushInst(opcode.ABC(opcode.LE, 1, y, x))
   608  		g.pushInst(opcode.AsBx(opcode.JMP, 0, 1))
   609  		g.pushInst(opcode.ABC(opcode.LOADBOOL, sp, 0, 1))
   610  		g.pushInst(opcode.ABC(opcode.LOADBOOL, sp, 1, 0))
   611  
   612  		g.lockpeep = true
   613  	case token.ADD:
   614  		x := g.genExpr(expr.X, genR|genK)
   615  		y := g.genExpr(expr.Y, genR|genK)
   616  
   617  		g.pushInst(opcode.ABC(opcode.ADD, sp, x, y))
   618  	case token.SUB:
   619  		x := g.genExpr(expr.X, genR|genK)
   620  		y := g.genExpr(expr.Y, genR|genK)
   621  
   622  		g.pushInst(opcode.ABC(opcode.SUB, sp, x, y))
   623  	case token.MUL:
   624  		x := g.genExpr(expr.X, genR|genK)
   625  		y := g.genExpr(expr.Y, genR|genK)
   626  
   627  		g.pushInst(opcode.ABC(opcode.MUL, sp, x, y))
   628  	case token.MOD:
   629  		x := g.genExpr(expr.X, genR|genK)
   630  		y := g.genExpr(expr.Y, genR|genK)
   631  
   632  		g.pushInst(opcode.ABC(opcode.MOD, sp, x, y))
   633  	case token.POW:
   634  		x := g.genExpr(expr.X, genR|genK)
   635  		y := g.genExpr(expr.Y, genR|genK)
   636  
   637  		g.pushInst(opcode.ABC(opcode.POW, sp, x, y))
   638  	case token.DIV:
   639  		x := g.genExpr(expr.X, genR|genK)
   640  		y := g.genExpr(expr.Y, genR|genK)
   641  
   642  		g.pushInst(opcode.ABC(opcode.DIV, sp, x, y))
   643  	case token.IDIV:
   644  		x := g.genExpr(expr.X, genR|genK)
   645  		y := g.genExpr(expr.Y, genR|genK)
   646  
   647  		g.pushInst(opcode.ABC(opcode.IDIV, sp, x, y))
   648  	case token.BAND:
   649  		x := g.genExpr(expr.X, genR|genK)
   650  		y := g.genExpr(expr.Y, genR|genK)
   651  
   652  		g.pushInst(opcode.ABC(opcode.BAND, sp, x, y))
   653  	case token.BOR:
   654  		x := g.genExpr(expr.X, genR|genK)
   655  		y := g.genExpr(expr.Y, genR|genK)
   656  
   657  		g.pushInst(opcode.ABC(opcode.BOR, sp, x, y))
   658  	case token.BXOR:
   659  		x := g.genExpr(expr.X, genR|genK)
   660  		y := g.genExpr(expr.Y, genR|genK)
   661  
   662  		g.pushInst(opcode.ABC(opcode.BXOR, sp, x, y))
   663  	case token.SHL:
   664  		x := g.genExpr(expr.X, genR|genK)
   665  		y := g.genExpr(expr.Y, genR|genK)
   666  
   667  		g.pushInst(opcode.ABC(opcode.SHL, sp, x, y))
   668  	case token.SHR:
   669  		x := g.genExpr(expr.X, genR|genK)
   670  		y := g.genExpr(expr.Y, genR|genK)
   671  
   672  		g.pushInst(opcode.ABC(opcode.SHR, sp, x, y))
   673  	case token.CONCAT:
   674  		locktmp := g.locktmp
   675  
   676  		g.locktmp = true
   677  
   678  		x := g.genExpr(expr.X, genMove)
   679  
   680  		Y := expr.Y
   681  		for {
   682  			ct, ok := Y.(*ast.BinaryExpr)
   683  			if !ok || ct.Op != token.CONCAT {
   684  				break
   685  			}
   686  
   687  			g.genExpr(ct.X, genMove)
   688  
   689  			Y = ct.Y
   690  		}
   691  
   692  		y := g.genExpr(Y, genMove)
   693  
   694  		g.locktmp = locktmp
   695  
   696  		g.pushInst(opcode.ABC(opcode.CONCAT, sp, x, y))
   697  	case token.AND:
   698  		if _, ok := g.foldExpr(expr.X); ok {
   699  			x := g.genExpr(expr.Y, genR)
   700  
   701  			if typ&genMove == 0 {
   702  				return x
   703  			}
   704  
   705  			g.pushInst(opcode.AB(opcode.MOVE, sp, x))
   706  		} else {
   707  			x := g.genExpr(expr.X, genR)
   708  
   709  			g.pushInst(opcode.ABC(opcode.TESTSET, sp, x, 0))
   710  
   711  			endJump := g.genJumpPoint()
   712  
   713  			y := g.genExpr(expr.Y, genR)
   714  
   715  			g.pushInst(opcode.AB(opcode.MOVE, sp, y))
   716  
   717  			g.genJumpFrom(endJump)
   718  		}
   719  	case token.OR:
   720  		if _, ok := g.foldExpr(expr.X); ok {
   721  			y := g.genExpr(expr.Y, genR)
   722  
   723  			if typ&genMove == 0 {
   724  				return y
   725  			}
   726  
   727  			g.pushInst(opcode.AB(opcode.MOVE, sp, y))
   728  		} else {
   729  			x := g.genExpr(expr.X, genR)
   730  
   731  			g.pushInst(opcode.ABC(opcode.TESTSET, sp, x, 1))
   732  
   733  			endJump := g.genJumpPoint()
   734  
   735  			y := g.genExpr(expr.Y, genR)
   736  
   737  			g.pushInst(opcode.AB(opcode.MOVE, sp, y))
   738  
   739  			g.genJumpFrom(endJump)
   740  		}
   741  	default:
   742  		panic("unreachable")
   743  	}
   744  
   745  	r = sp
   746  
   747  	// recover sp
   748  	g.setSP(sp + 1)
   749  
   750  	return
   751  }