package goja

import (
	

	
	
	
	
)

type compiledExpr interface {
	emitGetter(putOnStack bool)
	emitSetter(valueExpr compiledExpr, putOnStack bool)
	emitRef()
	emitUnary(prepare, body func(), postfix, putOnStack bool)
	deleteExpr() compiledExpr
	constant() bool
	addSrcMap()
}

type compiledExprOrRef interface {
	compiledExpr
	emitGetterOrRef()
}

type compiledCallExpr struct {
	baseCompiledExpr
	args   []compiledExpr
	callee compiledExpr

	isVariadic bool
}

type compiledNewExpr struct {
	compiledCallExpr
}

type compiledObjectLiteral struct {
	baseCompiledExpr
	expr *ast.ObjectLiteral
}

type compiledArrayLiteral struct {
	baseCompiledExpr
	expr *ast.ArrayLiteral
}

type compiledRegexpLiteral struct {
	baseCompiledExpr
	expr *ast.RegExpLiteral
}

type compiledLiteral struct {
	baseCompiledExpr
	val Value
}

type compiledTemplateLiteral struct {
	baseCompiledExpr
	tag         compiledExpr
	elements    []*ast.TemplateElement
	expressions []compiledExpr
}

type compiledAssignExpr struct {
	baseCompiledExpr
	left, right compiledExpr
	operator    token.Token
}

type compiledObjectAssignmentPattern struct {
	baseCompiledExpr
	expr *ast.ObjectPattern
}

type compiledArrayAssignmentPattern struct {
	baseCompiledExpr
	expr *ast.ArrayPattern
}

type deleteGlobalExpr struct {
	baseCompiledExpr
	name unistring.String
}

type deleteVarExpr struct {
	baseCompiledExpr
	name unistring.String
}

type deletePropExpr struct {
	baseCompiledExpr
	left compiledExpr
	name unistring.String
}

type deleteElemExpr struct {
	baseCompiledExpr
	left, member compiledExpr
}

type constantExpr struct {
	baseCompiledExpr
	val Value
}

type baseCompiledExpr struct {
	c      *compiler
	offset int
}

type compiledIdentifierExpr struct {
	baseCompiledExpr
	name unistring.String
}

type compiledAwaitExpression struct {
	baseCompiledExpr
	arg compiledExpr
}

type compiledYieldExpression struct {
	baseCompiledExpr
	arg      compiledExpr
	delegate bool
}

type funcType uint8

const (
	funcNone funcType = iota
	funcRegular
	funcArrow
	funcMethod
	funcClsInit
	funcCtor
	funcDerivedCtor
)

type compiledFunctionLiteral struct {
	baseCompiledExpr
	name            *ast.Identifier
	parameterList   *ast.ParameterList
	body            []ast.Statement
	source          string
	declarationList []*ast.VariableDeclaration
	lhsName         unistring.String
	strict          *ast.StringLiteral
	homeObjOffset   uint32
	typ             funcType
	isExpr          bool

	isAsync, isGenerator bool
}

type compiledBracketExpr struct {
	baseCompiledExpr
	left, member compiledExpr
}

type compiledThisExpr struct {
	baseCompiledExpr
}

type compiledSuperExpr struct {
	baseCompiledExpr
}

type compiledNewTarget struct {
	baseCompiledExpr
}

type compiledSequenceExpr struct {
	baseCompiledExpr
	sequence []compiledExpr
}

type compiledUnaryExpr struct {
	baseCompiledExpr
	operand  compiledExpr
	operator token.Token
	postfix  bool
}

type compiledConditionalExpr struct {
	baseCompiledExpr
	test, consequent, alternate compiledExpr
}

type compiledLogicalOr struct {
	baseCompiledExpr
	left, right compiledExpr
}

type compiledCoalesce struct {
	baseCompiledExpr
	left, right compiledExpr
}

type compiledLogicalAnd struct {
	baseCompiledExpr
	left, right compiledExpr
}

type compiledBinaryExpr struct {
	baseCompiledExpr
	left, right compiledExpr
	operator    token.Token
}

type compiledEnumGetExpr struct {
	baseCompiledExpr
}

type defaultDeleteExpr struct {
	baseCompiledExpr
	expr compiledExpr
}

type compiledSpreadCallArgument struct {
	baseCompiledExpr
	expr compiledExpr
}

type compiledOptionalChain struct {
	baseCompiledExpr
	expr compiledExpr
}

type compiledOptional struct {
	baseCompiledExpr
	expr compiledExpr
}

func ( *defaultDeleteExpr) ( bool) {
	.expr.emitGetter(false)
	if  {
		.c.emitLiteralValue(valueTrue)
	}
}

func ( *compiler) ( ast.Expression) compiledExpr {
	// log.Printf("compileExpression: %T", v)
	switch v := .(type) {
	case nil:
		return nil
	case *ast.AssignExpression:
		return .compileAssignExpression()
	case *ast.NumberLiteral:
		return .compileNumberLiteral()
	case *ast.StringLiteral:
		return .compileStringLiteral()
	case *ast.TemplateLiteral:
		return .compileTemplateLiteral()
	case *ast.BooleanLiteral:
		return .compileBooleanLiteral()
	case *ast.NullLiteral:
		 := &compiledLiteral{
			val: _null,
		}
		.init(, .Idx0())
		return 
	case *ast.Identifier:
		return .compileIdentifierExpression()
	case *ast.CallExpression:
		return .compileCallExpression()
	case *ast.ObjectLiteral:
		return .compileObjectLiteral()
	case *ast.ArrayLiteral:
		return .compileArrayLiteral()
	case *ast.RegExpLiteral:
		return .compileRegexpLiteral()
	case *ast.BinaryExpression:
		return .compileBinaryExpression()
	case *ast.UnaryExpression:
		return .compileUnaryExpression()
	case *ast.ConditionalExpression:
		return .compileConditionalExpression()
	case *ast.FunctionLiteral:
		return .compileFunctionLiteral(, true)
	case *ast.ArrowFunctionLiteral:
		return .compileArrowFunctionLiteral()
	case *ast.ClassLiteral:
		return .compileClassLiteral(, true)
	case *ast.DotExpression:
		return .compileDotExpression()
	case *ast.PrivateDotExpression:
		return .compilePrivateDotExpression()
	case *ast.BracketExpression:
		return .compileBracketExpression()
	case *ast.ThisExpression:
		 := &compiledThisExpr{}
		.init(, .Idx0())
		return 
	case *ast.SuperExpression:
		.throwSyntaxError(int(.Idx0())-1, "'super' keyword unexpected here")
		panic("unreachable")
	case *ast.SequenceExpression:
		return .compileSequenceExpression()
	case *ast.NewExpression:
		return .compileNewExpression()
	case *ast.MetaProperty:
		return .compileMetaProperty()
	case *ast.ObjectPattern:
		return .compileObjectAssignmentPattern()
	case *ast.ArrayPattern:
		return .compileArrayAssignmentPattern()
	case *ast.OptionalChain:
		 := &compiledOptionalChain{
			expr: .(.Expression),
		}
		.init(, .Idx0())
		return 
	case *ast.Optional:
		 := &compiledOptional{
			expr: .(.Expression),
		}
		.init(, .Idx0())
		return 
	case *ast.AwaitExpression:
		 := &compiledAwaitExpression{
			arg: .(.Argument),
		}
		.init(, .Await)
		return 
	case *ast.YieldExpression:
		 := &compiledYieldExpression{
			arg:      .(.Argument),
			delegate: .Delegate,
		}
		.init(, .Yield)
		return 
	default:
		.assert(false, int(.Idx0())-1, "Unknown expression type: %T", )
		panic("unreachable")
	}
}

func ( *baseCompiledExpr) () bool {
	return false
}

func ( *baseCompiledExpr) ( *compiler,  file.Idx) {
	.c = 
	.offset = int() - 1
}

func ( *baseCompiledExpr) (compiledExpr, bool) {
	.c.throwSyntaxError(.offset, "Not a valid left-value expression")
}

func ( *baseCompiledExpr) () {
	.c.assert(false, .offset, "Cannot emit reference for this type of expression")
}

func ( *baseCompiledExpr) () compiledExpr {
	 := &constantExpr{
		val: valueTrue,
	}
	.init(.c, file.Idx(.offset+1))
	return 
}

func ( *baseCompiledExpr) (func(), func(), bool, bool) {
	.c.throwSyntaxError(.offset, "Not a valid left-value expression")
}

func ( *baseCompiledExpr) () {
	if .offset >= 0 {
		.c.p.addSrcMap(.offset)
	}
}

func ( *constantExpr) ( bool) {
	if  {
		.addSrcMap()
		.c.emitLiteralValue(.val)
	}
}

func ( *compiledIdentifierExpr) ( bool) {
	.addSrcMap()
	if ,  := .c.scope.lookupName(.name);  {
		.c.assert( != nil, .offset, "No dynamics and not found")
		if  {
			.emitGet()
		} else {
			.emitGetP()
		}
	} else {
		if  != nil {
			.emitGetVar(false)
		} else {
			.c.emit(loadDynamic(.name))
		}
		if ! {
			.c.emit(pop)
		}
	}
}

func ( *compiledIdentifierExpr) () {
	.addSrcMap()
	if ,  := .c.scope.lookupName(.name);  {
		.c.assert( != nil, .offset, "No dynamics and not found")
		.emitGet()
	} else {
		if  != nil {
			.emitGetVar(false)
		} else {
			.c.emit(loadDynamicRef(.name))
		}
	}
}

func ( *compiledIdentifierExpr) () {
	.addSrcMap()
	if ,  := .c.scope.lookupName(.name);  {
		.c.assert( != nil, .offset, "No dynamics and not found")
		.c.emit(loadUndef)
		.emitGet()
	} else {
		if  != nil {
			.emitGetVar(true)
		} else {
			.c.emit(loadDynamicCallee(.name))
		}
	}
}

func ( *compiledIdentifierExpr) ( bool,  func( bool)) {
	.addSrcMap()
	 := .c

	if ,  := .scope.lookupName(.name);  {
		if .scope.strict {
			.checkIdentifierLName(.name, .offset)
		}
		(false)
		if  != nil {
			if  {
				.emitSet()
			} else {
				.emitSetP()
			}
		} else {
			if .scope.strict {
				.emit(setGlobalStrict(.name))
			} else {
				.emit(setGlobal(.name))
			}
			if ! {
				.emit(pop)
			}
		}
	} else {
		.emitVarRef(.name, .offset, )
		(true)
		if  {
			.emit(putValue)
		} else {
			.emit(putValueP)
		}
	}
}

func ( *compiledIdentifierExpr) ( compiledExpr,  bool) {
	.emitVarSetter1(, func(bool) {
		.c.emitNamedOrConst(, .name)
	})
}

func ( *compiler) ( unistring.String,  int,  *binding) {
	if .scope.strict {
		.checkIdentifierLName(, )
	}

	if  != nil {
		.emitResolveVar(.scope.strict)
	} else {
		if .scope.strict {
			.emit(resolveVar1Strict())
		} else {
			.emit(resolveVar1())
		}
	}
}

func ( *compiledIdentifierExpr) () {
	,  := .c.scope.lookupName(.name)
	.c.emitVarRef(.name, .offset, )
}

func ( *compiledIdentifierExpr) ( compiledExpr,  bool) {
	.emitVarSetter(, )
}

func ( *compiledIdentifierExpr) (,  func(), ,  bool) {
	if  {
		.emitVarSetter1(true, func( bool) {
			.c.emit(loadUndef)
			if  {
				.c.emit(getValue)
			} else {
				.emitGetter(true)
			}
			if  != nil {
				()
			}
			if ! {
				()
			}
			.c.emit(rdupN(1))
			if  {
				()
			}
		})
		.c.emit(pop)
	} else {
		.emitVarSetter1(false, func( bool) {
			if  {
				.c.emit(getValue)
			} else {
				.emitGetter(true)
			}
			()
		})
	}
}

func ( *compiledIdentifierExpr) () compiledExpr {
	if .c.scope.strict {
		.c.throwSyntaxError(.offset, "Delete of an unqualified identifier in strict mode")
		panic("Unreachable")
	}
	if ,  := .c.scope.lookupName(.name);  {
		if  == nil {
			 := &deleteGlobalExpr{
				name: .name,
			}
			.init(.c, file.Idx(0))
			return 
		}
	} else {
		if  == nil {
			 := &deleteVarExpr{
				name: .name,
			}
			.init(.c, file.Idx(.offset+1))
			return 
		}
	}
	 := &compiledLiteral{
		val: valueFalse,
	}
	.init(.c, file.Idx(.offset+1))
	return 
}

type compiledSuperDotExpr struct {
	baseCompiledExpr
	name unistring.String
}

func ( *compiledSuperDotExpr) ( bool) {
	.c.emitLoadThis()
	.c.emit(loadSuper)
	.addSrcMap()
	.c.emit(getPropRecv(.name))
	if ! {
		.c.emit(pop)
	}
}

func ( *compiledSuperDotExpr) ( compiledExpr,  bool) {
	.c.emitLoadThis()
	.c.emit(loadSuper)
	.emitGetter(true)
	.addSrcMap()
	if  {
		if .c.scope.strict {
			.c.emit(setPropRecvStrict(.name))
		} else {
			.c.emit(setPropRecv(.name))
		}
	} else {
		if .c.scope.strict {
			.c.emit(setPropRecvStrictP(.name))
		} else {
			.c.emit(setPropRecvP(.name))
		}
	}
}

func ( *compiledSuperDotExpr) (,  func(), ,  bool) {
	if ! {
		.c.emitLoadThis()
		.c.emit(loadSuper, dupLast(2), getPropRecv(.name))
		()
		.addSrcMap()
		if .c.scope.strict {
			.c.emit(setPropRecvStrictP(.name))
		} else {
			.c.emit(setPropRecvP(.name))
		}
	} else {
		if ! {
			.c.emitLoadThis()
			.c.emit(loadSuper, dupLast(2), getPropRecv(.name))
			if  != nil {
				()
			}
			()
			.addSrcMap()
			if .c.scope.strict {
				.c.emit(setPropRecvStrict(.name))
			} else {
				.c.emit(setPropRecv(.name))
			}
		} else {
			.c.emit(loadUndef)
			.c.emitLoadThis()
			.c.emit(loadSuper, dupLast(2), getPropRecv(.name))
			if  != nil {
				()
			}
			.c.emit(rdupN(3))
			()
			.addSrcMap()
			if .c.scope.strict {
				.c.emit(setPropRecvStrictP(.name))
			} else {
				.c.emit(setPropRecvP(.name))
			}
		}
	}
}

func ( *compiledSuperDotExpr) () {
	.c.emitLoadThis()
	.c.emit(loadSuper)
	if .c.scope.strict {
		.c.emit(getPropRefRecvStrict(.name))
	} else {
		.c.emit(getPropRefRecv(.name))
	}
}

func ( *compiledSuperDotExpr) () compiledExpr {
	return .c.superDeleteError(.offset)
}

type compiledDotExpr struct {
	baseCompiledExpr
	left compiledExpr
	name unistring.String
}

type compiledPrivateDotExpr struct {
	baseCompiledExpr
	left compiledExpr
	name unistring.String
}

func ( *compiler) ( file.Idx) {
	if  := .scope.nearestThis();  != nil {
		switch .funcType {
		case funcMethod, funcClsInit, funcCtor, funcDerivedCtor:
			return
		}
	}
	.throwSyntaxError(int()-1, "'super' keyword unexpected here")
	panic("unreachable")
}

func ( *compiler) ( *ast.DotExpression) compiledExpr {
	if ,  := .Left.(*ast.SuperExpression);  {
		.checkSuperBase(.Idx)
		 := &compiledSuperDotExpr{
			name: .Identifier.Name,
		}
		.init(, .Identifier.Idx)
		return 
	}

	 := &compiledDotExpr{
		left: .compileExpression(.Left),
		name: .Identifier.Name,
	}
	.init(, .Identifier.Idx)
	return 
}

func ( *compiler) ( *ast.PrivateDotExpression) compiledExpr {
	 := &compiledPrivateDotExpr{
		left: .compileExpression(.Left),
		name: .Identifier.Name,
	}
	.init(, .Identifier.Idx)
	return 
}

func ( *compiledPrivateDotExpr) ( *resolvedPrivateName,  *privateId) {
	if  != nil {
		.c.emit((*getPrivatePropRes)())
	} else {
		.c.emit((*getPrivatePropId)())
	}
}

func ( *compiledPrivateDotExpr) ( *resolvedPrivateName,  *privateId) {
	if  != nil {
		.c.emit((*setPrivatePropRes)())
	} else {
		.c.emit((*setPrivatePropId)())
	}
}

func ( *compiledPrivateDotExpr) ( *resolvedPrivateName,  *privateId) {
	if  != nil {
		.c.emit((*setPrivatePropResP)())
	} else {
		.c.emit((*setPrivatePropIdP)())
	}
}

func ( *compiledPrivateDotExpr) ( bool) {
	.left.emitGetter(true)
	.addSrcMap()
	,  := .c.resolvePrivateName(.name, .offset)
	._emitGetter(, )
	if ! {
		.c.emit(pop)
	}
}

func ( *compiledPrivateDotExpr) ( compiledExpr,  bool) {
	,  := .c.resolvePrivateName(.name, .offset)
	.left.emitGetter(true)
	.emitGetter(true)
	.addSrcMap()
	if  {
		._emitSetter(, )
	} else {
		._emitSetterP(, )
	}
}

func ( *compiledPrivateDotExpr) (,  func(), ,  bool) {
	,  := .c.resolvePrivateName(.name, .offset)
	if ! {
		.left.emitGetter(true)
		.c.emit(dup)
		._emitGetter(, )
		()
		.addSrcMap()
		._emitSetterP(, )
	} else {
		if ! {
			.left.emitGetter(true)
			.c.emit(dup)
			._emitGetter(, )
			if  != nil {
				()
			}
			()
			.addSrcMap()
			._emitSetter(, )
		} else {
			.c.emit(loadUndef)
			.left.emitGetter(true)
			.c.emit(dup)
			._emitGetter(, )
			if  != nil {
				()
			}
			.c.emit(rdupN(2))
			()
			.addSrcMap()
			._emitSetterP(, )
		}
	}
}

func ( *compiledPrivateDotExpr) () compiledExpr {
	.c.throwSyntaxError(.offset, "Private fields can not be deleted")
	panic("unreachable")
}

func ( *compiledPrivateDotExpr) () {
	.left.emitGetter(true)
	,  := .c.resolvePrivateName(.name, .offset)
	if  != nil {
		.c.emit((*getPrivateRefRes)())
	} else {
		.c.emit((*getPrivateRefId)())
	}
}

type compiledSuperBracketExpr struct {
	baseCompiledExpr
	member compiledExpr
}

func ( *compiledSuperBracketExpr) ( bool) {
	.c.emitLoadThis()
	.member.emitGetter(true)
	.c.emit(loadSuper)
	.addSrcMap()
	.c.emit(getElemRecv)
	if ! {
		.c.emit(pop)
	}
}

func ( *compiledSuperBracketExpr) ( compiledExpr,  bool) {
	.c.emitLoadThis()
	.member.emitGetter(true)
	.c.emit(loadSuper)
	.emitGetter(true)
	.addSrcMap()
	if  {
		if .c.scope.strict {
			.c.emit(setElemRecvStrict)
		} else {
			.c.emit(setElemRecv)
		}
	} else {
		if .c.scope.strict {
			.c.emit(setElemRecvStrictP)
		} else {
			.c.emit(setElemRecvP)
		}
	}
}

func ( *compiledSuperBracketExpr) (,  func(), ,  bool) {
	if ! {
		.c.emitLoadThis()
		.member.emitGetter(true)
		.c.emit(loadSuper, dupLast(3), getElemRecv)
		()
		.addSrcMap()
		if .c.scope.strict {
			.c.emit(setElemRecvStrictP)
		} else {
			.c.emit(setElemRecvP)
		}
	} else {
		if ! {
			.c.emitLoadThis()
			.member.emitGetter(true)
			.c.emit(loadSuper, dupLast(3), getElemRecv)
			if  != nil {
				()
			}
			()
			.addSrcMap()
			if .c.scope.strict {
				.c.emit(setElemRecvStrict)
			} else {
				.c.emit(setElemRecv)
			}
		} else {
			.c.emit(loadUndef)
			.c.emitLoadThis()
			.member.emitGetter(true)
			.c.emit(loadSuper, dupLast(3), getElemRecv)
			if  != nil {
				()
			}
			.c.emit(rdupN(4))
			()
			.addSrcMap()
			if .c.scope.strict {
				.c.emit(setElemRecvStrictP)
			} else {
				.c.emit(setElemRecvP)
			}
		}
	}
}

func ( *compiledSuperBracketExpr) () {
	.c.emitLoadThis()
	.member.emitGetter(true)
	.c.emit(loadSuper)
	if .c.scope.strict {
		.c.emit(getElemRefRecvStrict)
	} else {
		.c.emit(getElemRefRecv)
	}
}

func ( *compiler) ( int) compiledExpr {
	return .compileEmitterExpr(func() {
		.emit(throwConst{referenceError("Unsupported reference to 'super'")})
	}, file.Idx(+1))
}

func ( *compiledSuperBracketExpr) () compiledExpr {
	return .c.superDeleteError(.offset)
}

func ( *compiler) ( compiledExpr) (unistring.String, bool) {
	if .constant() {
		if ,  := .evalConst();  == nil {
			if ,  := .(String);  {
				return .string(), true
			}
		}
	}
	return "", false
}

func ( *compiler) ( *ast.BracketExpression) compiledExpr {
	if ,  := .Left.(*ast.SuperExpression);  {
		.checkSuperBase(.Idx)
		 := .compileExpression(.Member)
		if ,  := .checkConstantString();  {
			 := &compiledSuperDotExpr{
				name: ,
			}
			.init(, .LeftBracket)
			return 
		}

		 := &compiledSuperBracketExpr{
			member: ,
		}
		.init(, .LeftBracket)
		return 
	}

	 := .compileExpression(.Left)
	 := .compileExpression(.Member)
	if ,  := .checkConstantString();  {
		 := &compiledDotExpr{
			left: ,
			name: ,
		}
		.init(, .LeftBracket)
		return 
	}

	 := &compiledBracketExpr{
		left:   ,
		member: ,
	}
	.init(, .LeftBracket)
	return 
}

func ( *compiledDotExpr) ( bool) {
	.left.emitGetter(true)
	.addSrcMap()
	.c.emit(getProp(.name))
	if ! {
		.c.emit(pop)
	}
}

func ( *compiledDotExpr) () {
	.left.emitGetter(true)
	if .c.scope.strict {
		.c.emit(getPropRefStrict(.name))
	} else {
		.c.emit(getPropRef(.name))
	}
}

func ( *compiledDotExpr) ( compiledExpr,  bool) {
	.left.emitGetter(true)
	.emitGetter(true)
	.addSrcMap()
	if .c.scope.strict {
		if  {
			.c.emit(setPropStrict(.name))
		} else {
			.c.emit(setPropStrictP(.name))
		}
	} else {
		if  {
			.c.emit(setProp(.name))
		} else {
			.c.emit(setPropP(.name))
		}
	}
}

func ( *compiledDotExpr) (,  func(), ,  bool) {
	if ! {
		.left.emitGetter(true)
		.c.emit(dup)
		.c.emit(getProp(.name))
		()
		.addSrcMap()
		if .c.scope.strict {
			.c.emit(setPropStrictP(.name))
		} else {
			.c.emit(setPropP(.name))
		}
	} else {
		if ! {
			.left.emitGetter(true)
			.c.emit(dup)
			.c.emit(getProp(.name))
			if  != nil {
				()
			}
			()
			.addSrcMap()
			if .c.scope.strict {
				.c.emit(setPropStrict(.name))
			} else {
				.c.emit(setProp(.name))
			}
		} else {
			.c.emit(loadUndef)
			.left.emitGetter(true)
			.c.emit(dup)
			.c.emit(getProp(.name))
			if  != nil {
				()
			}
			.c.emit(rdupN(2))
			()
			.addSrcMap()
			if .c.scope.strict {
				.c.emit(setPropStrictP(.name))
			} else {
				.c.emit(setPropP(.name))
			}
		}
	}
}

func ( *compiledDotExpr) () compiledExpr {
	 := &deletePropExpr{
		left: .left,
		name: .name,
	}
	.init(.c, file.Idx(.offset)+1)
	return 
}

func ( *compiledBracketExpr) ( bool) {
	.left.emitGetter(true)
	.member.emitGetter(true)
	.addSrcMap()
	.c.emit(getElem)
	if ! {
		.c.emit(pop)
	}
}

func ( *compiledBracketExpr) () {
	.left.emitGetter(true)
	.member.emitGetter(true)
	if .c.scope.strict {
		.c.emit(getElemRefStrict)
	} else {
		.c.emit(getElemRef)
	}
}

func ( *compiledBracketExpr) ( compiledExpr,  bool) {
	.left.emitGetter(true)
	.member.emitGetter(true)
	.emitGetter(true)
	.addSrcMap()
	if .c.scope.strict {
		if  {
			.c.emit(setElemStrict)
		} else {
			.c.emit(setElemStrictP)
		}
	} else {
		if  {
			.c.emit(setElem)
		} else {
			.c.emit(setElemP)
		}
	}
}

func ( *compiledBracketExpr) (,  func(), ,  bool) {
	if ! {
		.left.emitGetter(true)
		.member.emitGetter(true)
		.c.emit(dupLast(2), getElem)
		()
		.addSrcMap()
		if .c.scope.strict {
			.c.emit(setElemStrict, pop)
		} else {
			.c.emit(setElem, pop)
		}
	} else {
		if ! {
			.left.emitGetter(true)
			.member.emitGetter(true)
			.c.emit(dupLast(2), getElem)
			if  != nil {
				()
			}
			()
			.addSrcMap()
			if .c.scope.strict {
				.c.emit(setElemStrict)
			} else {
				.c.emit(setElem)
			}
		} else {
			.c.emit(loadUndef)
			.left.emitGetter(true)
			.member.emitGetter(true)
			.c.emit(dupLast(2), getElem)
			if  != nil {
				()
			}
			.c.emit(rdupN(3))
			()
			.addSrcMap()
			if .c.scope.strict {
				.c.emit(setElemStrict, pop)
			} else {
				.c.emit(setElem, pop)
			}
		}
	}
}

func ( *compiledBracketExpr) () compiledExpr {
	 := &deleteElemExpr{
		left:   .left,
		member: .member,
	}
	.init(.c, file.Idx(.offset)+1)
	return 
}

func ( *deleteElemExpr) ( bool) {
	.left.emitGetter(true)
	.member.emitGetter(true)
	.addSrcMap()
	if .c.scope.strict {
		.c.emit(deleteElemStrict)
	} else {
		.c.emit(deleteElem)
	}
	if ! {
		.c.emit(pop)
	}
}

func ( *deletePropExpr) ( bool) {
	.left.emitGetter(true)
	.addSrcMap()
	if .c.scope.strict {
		.c.emit(deletePropStrict(.name))
	} else {
		.c.emit(deleteProp(.name))
	}
	if ! {
		.c.emit(pop)
	}
}

func ( *deleteVarExpr) ( bool) {
	/*if e.c.scope.strict {
		e.c.throwSyntaxError(e.offset, "Delete of an unqualified identifier in strict mode")
		return
	}*/
	.c.emit(deleteVar(.name))
	if ! {
		.c.emit(pop)
	}
}

func ( *deleteGlobalExpr) ( bool) {
	/*if e.c.scope.strict {
		e.c.throwSyntaxError(e.offset, "Delete of an unqualified identifier in strict mode")
		return
	}*/

	.c.emit(deleteGlobal(.name))
	if ! {
		.c.emit(pop)
	}
}

func ( *compiledAssignExpr) ( bool) {
	switch .operator {
	case token.ASSIGN:
		.left.emitSetter(.right, )
	case token.PLUS:
		.left.emitUnary(nil, func() {
			.right.emitGetter(true)
			.c.emit(add)
		}, false, )
	case token.MINUS:
		.left.emitUnary(nil, func() {
			.right.emitGetter(true)
			.c.emit(sub)
		}, false, )
	case token.MULTIPLY:
		.left.emitUnary(nil, func() {
			.right.emitGetter(true)
			.c.emit(mul)
		}, false, )
	case token.EXPONENT:
		.left.emitUnary(nil, func() {
			.right.emitGetter(true)
			.c.emit(exp)
		}, false, )
	case token.SLASH:
		.left.emitUnary(nil, func() {
			.right.emitGetter(true)
			.c.emit(div)
		}, false, )
	case token.REMAINDER:
		.left.emitUnary(nil, func() {
			.right.emitGetter(true)
			.c.emit(mod)
		}, false, )
	case token.OR:
		.left.emitUnary(nil, func() {
			.right.emitGetter(true)
			.c.emit(or)
		}, false, )
	case token.AND:
		.left.emitUnary(nil, func() {
			.right.emitGetter(true)
			.c.emit(and)
		}, false, )
	case token.EXCLUSIVE_OR:
		.left.emitUnary(nil, func() {
			.right.emitGetter(true)
			.c.emit(xor)
		}, false, )
	case token.SHIFT_LEFT:
		.left.emitUnary(nil, func() {
			.right.emitGetter(true)
			.c.emit(sal)
		}, false, )
	case token.SHIFT_RIGHT:
		.left.emitUnary(nil, func() {
			.right.emitGetter(true)
			.c.emit(sar)
		}, false, )
	case token.UNSIGNED_SHIFT_RIGHT:
		.left.emitUnary(nil, func() {
			.right.emitGetter(true)
			.c.emit(shr)
		}, false, )
	default:
		.c.assert(false, .offset, "Unknown assign operator: %s", .operator.String())
		panic("unreachable")
	}
}

func ( *compiledLiteral) ( bool) {
	if  {
		.c.emitLiteralValue(.val)
	}
}

func ( *compiledLiteral) () bool {
	return true
}

func ( *compiledTemplateLiteral) ( bool) {
	if .tag == nil {
		if len(.elements) == 0 {
			.c.emitLiteralString(stringEmpty)
		} else {
			 := .elements[len(.elements)-1].Parsed
			if len(.elements) == 1 {
				.c.emitLiteralString(stringValueFromRaw())
			} else {
				 := 0
				if  := .elements[0].Parsed;  != "" {
					.c.emitLiteralString(stringValueFromRaw())
					++
				}
				.expressions[0].emitGetter(true)
				.c.emit(_toString{})
				++
				for  := 1;  < len(.elements)-1; ++ {
					if  := .elements[].Parsed;  != "" {
						.c.emitLiteralString(stringValueFromRaw())
						++
					}
					.expressions[].emitGetter(true)
					.c.emit(_toString{})
					++
				}
				if  != "" {
					.c.emitLiteralString(stringValueFromRaw())
					++
				}
				.c.emit(concatStrings())
			}
		}
	} else {
		 := make([]Value, len(.elements))
		 := make([]Value, len(.elements))
		for ,  := range .elements {
			[] = &valueProperty{
				enumerable: true,
				value:      newStringValue(.Literal),
			}
			var  Value
			if .Valid {
				 = stringValueFromRaw(.Parsed)
			} else {
				 = _undefined
			}
			[] = &valueProperty{
				enumerable: true,
				value:      ,
			}
		}
		.c.emitCallee(.tag)
		.c.emit(&getTaggedTmplObject{
			raw:    ,
			cooked: ,
		})
		for ,  := range .expressions {
			.emitGetter(true)
		}
		.c.emit(call(len(.expressions) + 1))
	}
	if ! {
		.c.emit(pop)
	}
}

func ( *compiler) ( unistring.String,  int) (*binding, bool) {
	if .scope.strict {
		.checkIdentifierName(, )
		.checkIdentifierLName(, )
	}
	return .scope.bindNameShadow()
}

func ( *compiler) ( unistring.String,  int) {
	if ,  := .compileParameterBindingIdentifier(, ); ! {
		.throwSyntaxError(, "Duplicate parameter name not allowed in this context")
	}
}

func ( *compiler) ( ast.Expression) {
	.createBindings(, .compileParameterPatternIdBinding)
}

func ( *compiler) (,  int) ( []instruction) {
	if .codeScratchpad != nil {
		 = .codeScratchpad
		.codeScratchpad = nil
	}
	if cap() <  {
		 = make([]instruction, , )
	} else {
		 = [:]
	}
	return
}

func ( *compiledFunctionLiteral) () ( *Program,  unistring.String,  int,  bool) {
	.c.assert(.typ != funcNone, .offset, "compiledFunctionLiteral.typ is not set")

	 := .c.p
	 := 8 // enter, boxThis, loadStack(0), initThis, createArgs, set, loadCallee, init
	.c.p = &Program{
		src:    .c.p.src,
		code:   .c.newCode(, 16),
		srcMap: []srcMapItem{{srcPos: .offset}},
	}
	.c.newScope()
	 := .c.scope
	.funcType = .typ

	if .name != nil {
		 = .name.Name
	} else {
		 = .lhsName
	}

	if  != "" {
		.c.p.funcName = 
	}
	 := .c.block
	defer func() {
		.c.block = 
	}()

	.c.block = &block{
		typ: blockScope,
	}

	if !.strict {
		.strict = .strict != nil
	}

	 := false
	 := false
	 := -1

	if .parameterList.Rest != nil {
		 = true // strictly speaking not, but we need to activate all the checks
	}

	// First, make sure that the first bindings correspond to the formal parameters
	for ,  := range .parameterList.List {
		switch tgt := .Target.(type) {
		case *ast.Identifier:
			 := int(.Idx) - 1
			,  := .c.compileParameterBindingIdentifier(.Name, )
			if ! {
				 = 
			}
			.isArg = true
		case ast.Pattern:
			 := .addBinding(int(.Idx0()) - 1)
			.isArg = true
			 = true
		default:
			.c.throwSyntaxError(int(.Idx0())-1, "Unsupported BindingElement type: %T", )
			return
		}
		if .Initializer != nil {
			 = true
		}

		if  >= 0 && ( ||  || .strict || .typ == funcArrow || .typ == funcMethod) {
			.c.throwSyntaxError(, "Duplicate parameter name not allowed in this context")
			return
		}

		if ( || ) && .strict != nil {
			.c.throwSyntaxError(int(.strict.Idx)-1, "Illegal 'use strict' directive in function with non-simple parameter list")
			return
		}

		if ! {
			++
		}
	}

	var  *binding
	if .typ != funcArrow {
		 = .createThisBinding()
	}

	// create pattern bindings
	if  {
		for ,  := range .parameterList.List {
			switch tgt := .Target.(type) {
			case *ast.Identifier:
				// we already created those in the previous loop, skipping
			default:
				.c.compileParameterPatternBinding()
			}
		}
		if  := .parameterList.Rest;  != nil {
			.c.compileParameterPatternBinding()
		}
	}

	 := len(.parameterList.List)

	.numArgs = 
	 := .body
	 := .c.extractFunctions()
	var  *binding

	 := -1
	 := -1
	 := -1

	if  ||  {
		if .isExpr && .name != nil {
			if ,  := .bindNameLexical(.name.Name, false, 0);  {
				.isConst = true
				 = 
			}
		}
		for ,  := range .parameterList.List {
			if ,  := .Target.(ast.Pattern);  {
				 := 
				.c.compilePatternInitExpr(func() {
					if  == -1 {
						.bindings[].emitGet()
					} else {
						.c.emit(loadStackLex(- - 1))
					}
				}, .Initializer, .Target.Idx0()).emitGetter(true)
				.c.emitPattern(, func(,  compiledExpr) {
					.c.emitPatternLexicalAssign(, )
				}, false)
			} else if .Initializer != nil {
				 := len(.c.p.code)
				.c.emit(nil)
				 := len(.c.p.code)
				.c.emit(nil)
				.c.emitExpr(.c.compileExpression(.Initializer), true)
				if  == -1 && (.isDynamic() || .bindings[].useCount() > 0) {
					 = 
				}
				if  == -1 {
					.bindings[].emitGetAt()
				} else {
					.c.p.code[] = loadStackLex(- - 1)
				}
				.bindings[].emitInitP()
				.c.p.code[] = jdefP(len(.c.p.code) - )
			} else {
				if  == -1 && .bindings[].useCount() > 0 {
					 = 
				}
				if  != -1 {
					.c.emit(loadStackLex(- - 1))
					.bindings[].emitInitP()
				}
			}
		}
		if  := .parameterList.Rest;  != nil {
			.c.emitAssign(, .c.compileEmitterExpr(
				func() {
					 = len(.c.p.code)
					.c.emit(createArgsRestStack())
				}, .Idx0()),
				func(,  compiledExpr) {
					.c.emitPatternLexicalAssign(, )
				})
		}
		if  != -1 {
			for ,  := range .bindings {
				.inStash = true
			}
			.argsInStash = true
			.needStash = true
		}

		.c.newBlockScope()
		 := .c.scope
		.variable = true
		 = len(.c.p.code)
		.c.emit(nil)
		.c.compileDeclList(.declarationList, false)
		.c.createFunctionBindings()
		.c.compileLexicalDeclarationsFuncBody(, )
		for ,  := range .bindings {
			if .isVar {
				if  := .boundNames[.name];  != nil &&  !=  {
					.emitGet()
					.emitSetP()
				}
			}
		}
	} else {
		// To avoid triggering variable conflict when binding from non-strict direct eval().
		// Parameters are supposed to be in a parent scope, hence no conflict.
		for ,  := range .bindings[:] {
			.isVar = true
		}
		.c.compileDeclList(.declarationList, true)
		.c.createFunctionBindings()
		.c.compileLexicalDeclarations(, true)
		if .isExpr && .name != nil {
			if ,  := .bindNameLexical(.name.Name, false, 0);  {
				.isConst = true
				 = 
			}
		}
		if  != nil {
			.c.emit(loadCallee)
			.emitInitP()
		}
	}

	.c.compileFunctions()
	if .isGenerator {
		.c.emit(yieldEmpty)
	}
	.c.compileStatements(, false)

	var  ast.Statement
	if  := len();  > 0 {
		 = [-1]
	}
	if ,  := .(*ast.ReturnStatement); ! {
		if .typ == funcDerivedCtor {
			.c.emit(loadUndef)
			.markAccessPoint()
			.c.emit(ret)
		} else {
			.c.emit(loadUndef, ret)
		}
	}

	 := 0
	 := .c.p.code

	if .isDynamic() && !.argsInStash {
		.moveArgsToStash()
	}

	if .argsNeeded || .isDynamic() && .typ != funcArrow && .typ != funcClsInit {
		if .typ == funcClsInit {
			.c.throwSyntaxError(.offset, "'arguments' is not allowed in class field initializer or static initialization block")
		}
		,  := .bindNameLexical("arguments", false, 0)
		if  || .isVar {
			if !.argsInStash {
				.moveArgsToStash()
			}
			if .strict {
				.isConst = true
			} else {
				.isVar = .c.scope.isFunction()
			}
			 :=  - 2
			 += 2
			if .strict ||  ||  {
				[] = createArgsUnmapped()
			} else {
				[] = createArgsMapped()
			}
			++
			.emitInitPAtScope(, )
		}
	}

	if  != nil {
		if !.isDynamic() && .useCount() == 0 {
			.deleteBinding()
			 = nil
		} else {
			++
			.emitInitPAtScope(, -)
			++
			[-] = loadCallee
		}
	}

	if  != nil {
		if !.isDynamic() && .useCount() == 0 {
			.deleteBinding()
			 = nil
		} else {
			if .inStash || .isDynamic() {
				++
				.emitInitAtScope(, -)
			}
		}
	}

	,  := .finaliseVarAlloc(0)

	if  != nil && .inStash && (!.argsInStash ||  > 0) {
		++
		[-] = loadStack(0)
	} // otherwise, 'this' will be at stack[sp-1], no need to load

	if !.strict &&  != nil {
		++
		[-] = boxThis
	}
	++
	 =  - 
	var  instruction
	if  > 0 || .argsInStash {
		if  == -1 {
			 := enterFunc{
				numArgs:     uint32(),
				argsToStash: .argsInStash,
				stashSize:   uint32(),
				stackSize:   uint32(),
				extensible:  .dynamic,
				funcType:    .typ,
			}
			if .isDynamic() {
				.names = .makeNamesMap()
			}
			 = &
			if  != -1 {
				 := &enterFuncBody{
					extensible: .c.scope.dynamic,
					funcType:   .typ,
				}
				.c.updateEnterBlock(&.enterBlock)
				.c.p.code[] = 
			}
		} else {
			 := enterFunc1{
				stashSize:  uint32(),
				numArgs:    uint32(),
				argsToCopy: uint32(),
				extensible: .dynamic,
				funcType:   .typ,
			}
			if .isDynamic() {
				.names = .makeNamesMap()
			}
			 = &
			if  != -1 {
				 := &enterFuncBody{
					adjustStack: true,
					extensible:  .c.scope.dynamic,
					funcType:    .typ,
				}
				.c.updateEnterBlock(&.enterBlock)
				.c.p.code[] = 
			}
		}
		if  != -1 && .argsInStash {
			.c.p.code[] = createArgsRestStash
		}
	} else {
		 = &enterFuncStashless{
			stackSize: uint32(),
			args:      uint32(),
		}
		if  != -1 {
			 := &enterFuncBody{
				extensible: .c.scope.dynamic,
				funcType:   .typ,
			}
			.c.updateEnterBlock(&.enterBlock)
			.c.p.code[] = 
		}
	}
	[] = 
	.c.p.srcMap[0].pc = 
	.trimCode()

	 = .strict
	 = .c.p
	// e.c.p.dumpCode()
	if  != -1 {
		.c.popScope()
	}
	.c.popScope()
	.c.p = 

	return
}

func ( *compiledFunctionLiteral) ( bool) {
	, , ,  := .compile()
	switch .typ {
	case funcArrow:
		if .isAsync {
			.c.emit(&newAsyncArrowFunc{newArrowFunc: newArrowFunc{newFunc: newFunc{prg: , length: , name: , source: .source, strict: }}})
		} else {
			.c.emit(&newArrowFunc{newFunc: newFunc{prg: , length: , name: , source: .source, strict: }})
		}
	case funcMethod, funcClsInit:
		if .isAsync {
			.c.emit(&newAsyncMethod{newMethod: newMethod{newFunc: newFunc{prg: , length: , name: , source: .source, strict: }, homeObjOffset: .homeObjOffset}})
		} else {
			if .isGenerator {
				.c.emit(&newGeneratorMethod{newMethod: newMethod{newFunc: newFunc{prg: , length: , name: , source: .source, strict: }, homeObjOffset: .homeObjOffset}})
			} else {
				.c.emit(&newMethod{newFunc: newFunc{prg: , length: , name: , source: .source, strict: }, homeObjOffset: .homeObjOffset})
			}
		}
	case funcRegular:
		if .isAsync {
			.c.emit(&newAsyncFunc{newFunc: newFunc{prg: , length: , name: , source: .source, strict: }})
		} else {
			if .isGenerator {
				.c.emit(&newGeneratorFunc{newFunc: newFunc{prg: , length: , name: , source: .source, strict: }})
			} else {
				.c.emit(&newFunc{prg: , length: , name: , source: .source, strict: })
			}
		}
	default:
		.c.throwSyntaxError(.offset, "Unsupported func type: %v", .typ)
	}
	if ! {
		.c.emit(pop)
	}
}

func ( *compiler) ( *ast.FunctionLiteral,  bool) *compiledFunctionLiteral {
	 := .isStrictStatement(.Body)
	if .Name != nil && (.scope.strict ||  != nil) {
		.checkIdentifierName(.Name.Name, int(.Name.Idx)-1)
		.checkIdentifierLName(.Name.Name, int(.Name.Idx)-1)
	}
	if .Async && .Generator {
		.throwSyntaxError(int(.Function)-1, "Async generators are not supported yet")
	}
	 := &compiledFunctionLiteral{
		name:            .Name,
		parameterList:   .ParameterList,
		body:            .Body.List,
		source:          .Source,
		declarationList: .DeclarationList,
		isExpr:          ,
		typ:             funcRegular,
		strict:          ,
		isAsync:         .Async,
		isGenerator:     .Generator,
	}
	.init(, .Idx0())
	return 
}

type compiledClassLiteral struct {
	baseCompiledExpr
	name       *ast.Identifier
	superClass compiledExpr
	body       []ast.ClassElement
	lhsName    unistring.String
	source     string
	isExpr     bool
}

func ( *compiler) ( ast.Expression) ( unistring.String,  bool) {
	 := .compileExpression()
	if .constant() {
		,  := .evalConst()
		if  == nil {
			return .string(), false
		}
	}
	.emitGetter(true)
	 = true
	return
}

func ( *compiledClassLiteral) ( ast.Expression) ( *privateName,  unistring.String,  bool) {
	if ,  := .(*ast.PrivateIdentifier);  {
		 = .c.classScope.getDeclaredPrivateId(.Name)
		 = privateIdString(.Name)
		return
	}
	,  = .c.processKey()
	return
}

type clsElement struct {
	key         unistring.String
	privateName *privateName
	initializer compiledExpr
	body        *compiledFunctionLiteral
	computed    bool
}

func ( *compiledClassLiteral) ( bool) {
	.c.newBlockScope()
	 := .c.scope
	.strict = true

	 := &enterBlock{}
	 := len(.c.p.code)
	.c.emit()
	.c.block = &block{
		typ:   blockScope,
		outer: .c.block,
	}
	var  *binding
	var  unistring.String
	if  := .name;  != nil {
		 = .Name
		 = .c.createLexicalIdBinding(, true, int(.Idx)-1)
	} else {
		 = .lhsName
	}

	var  *ast.MethodDefinition
	 := -1
	 := 0
	 := 0
	 := false
	 := &classScope{
		c:     .c,
		outer: .c.classScope,
	}

	for ,  := range .body {
		switch elt := .(type) {
		case *ast.ClassStaticBlock:
			if len(.Block.List) > 0 {
				++
			}
		case *ast.FieldDefinition:
			if ,  := .Key.(*ast.PrivateIdentifier);  {
				.declarePrivateId(.Name, ast.PropertyKindValue, .Static, int(.Idx)-1)
			}
			if .Static {
				++
			} else {
				++
			}
		case *ast.MethodDefinition:
			if !.Static {
				if ,  := .Key.(*ast.StringLiteral);  {
					if !.Computed && .Value == "constructor" {
						if  != nil {
							.c.throwSyntaxError(int(.Idx)-1, "A class may only have one constructor")
						}
						 = 
						 = 
						continue
					}
				}
			}
			if ,  := .Key.(*ast.PrivateIdentifier);  {
				.declarePrivateId(.Name, .Kind, .Static, int(.Idx)-1)
				if .Static {
					 = true
				}
			}
		default:
			.c.assert(false, int(.Idx0())-1, "Unsupported static element: %T", )
		}
	}

	var  *newStaticFieldInit
	if  > 0 ||  {
		 = &newStaticFieldInit{}
		.c.emit()
	}

	var  bool
	var  *newClass
	if  := .superClass;  != nil {
		 = true
		.emitGetter(true)
		 := &newDerivedClass{
			newClass: newClass{
				name:   ,
				source: .source,
			},
		}
		.addSrcMap()
		.c.emit()
		 = &.newClass
	} else {
		 = &newClass{
			name:   ,
			source: .source,
		}
		.addSrcMap()
		.c.emit()
	}

	.c.classScope = 

	if  != nil {
		.ctor, .length = .c.compileCtor(.Body, )
	}

	 := false

	 := make([]clsElement, 0, )
	 := make([]clsElement, 0, )

	// stack at this point:
	//
	// staticFieldInit (if staticsCount > 0 || hasStaticPrivateMethods)
	// prototype
	// class function
	// <- sp

	for ,  := range .body {
		if  ==  {
			continue
		}
		switch elt := .(type) {
		case *ast.ClassStaticBlock:
			if len(.Block.List) > 0 {
				 := .c.compileFunctionLiteral(&ast.FunctionLiteral{
					Function:        .Idx0(),
					ParameterList:   &ast.ParameterList{},
					Body:            .Block,
					Source:          .Source,
					DeclarationList: .DeclarationList,
				}, true)
				.typ = funcClsInit
				//f.lhsName = "<static_initializer>"
				.homeObjOffset = 1
				 = append(, clsElement{
					body: ,
				})
			}
		case *ast.FieldDefinition:
			, ,  := .processClassKey(.Key)
			var  clsElement
			if .Initializer != nil {
				.initializer = .c.compileExpression(.Initializer)
			}
			.computed = 
			if  {
				if .Static {
					if  {
						.c.emit(defineComputedKey(5))
					} else {
						.c.emit(defineComputedKey(4))
					}
				} else {
					if  {
						.c.emit(defineComputedKey(3))
					} else {
						.c.emit(defineComputedKey(2))
					}
				}
			} else {
				.privateName = 
				.key = 
			}
			if .Static {
				 = append(, )
			} else {
				 = append(, )
			}
		case *ast.MethodDefinition:
			if .Static {
				if  {
					.c.emit(pop)
					 = false
				}
			} else {
				if ! {
					.c.emit(dupN(1))
					 = true
				}
			}
			, ,  := .processClassKey(.Key)
			 := .c.compileFunctionLiteral(.Body, true)
			.typ = funcMethod
			if  {
				.c.emit(_toPropertyKey{})
				.homeObjOffset = 2
			} else {
				.homeObjOffset = 1
				.lhsName = 
			}
			.emitGetter(true)
			if  != nil {
				var  int
				if .Static {
					if  {
						/*
							staticInit
							proto
							cls
							proto
							method
							<- sp
						*/
						 = 5
					} else {
						/*
							staticInit
							proto
							cls
							method
							<- sp
						*/
						 = 4
					}
				} else {
					if  {
						 = 3
					} else {
						 = 2
					}
				}
				switch .Kind {
				case ast.PropertyKindGet:
					.c.emit(&definePrivateGetter{
						definePrivateMethod: definePrivateMethod{
							idx:          .idx,
							targetOffset: ,
						},
					})
				case ast.PropertyKindSet:
					.c.emit(&definePrivateSetter{
						definePrivateMethod: definePrivateMethod{
							idx:          .idx,
							targetOffset: ,
						},
					})
				default:
					.c.emit(&definePrivateMethod{
						idx:          .idx,
						targetOffset: ,
					})
				}
			} else if  {
				switch .Kind {
				case ast.PropertyKindGet:
					.c.emit(&defineGetter{})
				case ast.PropertyKindSet:
					.c.emit(&defineSetter{})
				default:
					.c.emit(&defineMethod{})
				}
			} else {
				switch .Kind {
				case ast.PropertyKindGet:
					.c.emit(&defineGetterKeyed{key: })
				case ast.PropertyKindSet:
					.c.emit(&defineSetterKeyed{key: })
				default:
					.c.emit(&defineMethodKeyed{key: })
				}
			}
		}
	}
	if  {
		.c.emit(pop)
	}

	if len() > 0 {
		.initFields = .compileFieldsAndStaticBlocks(, "<instance_members_initializer>")
	}
	if  != nil {
		if len() > 0 {
			.initFields = .compileFieldsAndStaticBlocks(, "<static_initializer>")
		}
	}

	 := .c.classScope.instanceEnv
	if .dynLookup {
		.privateMethods, .privateFields = .methods, .fields
	}
	.numPrivateMethods = uint32(len(.methods))
	.numPrivateFields = uint32(len(.fields))
	.hasPrivateEnv = len(.c.classScope.privateNames) > 0

	if ( != nil && .useCount() > 0) || .dynLookup {
		if  != nil {
			// Because this block may be in the middle of an expression, its initial stack position
			// cannot be known, and therefore it may not have any stack variables.
			// Note, because clsBinding would be accessed through a function, it should already be in stash,
			// this is just to make sure.
			.moveToStash()
			.emitInit()
		}
	} else {
		if  != nil {
			.deleteBinding()
			 = nil
		}
		.c.p.code[] = jump(1)
	}

	if  > 0 ||  {
		 := &initStaticElements{}
		.c.emit()
		 := .c.classScope.staticEnv
		.numPrivateFields = uint32(len(.fields))
		.numPrivateMethods = uint32(len(.methods))
		if .dynLookup {
			// These cannot be set on staticInit, because it is executed before ClassHeritage, and therefore
			// the VM's PrivateEnvironment is still not set.
			.privateFields = .fields
			.privateMethods = .methods
		}
	} else {
		.c.emit(endVariadic) // re-using as semantics match
	}

	if ! {
		.c.emit(pop)
	}

	if  != nil || .dynLookup {
		.c.leaveScopeBlock()
		.c.assert(.stackSize == 0, .offset, "enter.StackSize != 0 in compiledClassLiteral")
	} else {
		.c.block = .c.block.outer
	}
	if len(.c.classScope.privateNames) > 0 {
		.c.emit(popPrivateEnv{})
	}
	.c.classScope = .c.classScope.outer
	.c.popScope()
}

func ( *compiledClassLiteral) ( []clsElement,  unistring.String) *Program {
	 := .c.p
	 := .c.block
	defer func() {
		.c.p = 
		.c.block = 
	}()

	.c.block = &block{
		typ: blockScope,
	}

	.c.p = &Program{
		src:      .src,
		funcName: ,
		code:     .c.newCode(2, 16),
	}

	.c.newScope()
	 := .c.scope
	.funcType = funcClsInit
	 := .createThisBinding()

	 := 0
	for ,  := range  {
		if .body != nil {
			.c.emit(dup) // this
			.body.emitGetter(true)
			.body.addSrcMap()
			.c.emit(call(0), pop)
		} else {
			if .computed {
				.c.emit(loadComputedKey())
				++
			}
			if  := .initializer;  != nil {
				if !.computed {
					.c.emitNamedOrConst(, .key)
				} else {
					.c.emitExpr(, true)
				}
			} else {
				.c.emit(loadUndef)
			}
			if .privateName != nil {
				.c.emit(&definePrivateProp{
					idx: .privateName.idx,
				})
			} else if .computed {
				.c.emit(defineProp{})
			} else {
				.c.emit(definePropKeyed(.key))
			}
		}
	}
	//e.c.emit(halt)
	if .isDynamic() || .useCount() > 0 {
		if .isDynamic() || .inStash {
			.emitInitAt(1)
		}
	} else {
		.deleteBinding()
	}
	,  := .finaliseVarAlloc(0)
	.c.assert( == 0, .offset, "stackSize != 0 in initFields")
	if  > 0 {
		.c.assert( == 1, .offset, "stashSize != 1 in initFields")
		 := &enterFunc{
			stashSize: 1,
			funcType:  funcClsInit,
		}
		if .dynLookup {
			.names = .makeNamesMap()
		}
		.c.p.code[0] = 
		.trimCode(0)
	} else {
		.trimCode(2)
	}
	 := .c.p
	.c.popScope()
	return 
}

func ( *compiler) ( *ast.ClassLiteral,  bool) *compiledClassLiteral {
	if .Name != nil {
		.checkIdentifierLName(.Name.Name, int(.Name.Idx)-1)
	}
	 := &compiledClassLiteral{
		name:       .Name,
		superClass: .compileExpression(.SuperClass),
		body:       .Body,
		source:     .Source,
		isExpr:     ,
	}
	.init(, .Idx0())
	return 
}

func ( *compiler) ( *ast.FunctionLiteral,  bool) ( *Program,  int) {
	 := .compileFunctionLiteral(, true)
	if  {
		.typ = funcDerivedCtor
	} else {
		.typ = funcCtor
	}
	, _, , _ = .compile()
	return
}

func ( *compiler) ( *ast.ArrowFunctionLiteral) *compiledFunctionLiteral {
	var  *ast.StringLiteral
	var  []ast.Statement
	switch b := .Body.(type) {
	case *ast.BlockStatement:
		 = .isStrictStatement()
		 = .List
	case *ast.ExpressionBody:
		 = []ast.Statement{
			&ast.ReturnStatement{
				Argument: .Expression,
			},
		}
	default:
		.throwSyntaxError(int(.Idx0())-1, "Unsupported ConciseBody type: %T", )
	}
	 := &compiledFunctionLiteral{
		parameterList:   .ParameterList,
		body:            ,
		source:          .Source,
		declarationList: .DeclarationList,
		isExpr:          true,
		typ:             funcArrow,
		strict:          ,
		isAsync:         .Async,
	}
	.init(, .Idx0())
	return 
}

func ( *compiler) () {
	,  := .scope.lookupThis()
	if  != nil {
		.emitGet()
	} else {
		if  {
			.emit(getThisDynamic{})
		} else {
			.emit(loadGlobalObject)
		}
	}
}

func ( *compiledThisExpr) ( bool) {
	.addSrcMap()
	.c.emitLoadThis()
	if ! {
		.c.emit(pop)
	}
}

func ( *compiledSuperExpr) ( bool) {
	if  {
		.c.emit(loadSuper)
	}
}

func ( *compiledNewExpr) ( bool) {
	if .isVariadic {
		.c.emit(startVariadic)
	}
	.callee.emitGetter(true)
	for ,  := range .args {
		.emitGetter(true)
	}
	.addSrcMap()
	if .isVariadic {
		.c.emit(newVariadic, endVariadic)
	} else {
		.c.emit(_new(len(.args)))
	}
	if ! {
		.c.emit(pop)
	}
}

func ( *compiler) ( []ast.Expression) ( []compiledExpr,  bool) {
	 = make([]compiledExpr, len())
	for ,  := range  {
		if ,  := .(*ast.SpreadElement);  {
			[] = .compileSpreadCallArgument()
			 = true
		} else {
			[] = .compileExpression()
		}
	}
	return
}

func ( *compiler) ( *ast.NewExpression) compiledExpr {
	,  := .compileCallArgs(.ArgumentList)
	 := &compiledNewExpr{
		compiledCallExpr: compiledCallExpr{
			callee:     .compileExpression(.Callee),
			args:       ,
			isVariadic: ,
		},
	}
	.init(, .Idx0())
	return 
}

func ( *compiledNewTarget) ( bool) {
	if  := .c.scope.nearestThis();  == nil || .funcType == funcNone {
		.c.throwSyntaxError(.offset, "new.target expression is not allowed here")
	}
	if  {
		.addSrcMap()
		.c.emit(loadNewTarget)
	}
}

func ( *compiler) ( *ast.MetaProperty) compiledExpr {
	if .Meta.Name == "new" || .Property.Name != "target" {
		 := &compiledNewTarget{}
		.init(, .Idx0())
		return 
	}
	.throwSyntaxError(int(.Idx)-1, "Unsupported meta property: %s.%s", .Meta.Name, .Property.Name)
	return nil
}

func ( *compiledSequenceExpr) ( bool) {
	if len(.sequence) > 0 {
		for  := 0;  < len(.sequence)-1; ++ {
			.sequence[].emitGetter(false)
		}
		.sequence[len(.sequence)-1].emitGetter()
	}
}

func ( *compiler) ( *ast.SequenceExpression) compiledExpr {
	 := make([]compiledExpr, len(.Sequence))
	for ,  := range .Sequence {
		[] = .compileExpression()
	}
	 := &compiledSequenceExpr{
		sequence: ,
	}
	var  file.Idx
	if len(.Sequence) > 0 {
		 = .Idx0()
	}
	.init(, )
	return 
}

func ( *compiler) ( Value) {
	if ,  := .(*Object);  {
		 := nilSafe(.self.getStr("name", nil)).toString().String()
		switch  {
		case "TypeError", "RangeError":
			.emit(loadDynamic())
			 := .self.getStr("message", nil)
			if  != nil {
				.emitLiteralValue()
				.emit(_new(1))
			} else {
				.emit(_new(0))
			}
			.emit(throw)
			return
		}
	}
	.assert(false, 0, "unknown exception type thrown while evaluating constant expression: %s", .String())
	panic("unreachable")
}

func ( *compiler) ( compiledExpr,  bool) {
	,  := .evalConst()
	if  == nil {
		if  {
			.emitLiteralValue()
		}
	} else {
		.emitThrow(.val)
	}
}

func ( *compiler) ( compiledExpr) (Value, *Exception) {
	if ,  := .(*compiledLiteral);  {
		return .val, nil
	}
	if .evalVM == nil {
		.evalVM = New().vm
	}
	var  *Program
	 := false
	if .evalVM.prg == nil {
		.evalVM.prg = &Program{
			src: .p.src,
		}
		 = .p
		.p = .evalVM.prg
		 = true
	}
	 := len(.p.code)
	.emitGetter(true)
	.evalVM.pc = 
	 := .evalVM.runTry()
	if  {
		.evalVM.prg = nil
		.evalVM.pc = 0
		.p = 
	} else {
		.evalVM.prg.code = .evalVM.prg.code[:]
		.p.code = .evalVM.prg.code
	}
	if  == nil {
		return .evalVM.pop(), nil
	}
	return nil, 
}

func ( *compiledUnaryExpr) () bool {
	return .operand.constant()
}

func ( *compiledUnaryExpr) ( bool) {
	var ,  func()

	 := func() {
		.addSrcMap()
		.c.emit(toNumber)
	}

	switch .operator {
	case token.NOT:
		.operand.emitGetter(true)
		.c.emit(not)
		goto 
	case token.BITWISE_NOT:
		.operand.emitGetter(true)
		.c.emit(bnot)
		goto 
	case token.TYPEOF:
		if ,  := .operand.(compiledExprOrRef);  {
			.emitGetterOrRef()
		} else {
			.operand.emitGetter(true)
		}
		.c.emit(typeof)
		goto 
	case token.DELETE:
		.operand.deleteExpr().emitGetter()
		return
	case token.MINUS:
		.c.emitExpr(.operand, true)
		.c.emit(neg)
		goto 
	case token.PLUS:
		.c.emitExpr(.operand, true)
		.c.emit(plus)
		goto 
	case token.INCREMENT:
		 = 
		 = func() {
			.c.emit(inc)
		}
	case token.DECREMENT:
		 = 
		 = func() {
			.c.emit(dec)
		}
	case token.VOID:
		.c.emitExpr(.operand, false)
		if  {
			.c.emit(loadUndef)
		}
		return
	default:
		.c.assert(false, .offset, "Unknown unary operator: %s", .operator.String())
		panic("unreachable")
	}

	.operand.emitUnary(, , .postfix, )
	return

:
	if ! {
		.c.emit(pop)
	}
}

func ( *compiler) ( *ast.UnaryExpression) compiledExpr {
	 := &compiledUnaryExpr{
		operand:  .compileExpression(.Operand),
		operator: .Operator,
		postfix:  .Postfix,
	}
	.init(, .Idx0())
	return 
}

func ( *compiledConditionalExpr) ( bool) {
	.test.emitGetter(true)
	 := len(.c.p.code)
	.c.emit(nil)
	.consequent.emitGetter()
	 := len(.c.p.code)
	.c.emit(nil)
	.c.p.code[] = jne(len(.c.p.code) - )
	.alternate.emitGetter()
	.c.p.code[] = jump(len(.c.p.code) - )
}

func ( *compiler) ( *ast.ConditionalExpression) compiledExpr {
	 := &compiledConditionalExpr{
		test:       .compileExpression(.Test),
		consequent: .compileExpression(.Consequent),
		alternate:  .compileExpression(.Alternate),
	}
	.init(, .Idx0())
	return 
}

func ( *compiledLogicalOr) () bool {
	if .left.constant() {
		if ,  := .c.evalConst(.left);  == nil {
			if .ToBoolean() {
				return true
			}
			return .right.constant()
		} else {
			return true
		}
	}

	return false
}

func ( *compiledLogicalOr) ( bool) {
	if .left.constant() {
		if ,  := .c.evalConst(.left);  == nil {
			if !.ToBoolean() {
				.c.emitExpr(.right, )
			} else {
				if  {
					.c.emitLiteralValue()
				}
			}
		} else {
			.c.emitThrow(.val)
		}
		return
	}
	.c.emitExpr(.left, true)
	 := len(.c.p.code)
	.addSrcMap()
	.c.emit(nil)
	.c.emitExpr(.right, true)
	.c.p.code[] = jeq1(len(.c.p.code) - )
	if ! {
		.c.emit(pop)
	}
}

func ( *compiledCoalesce) () bool {
	if .left.constant() {
		if ,  := .c.evalConst(.left);  == nil {
			if  != _null &&  != _undefined {
				return true
			}
			return .right.constant()
		} else {
			return true
		}
	}

	return false
}

func ( *compiledCoalesce) ( bool) {
	if .left.constant() {
		if ,  := .c.evalConst(.left);  == nil {
			if  == _undefined ||  == _null {
				.c.emitExpr(.right, )
			} else {
				if  {
					.c.emitLiteralValue()
				}
			}
		} else {
			.c.emitThrow(.val)
		}
		return
	}
	.c.emitExpr(.left, true)
	 := len(.c.p.code)
	.addSrcMap()
	.c.emit(nil)
	.c.emitExpr(.right, true)
	.c.p.code[] = jcoalesc(len(.c.p.code) - )
	if ! {
		.c.emit(pop)
	}
}

func ( *compiledLogicalAnd) () bool {
	if .left.constant() {
		if ,  := .c.evalConst(.left);  == nil {
			if !.ToBoolean() {
				return true
			} else {
				return .right.constant()
			}
		} else {
			return true
		}
	}

	return false
}

func ( *compiledLogicalAnd) ( bool) {
	var  int
	if .left.constant() {
		if ,  := .c.evalConst(.left);  == nil {
			if !.ToBoolean() {
				.c.emitLiteralValue()
			} else {
				.c.emitExpr(.right, )
			}
		} else {
			.c.emitThrow(.val)
		}
		return
	}
	.left.emitGetter(true)
	 = len(.c.p.code)
	.addSrcMap()
	.c.emit(nil)
	.c.emitExpr(.right, true)
	.c.p.code[] = jneq1(len(.c.p.code) - )
	if ! {
		.c.emit(pop)
	}
}

func ( *compiledBinaryExpr) () bool {
	return .left.constant() && .right.constant()
}

func ( *compiledBinaryExpr) ( bool) {
	.c.emitExpr(.left, true)
	.c.emitExpr(.right, true)
	.addSrcMap()

	switch .operator {
	case token.LESS:
		.c.emit(op_lt)
	case token.GREATER:
		.c.emit(op_gt)
	case token.LESS_OR_EQUAL:
		.c.emit(op_lte)
	case token.GREATER_OR_EQUAL:
		.c.emit(op_gte)
	case token.EQUAL:
		.c.emit(op_eq)
	case token.NOT_EQUAL:
		.c.emit(op_neq)
	case token.STRICT_EQUAL:
		.c.emit(op_strict_eq)
	case token.STRICT_NOT_EQUAL:
		.c.emit(op_strict_neq)
	case token.PLUS:
		.c.emit(add)
	case token.MINUS:
		.c.emit(sub)
	case token.MULTIPLY:
		.c.emit(mul)
	case token.EXPONENT:
		.c.emit(exp)
	case token.SLASH:
		.c.emit(div)
	case token.REMAINDER:
		.c.emit(mod)
	case token.AND:
		.c.emit(and)
	case token.OR:
		.c.emit(or)
	case token.EXCLUSIVE_OR:
		.c.emit(xor)
	case token.INSTANCEOF:
		.c.emit(op_instanceof)
	case token.IN:
		.c.emit(op_in)
	case token.SHIFT_LEFT:
		.c.emit(sal)
	case token.SHIFT_RIGHT:
		.c.emit(sar)
	case token.UNSIGNED_SHIFT_RIGHT:
		.c.emit(shr)
	default:
		.c.assert(false, .offset, "Unknown operator: %s", .operator.String())
		panic("unreachable")
	}

	if ! {
		.c.emit(pop)
	}
}

func ( *compiler) ( *ast.BinaryExpression) compiledExpr {

	switch .Operator {
	case token.LOGICAL_OR:
		return .compileLogicalOr(.Left, .Right, .Idx0())
	case token.COALESCE:
		return .compileCoalesce(.Left, .Right, .Idx0())
	case token.LOGICAL_AND:
		return .compileLogicalAnd(.Left, .Right, .Idx0())
	}

	if ,  := .Left.(*ast.PrivateIdentifier);  {
		return .compilePrivateIn(, .Right, .Idx)
	}

	 := &compiledBinaryExpr{
		left:     .compileExpression(.Left),
		right:    .compileExpression(.Right),
		operator: .Operator,
	}
	.init(, .Idx0())
	return 
}

type compiledPrivateIn struct {
	baseCompiledExpr
	id    unistring.String
	right compiledExpr
}

func ( *compiledPrivateIn) ( bool) {
	.right.emitGetter(true)
	,  := .c.resolvePrivateName(.id, .offset)
	if  != nil {
		.c.emit((*privateInRes)())
	} else {
		.c.emit((*privateInId)())
	}
	if ! {
		.c.emit(pop)
	}
}

func ( *compiler) ( *ast.PrivateIdentifier,  ast.Expression,  file.Idx) compiledExpr {
	 := &compiledPrivateIn{
		id:    .Name,
		right: .compileExpression(),
	}
	.init(, )
	return 
}

func ( *compiler) (,  ast.Expression,  file.Idx) compiledExpr {
	 := &compiledLogicalOr{
		left:  .compileExpression(),
		right: .compileExpression(),
	}
	.init(, )
	return 
}

func ( *compiler) (,  ast.Expression,  file.Idx) compiledExpr {
	 := &compiledCoalesce{
		left:  .compileExpression(),
		right: .compileExpression(),
	}
	.init(, )
	return 
}

func ( *compiler) (,  ast.Expression,  file.Idx) compiledExpr {
	 := &compiledLogicalAnd{
		left:  .compileExpression(),
		right: .compileExpression(),
	}
	.init(, )
	return 
}

func ( *compiledObjectLiteral) ( bool) {
	.addSrcMap()
	.c.emit(newObject)
	 := false
	for ,  := range .expr.Value {
		switch prop := .(type) {
		case *ast.PropertyKeyed:
			,  := .c.processKey(.Key)
			 := .c.compileExpression(.Value)
			var  namedEmitter
			if ,  := .(*compiledFunctionLiteral);  {
				if .name == nil {
					 = 
				}
				switch .Kind {
				case ast.PropertyKindMethod, ast.PropertyKindGet, ast.PropertyKindSet:
					.typ = funcMethod
					if  {
						.homeObjOffset = 2
					} else {
						.homeObjOffset = 1
					}
				}
			} else if ,  := .(namedEmitter);  {
				 = 
			}
			if  {
				.c.emit(_toPropertyKey{})
				.c.emitExpr(, true)
				switch .Kind {
				case ast.PropertyKindValue:
					if  != nil {
						.c.emit(setElem1Named)
					} else {
						.c.emit(setElem1)
					}
				case ast.PropertyKindMethod:
					.c.emit(&defineMethod{enumerable: true})
				case ast.PropertyKindGet:
					.c.emit(&defineGetter{enumerable: true})
				case ast.PropertyKindSet:
					.c.emit(&defineSetter{enumerable: true})
				default:
					.c.assert(false, .offset, "unknown property kind: %s", .Kind)
					panic("unreachable")
				}
			} else {
				 :=  == __proto__ && !.Computed
				if  {
					if  {
						.c.throwSyntaxError(int(.Idx0())-1, "Duplicate __proto__ fields are not allowed in object literals")
					} else {
						 = true
					}
				}
				if  != nil && ! {
					.emitNamed()
				} else {
					.c.emitExpr(, true)
				}
				switch .Kind {
				case ast.PropertyKindValue:
					if  {
						.c.emit(setProto)
					} else {
						.c.emit(putProp())
					}
				case ast.PropertyKindMethod:
					.c.emit(&defineMethodKeyed{key: , enumerable: true})
				case ast.PropertyKindGet:
					.c.emit(&defineGetterKeyed{key: , enumerable: true})
				case ast.PropertyKindSet:
					.c.emit(&defineSetterKeyed{key: , enumerable: true})
				default:
					.c.assert(false, .offset, "unknown property kind: %s", .Kind)
					panic("unreachable")
				}
			}
		case *ast.PropertyShort:
			 := .Name.Name
			if .Initializer != nil {
				.c.throwSyntaxError(int(.Initializer.Idx0())-1, "Invalid shorthand property initializer")
			}
			if .c.scope.strict &&  == "let" {
				.c.throwSyntaxError(.offset, "'let' cannot be used as a shorthand property in strict mode")
			}
			.c.compileIdentifierExpression(&.Name).emitGetter(true)
			.c.emit(putProp())
		case *ast.SpreadElement:
			.c.compileExpression(.Expression).emitGetter(true)
			.c.emit(copySpread)
		default:
			.c.assert(false, .offset, "unknown Property type: %T", )
			panic("unreachable")
		}
	}
	if ! {
		.c.emit(pop)
	}
}

func ( *compiler) ( *ast.ObjectLiteral) compiledExpr {
	 := &compiledObjectLiteral{
		expr: ,
	}
	.init(, .Idx0())
	return 
}

func ( *compiledArrayLiteral) ( bool) {
	.addSrcMap()
	 := false
	 := len(.c.p.code)
	.c.emit(nil)
	for ,  := range .expr.Value {
		if ,  := .(*ast.SpreadElement);  {
			 = true
			.c.compileExpression(.Expression).emitGetter(true)
			.c.emit(pushArraySpread)
		} else {
			if  != nil {
				.c.emitExpr(.c.compileExpression(), true)
			} else {
				.c.emit(loadNil)
			}
			.c.emit(pushArrayItem)
		}
	}
	var  uint32
	if ! {
		 = uint32(len(.expr.Value))
	}
	.c.p.code[] = newArray()
	if ! {
		.c.emit(pop)
	}
}

func ( *compiler) ( *ast.ArrayLiteral) compiledExpr {
	 := &compiledArrayLiteral{
		expr: ,
	}
	.init(, .Idx0())
	return 
}

func ( *compiledRegexpLiteral) ( bool) {
	if  {
		,  := compileRegexp(.expr.Pattern, .expr.Flags)
		if  != nil {
			.c.throwSyntaxError(.offset, .Error())
		}

		.c.emit(&newRegexp{pattern: , src: newStringValue(.expr.Pattern)})
	}
}

func ( *compiler) ( *ast.RegExpLiteral) compiledExpr {
	 := &compiledRegexpLiteral{
		expr: ,
	}
	.init(, .Idx0())
	return 
}

func ( *compiler) ( compiledExpr) ( unistring.String) {
	switch callee := .(type) {
	case *compiledDotExpr:
		.left.emitGetter(true)
		.emit(getPropCallee(.name))
	case *compiledPrivateDotExpr:
		.left.emitGetter(true)
		,  := .resolvePrivateName(.name, .offset)
		if  != nil {
			.emit((*getPrivatePropResCallee)())
		} else {
			.emit((*getPrivatePropIdCallee)())
		}
	case *compiledSuperDotExpr:
		.emitLoadThis()
		.emit(loadSuper)
		.emit(getPropRecvCallee(.name))
	case *compiledBracketExpr:
		.left.emitGetter(true)
		.member.emitGetter(true)
		.emit(getElemCallee)
	case *compiledSuperBracketExpr:
		.emitLoadThis()
		.emit(loadSuper)
		.member.emitGetter(true)
		.emit(getElemRecvCallee)
	case *compiledIdentifierExpr:
		 = .name
		.emitGetterAndCallee()
	case *compiledOptionalChain:
		.startOptChain()
		.(.expr)
		.endOptChain()
	case *compiledOptional:
		.(.expr)
		.block.conts = append(.block.conts, len(.p.code))
		.emit(nil)
	case *compiledSuperExpr:
		// no-op
	default:
		.emit(loadUndef)
		.emitGetter(true)
	}
	return
}

func ( *compiledCallExpr) ( bool) {
	if .isVariadic {
		.c.emit(startVariadic)
	}
	 := .c.emitCallee(.callee)

	for ,  := range .args {
		.emitGetter(true)
	}

	.addSrcMap()
	if ,  := .callee.(*compiledSuperExpr);  {
		,  := .c.scope.lookupThis()
		.c.assert( ||  != nil, .offset, "super call, but no 'this' binding")
		if  {
			.c.emit(resolveThisDynamic{})
		} else {
			.markAccessPoint()
			.c.emit(resolveThisStack{})
		}
		if .isVariadic {
			.c.emit(superCallVariadic)
		} else {
			.c.emit(superCall(len(.args)))
		}
	} else if  == "eval" {
		 := false
		for  := .c.scope;  != nil;  = .outer {
			if ! && (.variable || .isFunction()) {
				 = true
				if !.strict {
					.dynamic = true
				}
			}
			.dynLookup = true
		}

		if .c.scope.strict {
			if .isVariadic {
				.c.emit(callEvalVariadicStrict)
			} else {
				.c.emit(callEvalStrict(len(.args)))
			}
		} else {
			if .isVariadic {
				.c.emit(callEvalVariadic)
			} else {
				.c.emit(callEval(len(.args)))
			}
		}
	} else {
		if .isVariadic {
			.c.emit(callVariadic)
		} else {
			.c.emit(call(len(.args)))
		}
	}
	if .isVariadic {
		.c.emit(endVariadic)
	}
	if ! {
		.c.emit(pop)
	}
}

func ( *compiledCallExpr) () compiledExpr {
	 := &defaultDeleteExpr{
		expr: ,
	}
	.init(.c, file.Idx(.offset+1))
	return 
}

func ( *compiler) ( *ast.SpreadElement) compiledExpr {
	 := &compiledSpreadCallArgument{
		expr: .compileExpression(.Expression),
	}
	.init(, .Idx0())
	return 
}

func ( *compiler) ( ast.Expression) compiledExpr {
	if ,  := .(*ast.SuperExpression);  {
		if  := .scope.nearestThis();  != nil && .funcType == funcDerivedCtor {
			 := &compiledSuperExpr{}
			.init(, .Idx)
			return 
		}
		.throwSyntaxError(int(.Idx0())-1, "'super' keyword unexpected here")
		panic("unreachable")
	}
	return .compileExpression()
}

func ( *compiler) ( *ast.CallExpression) compiledExpr {

	 := make([]compiledExpr, len(.ArgumentList))
	 := false
	for ,  := range .ArgumentList {
		if ,  := .(*ast.SpreadElement);  {
			[] = .compileSpreadCallArgument()
			 = true
		} else {
			[] = .compileExpression()
		}
	}

	 := &compiledCallExpr{
		args:       ,
		callee:     .compileCallee(.Callee),
		isVariadic: ,
	}
	.init(, .LeftParenthesis)
	return 
}

func ( *compiler) ( *ast.Identifier) compiledExpr {
	if .scope.strict {
		.checkIdentifierName(.Name, int(.Idx)-1)
	}

	 := &compiledIdentifierExpr{
		name: .Name,
	}
	.offset = int(.Idx) - 1
	.init(, .Idx0())
	return 
}

func ( *compiler) ( *ast.NumberLiteral) compiledExpr {
	if .scope.strict && len(.Literal) > 1 && .Literal[0] == '0' && .Literal[1] <= '7' && .Literal[1] >= '0' {
		.throwSyntaxError(int(.Idx)-1, "Octal literals are not allowed in strict mode")
		panic("Unreachable")
	}
	var  Value
	switch num := .Value.(type) {
	case int64:
		 = intToValue()
	case float64:
		 = floatToValue()
	case *big.Int:
		 = (*valueBigInt)()
	default:
		.assert(false, int(.Idx)-1, "Unsupported number literal type: %T", .Value)
		panic("unreachable")
	}
	 := &compiledLiteral{
		val: ,
	}
	.init(, .Idx0())
	return 
}

func ( *compiler) ( *ast.StringLiteral) compiledExpr {
	 := &compiledLiteral{
		val: stringValueFromRaw(.Value),
	}
	.init(, .Idx0())
	return 
}

func ( *compiler) ( *ast.TemplateLiteral) compiledExpr {
	 := &compiledTemplateLiteral{}
	if .Tag != nil {
		.tag = .compileExpression(.Tag)
	}
	 := make([]compiledExpr, len(.Expressions))
	for ,  := range .Expressions {
		[] = .compileExpression()
	}
	.expressions = 
	.elements = .Elements
	.init(, .Idx0())
	return 
}

func ( *compiler) ( *ast.BooleanLiteral) compiledExpr {
	var  Value
	if .Value {
		 = valueTrue
	} else {
		 = valueFalse
	}

	 := &compiledLiteral{
		val: ,
	}
	.init(, .Idx0())
	return 
}

func ( *compiler) ( *ast.AssignExpression) compiledExpr {
	// log.Printf("compileAssignExpression(): %+v", v)

	 := &compiledAssignExpr{
		left:     .compileExpression(.Left),
		right:    .compileExpression(.Right),
		operator: .Operator,
	}
	.init(, .Idx0())
	return 
}

func ( *compiledEnumGetExpr) ( bool) {
	.c.emit(enumGet)
	if ! {
		.c.emit(pop)
	}
}

func ( *compiler) ( *ast.ObjectPattern) compiledExpr {
	 := &compiledObjectAssignmentPattern{
		expr: ,
	}
	.init(, .Idx0())
	return 
}

func ( *compiledObjectAssignmentPattern) ( bool) {
	if  {
		.c.emit(loadUndef)
	}
}

func ( *compiler) ( *ast.ArrayPattern) compiledExpr {
	 := &compiledArrayAssignmentPattern{
		expr: ,
	}
	.init(, .Idx0())
	return 
}

func ( *compiledArrayAssignmentPattern) ( bool) {
	if  {
		.c.emit(loadUndef)
	}
}

func ( *compiler) ( compiledExpr,  bool) {
	if .constant() {
		.emitConst(, )
	} else {
		.emitGetter()
	}
}

type namedEmitter interface {
	emitNamed(name unistring.String)
}

func ( *compiler) ( compiledExpr,  unistring.String) {
	if ,  := .(namedEmitter);  {
		.emitNamed()
	} else {
		.emitGetter(true)
	}
}

func ( *compiler) ( compiledExpr,  unistring.String) {
	if .constant() {
		.emitConst(, true)
	} else {
		.emitNamed(, )
	}
}

func ( *compiledFunctionLiteral) ( unistring.String) {
	.lhsName = 
	.emitGetter(true)
}

func ( *compiledClassLiteral) ( unistring.String) {
	.lhsName = 
	.emitGetter(true)
}

func ( *compiler) ( ast.Pattern,  func(,  compiledExpr),  bool) {
	switch pattern := .(type) {
	case *ast.ObjectPattern:
		.emitObjectPattern(, , )
	case *ast.ArrayPattern:
		.emitArrayPattern(, , )
	default:
		.assert(false, int(.Idx0())-1, "unsupported Pattern: %T", )
		panic("unreachable")
	}
}

func ( *compiler) ( ast.Expression,  compiledExpr,  func(,  compiledExpr)) {
	,  := .(ast.Pattern)
	if  {
		.emitGetter(true)
		.emitPattern(, , false)
	} else {
		(.compileExpression(), )
	}
}

func ( *compiler) ( *ast.ObjectPattern,  func(,  compiledExpr),  bool) {
	if .Rest != nil {
		.emit(createDestructSrc)
	} else {
		.emit(checkObjectCoercible)
	}
	for ,  := range .Properties {
		switch prop := .(type) {
		case *ast.PropertyShort:
			.emit(dup)
			(.compileIdentifierExpression(&.Name), .compilePatternInitExpr(func() {
				.emit(getProp(.Name.Name))
			}, .Initializer, .Idx0()))
		case *ast.PropertyKeyed:
			.emit(dup)
			.compileExpression(.Key).emitGetter(true)
			.emit(_toPropertyKey{})
			var  ast.Expression
			var  ast.Expression
			if ,  := .Value.(*ast.AssignExpression);  {
				 = .Left
				 = .Right
			} else {
				 = .Value
			}
			.emitAssign(, .compilePatternInitExpr(func() {
				.emit(getKey)
			}, , .Idx0()), )
		default:
			.throwSyntaxError(int(.Idx0()-1), "Unsupported AssignmentProperty type: %T", )
		}
	}
	if .Rest != nil {
		(.compileExpression(.Rest), .compileEmitterExpr(func() {
			.emit(copyRest)
		}, .Rest.Idx0()))
		.emit(pop)
	}
	if ! {
		.emit(pop)
	}
}

func ( *compiler) ( *ast.ArrayPattern,  func(,  compiledExpr),  bool) {
	.emit(iterate)
	for ,  := range .Elements {
		switch elt := .(type) {
		case nil:
			.emit(iterGetNextOrUndef{}, pop)
		case *ast.AssignExpression:
			.emitAssign(.Left, .compilePatternInitExpr(func() {
				.emit(iterGetNextOrUndef{})
			}, .Right, .Idx0()), )
		default:
			.emitAssign(, .compileEmitterExpr(func() {
				.emit(iterGetNextOrUndef{})
			}, .Idx0()), )
		}
	}
	if .Rest != nil {
		.emitAssign(.Rest, .compileEmitterExpr(func() {
			.emit(newArrayFromIter)
		}, .Rest.Idx0()), )
	} else {
		.emit(enumPopClose)
	}

	if ! {
		.emit(pop)
	}
}

func ( *compiledObjectAssignmentPattern) ( compiledExpr,  bool) {
	.emitGetter(true)
	.c.emitObjectPattern(.expr, .c.emitPatternAssign, )
}

func ( *compiledArrayAssignmentPattern) ( compiledExpr,  bool) {
	.emitGetter(true)
	.c.emitArrayPattern(.expr, .c.emitPatternAssign, )
}

type compiledPatternInitExpr struct {
	baseCompiledExpr
	emitSrc func()
	def     compiledExpr
}

func ( *compiledPatternInitExpr) ( bool) {
	if ! {
		return
	}
	.emitSrc()
	if .def != nil {
		 := len(.c.p.code)
		.c.emit(nil)
		.c.emitExpr(.def, true)
		.c.p.code[] = jdef(len(.c.p.code) - )
	}
}

func ( *compiledPatternInitExpr) ( unistring.String) {
	.emitSrc()
	if .def != nil {
		 := len(.c.p.code)
		.c.emit(nil)
		.c.emitNamedOrConst(.def, )
		.c.p.code[] = jdef(len(.c.p.code) - )
	}
}

func ( *compiler) ( func(),  ast.Expression,  file.Idx) compiledExpr {
	 := &compiledPatternInitExpr{
		emitSrc: ,
		def:     .compileExpression(),
	}
	.init(, )
	return 
}

type compiledEmitterExpr struct {
	baseCompiledExpr
	emitter      func()
	namedEmitter func(name unistring.String)
}

func ( *compiledEmitterExpr) ( bool) {
	if .emitter != nil {
		.emitter()
	} else {
		.namedEmitter("")
	}
	if ! {
		.c.emit(pop)
	}
}

func ( *compiledEmitterExpr) ( unistring.String) {
	if .namedEmitter != nil {
		.namedEmitter()
	} else {
		.emitter()
	}
}

func ( *compiler) ( func(),  file.Idx) *compiledEmitterExpr {
	 := &compiledEmitterExpr{
		emitter: ,
	}
	.init(, )
	return 
}

func ( *compiledSpreadCallArgument) ( bool) {
	.expr.emitGetter()
	if  {
		.c.emit(pushSpread)
	}
}

func ( *compiler) () {
	.block = &block{
		typ:   blockOptChain,
		outer: .block,
	}
}

func ( *compiler) () {
	 := len(.p.code)
	for ,  := range .block.breaks {
		.p.code[] = jopt( - )
	}
	for ,  := range .block.conts {
		.p.code[] = joptc( - )
	}
	.block = .block.outer
}

func ( *compiledOptionalChain) ( bool) {
	.c.startOptChain()
	.expr.emitGetter(true)
	.c.endOptChain()
	if ! {
		.c.emit(pop)
	}
}

func ( *compiledOptional) ( bool) {
	.expr.emitGetter()
	if  {
		.c.block.breaks = append(.c.block.breaks, len(.c.p.code))
		.c.emit(nil)
	}
}

func ( *compiledAwaitExpression) ( bool) {
	.arg.emitGetter(true)
	.c.emit(await)
	if ! {
		.c.emit(pop)
	}
}

func ( *compiledYieldExpression) ( bool) {
	if .arg != nil {
		.arg.emitGetter(true)
	} else {
		.c.emit(loadUndef)
	}
	if  {
		if .delegate {
			.c.emit(yieldDelegateRes)
		} else {
			.c.emit(yieldRes)
		}
	} else {
		if .delegate {
			.c.emit(yieldDelegate)
		} else {
			.c.emit(yield)
		}
	}
}