func (c *expCompiler) ProcessTableConstructorExp(t ast.TableConstructor) {
	c.emitInstr(t, ir.MkTable{Dst: c.dst})
	c.TakeRegister(c.dst)
	currImplicitKey := 1
	for i, field := range t.Fields {
		keyExp := field.Key
		_, noKey := keyExp.(ast.NoTableKey)
		if i == len(t.Fields)-1 && noKey {
			tailExp, ok := field.Value.(ast.TailExpNode)
			if ok {
				etc := c.compileEtcExp(tailExp, c.GetFreeRegister())
				c.emitInstr(field.Value, ir.FillTable{
					Dst: c.dst,
					Idx: currImplicitKey,
					Etc: etc,
				})
				break
			}
		}
		valReg := c.compileExpNoDestHint(field.Value)
		c.TakeRegister(valReg)
		if noKey {
			keyExp = ast.Int{Val: uint64(currImplicitKey)}
			currImplicitKey++
		}
		keyReg := c.compileExpNoDestHint(keyExp)
		c.emitInstr(field.Value, ir.SetIndex{
			Table: c.dst,
			Index: keyReg,
			Src:   valReg,
		})
		c.ReleaseRegister(valReg)
	}
	c.ReleaseRegister(c.dst)
}
ProcessTableConstructorExp compiles a TableConstructorExp.
package astcomp
import (
	"github.com/arnodel/golua/ast"
	"github.com/arnodel/golua/ir"
	"github.com/arnodel/golua/ops"
)
type expCompiler struct {
	*compiler
	dst ir.Register
}
var _ ast.ExpProcessor = (*expCompiler)(nil)
func (c *expCompiler) ProcessBFunctionCallExp(f ast.BFunctionCall) {
	c.compileCall(f, false)
	c.emitInstr(f, ir.Receive{Dst: []ir.Register{c.dst}})
}
func (c *expCompiler) ProcessBinOpExp(b ast.BinOp) {
	if b.OpType == ops.OpAnd {
		c.compileLogicalOp(b, true)
		return
	}
	if b.OpType == ops.OpOr {
		c.compileLogicalOp(b, false)
		return
	}
	lsrc := c.compileExpNoDestHint(b.Left)
	for _, r := range b.Right {
		c.TakeRegister(lsrc)
		rsrc := c.compileExpNoDestHint(r.Operand)
		switch r.Op {
		case ops.OpNeq:
			c.emitInstr(b, ir.Combine{
				Op:   ops.OpEq,
				Dst:  c.dst,
				Lsrc: lsrc,
				Rsrc: rsrc,
			})
			c.emitInstr(b, ir.Transform{
				Op:  ops.OpNot,
				Dst: c.dst,
				Src: c.dst,
			})
		case ops.OpGt:
			c.emitInstr(b, ir.Combine{
				Op:   ops.OpLt,
				Dst:  c.dst,
				Lsrc: rsrc,
				Rsrc: lsrc,
			})
		case ops.OpGeq:
			c.emitInstr(b, ir.Combine{
				Op:   ops.OpLeq,
				Dst:  c.dst,
				Lsrc: rsrc,
				Rsrc: lsrc,
			})
		default:
			c.emitInstr(b, ir.Combine{
				Op:   r.Op,
				Dst:  c.dst,
				Lsrc: lsrc,
				Rsrc: rsrc,
			})
		}
		c.ReleaseRegister(lsrc)
		lsrc = c.dst
	}
	return
}
func (c *expCompiler) compileLogicalOp(b ast.BinOp, not bool) {
	doneLbl := c.GetNewLabel()
	c.compileExpInto(b.Left, c.dst)
	c.emitInstr(b.Left, ir.JumpIf{Cond: c.dst, Label: doneLbl, Not: not})
	for i, r := range b.Right {
		c.compileExpInto(r.Operand, c.dst)
		if i < len(b.Right) {
			c.emitInstr(r.Operand, ir.JumpIf{Cond: c.dst, Label: doneLbl, Not: not})
		}
	}
	c.EmitLabel(doneLbl)
}
func (c *expCompiler) ProcesBoolExp(b ast.Bool) {
	c.emitLoadConst(b, ir.Bool(b.Val), c.dst)
}
func (c *expCompiler) ProcessEtcExp(e ast.Etc) {
	reg := c.getEllipsisReg()
	c.emitInstr(e, ir.EtcLookup{Dst: c.dst, Etc: reg})
}
func (c *expCompiler) ProcessFunctionExp(f ast.Function) {
	fc := c.NewChild(f.Name)
	fc.compileFunctionBody(f)
	kidx, upvalues := fc.Close()
	c.emitInstr(f, ir.MkClosure{
		Dst:      c.dst,
		Code:     kidx,
		Upvalues: upvalues,
	})
}
func (c *expCompiler) ProcessFunctionCallExp(f ast.FunctionCall) {
	c.ProcessBFunctionCallExp(*f.BFunctionCall)
}
func (c *expCompiler) ProcessIndexExp(e ast.IndexExp) {
	tReg := c.compileExpNoDestHint(e.Coll)
	c.TakeRegister(tReg)
	iReg := c.compileExpNoDestHint(e.Idx)
	c.emitInstr(e, ir.Lookup{
		Dst:   c.dst,
		Table: tReg,
		Index: iReg,
	})
	c.ReleaseRegister(tReg)
}
func (c *expCompiler) ProcessNameExp(n ast.Name) {
	reg, ok := c.GetRegister(ir.Name(n.Val))
	if ok {
		c.dst = reg
		return
	}
	c.CompileExp(globalVar(n))
}
func (c *expCompiler) ProcessNilExp(n ast.Nil) {
	c.emitLoadConst(n, ir.NilType{}, c.dst)
}
func (c *expCompiler) ProcessIntExp(n ast.Int) {
	c.emitLoadConst(n, ir.Int(n.Val), c.dst)
}
func (c *expCompiler) ProcessFloatExp(f ast.Float) {
	c.emitLoadConst(f, ir.Float(f.Val), c.dst)
}
func (c *expCompiler) ProcessStringExp(s ast.String) {
	c.emitLoadConst(s, ir.String(s.Val), c.dst)
}