github.com/nuvolaris/goja@v0.0.0-20230825100449-967811910c6d/compiler.go (about)

     1  package goja
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  
     7  	"github.com/nuvolaris/goja/token"
     8  
     9  	"github.com/nuvolaris/goja/ast"
    10  	"github.com/nuvolaris/goja/file"
    11  	"github.com/nuvolaris/goja/unistring"
    12  )
    13  
    14  type blockType int
    15  
    16  const (
    17  	blockLoop blockType = iota
    18  	blockLoopEnum
    19  	blockTry
    20  	blockLabel
    21  	blockSwitch
    22  	blockWith
    23  	blockScope
    24  	blockIterScope
    25  	blockOptChain
    26  )
    27  
    28  const (
    29  	maskConst     = 1 << 31
    30  	maskVar       = 1 << 30
    31  	maskDeletable = 1 << 29
    32  	maskStrict    = maskDeletable
    33  
    34  	maskTyp = maskConst | maskVar | maskDeletable
    35  )
    36  
    37  type varType byte
    38  
    39  const (
    40  	varTypeVar varType = iota
    41  	varTypeLet
    42  	varTypeStrictConst
    43  	varTypeConst
    44  )
    45  
    46  const thisBindingName = " this" // must not be a valid identifier
    47  
    48  type CompilerError struct {
    49  	Message string
    50  	File    *file.File
    51  	Offset  int
    52  }
    53  
    54  type CompilerSyntaxError struct {
    55  	CompilerError
    56  }
    57  
    58  type CompilerReferenceError struct {
    59  	CompilerError
    60  }
    61  
    62  type srcMapItem struct {
    63  	pc     int
    64  	srcPos int
    65  }
    66  
    67  type Program struct {
    68  	code   []instruction
    69  	values []Value
    70  
    71  	funcName unistring.String
    72  	src      *file.File
    73  	srcMap   []srcMapItem
    74  }
    75  
    76  type compiler struct {
    77  	p     *Program
    78  	scope *scope
    79  	block *block
    80  
    81  	classScope *classScope
    82  
    83  	enumGetExpr compiledEnumGetExpr
    84  
    85  	evalVM *vm // VM used to evaluate constant expressions
    86  	ctxVM  *vm // VM in which an eval() code is compiled
    87  
    88  	codeScratchpad []instruction
    89  }
    90  
    91  type binding struct {
    92  	scope        *scope
    93  	name         unistring.String
    94  	accessPoints map[*scope]*[]int
    95  	isConst      bool
    96  	isStrict     bool
    97  	isArg        bool
    98  	isVar        bool
    99  	inStash      bool
   100  }
   101  
   102  func (b *binding) getAccessPointsForScope(s *scope) *[]int {
   103  	m := b.accessPoints[s]
   104  	if m == nil {
   105  		a := make([]int, 0, 1)
   106  		m = &a
   107  		if b.accessPoints == nil {
   108  			b.accessPoints = make(map[*scope]*[]int)
   109  		}
   110  		b.accessPoints[s] = m
   111  	}
   112  	return m
   113  }
   114  
   115  func (b *binding) markAccessPointAt(pos int) {
   116  	scope := b.scope.c.scope
   117  	m := b.getAccessPointsForScope(scope)
   118  	*m = append(*m, pos-scope.base)
   119  }
   120  
   121  func (b *binding) markAccessPointAtScope(scope *scope, pos int) {
   122  	m := b.getAccessPointsForScope(scope)
   123  	*m = append(*m, pos-scope.base)
   124  }
   125  
   126  func (b *binding) markAccessPoint() {
   127  	scope := b.scope.c.scope
   128  	m := b.getAccessPointsForScope(scope)
   129  	*m = append(*m, len(scope.prg.code)-scope.base)
   130  }
   131  
   132  func (b *binding) emitGet() {
   133  	b.markAccessPoint()
   134  	if b.isVar && !b.isArg {
   135  		b.scope.c.emit(loadStack(0))
   136  	} else {
   137  		b.scope.c.emit(loadStackLex(0))
   138  	}
   139  }
   140  
   141  func (b *binding) emitGetAt(pos int) {
   142  	b.markAccessPointAt(pos)
   143  	if b.isVar && !b.isArg {
   144  		b.scope.c.p.code[pos] = loadStack(0)
   145  	} else {
   146  		b.scope.c.p.code[pos] = loadStackLex(0)
   147  	}
   148  }
   149  
   150  func (b *binding) emitGetP() {
   151  	if b.isVar && !b.isArg {
   152  		// no-op
   153  	} else {
   154  		// make sure TDZ is checked
   155  		b.markAccessPoint()
   156  		b.scope.c.emit(loadStackLex(0), pop)
   157  	}
   158  }
   159  
   160  func (b *binding) emitSet() {
   161  	if b.isConst {
   162  		if b.isStrict || b.scope.c.scope.strict {
   163  			b.scope.c.emit(throwAssignToConst)
   164  		}
   165  		return
   166  	}
   167  	b.markAccessPoint()
   168  	if b.isVar && !b.isArg {
   169  		b.scope.c.emit(storeStack(0))
   170  	} else {
   171  		b.scope.c.emit(storeStackLex(0))
   172  	}
   173  }
   174  
   175  func (b *binding) emitSetP() {
   176  	if b.isConst {
   177  		if b.isStrict || b.scope.c.scope.strict {
   178  			b.scope.c.emit(throwAssignToConst)
   179  		}
   180  		return
   181  	}
   182  	b.markAccessPoint()
   183  	if b.isVar && !b.isArg {
   184  		b.scope.c.emit(storeStackP(0))
   185  	} else {
   186  		b.scope.c.emit(storeStackLexP(0))
   187  	}
   188  }
   189  
   190  func (b *binding) emitInitP() {
   191  	if !b.isVar && b.scope.outer == nil {
   192  		b.scope.c.emit(initGlobalP(b.name))
   193  	} else {
   194  		b.markAccessPoint()
   195  		b.scope.c.emit(initStackP(0))
   196  	}
   197  }
   198  
   199  func (b *binding) emitInit() {
   200  	if !b.isVar && b.scope.outer == nil {
   201  		b.scope.c.emit(initGlobal(b.name))
   202  	} else {
   203  		b.markAccessPoint()
   204  		b.scope.c.emit(initStack(0))
   205  	}
   206  }
   207  
   208  func (b *binding) emitInitAt(pos int) {
   209  	if !b.isVar && b.scope.outer == nil {
   210  		b.scope.c.p.code[pos] = initGlobal(b.name)
   211  	} else {
   212  		b.markAccessPointAt(pos)
   213  		b.scope.c.p.code[pos] = initStack(0)
   214  	}
   215  }
   216  
   217  func (b *binding) emitInitAtScope(scope *scope, pos int) {
   218  	if !b.isVar && scope.outer == nil {
   219  		scope.c.p.code[pos] = initGlobal(b.name)
   220  	} else {
   221  		b.markAccessPointAtScope(scope, pos)
   222  		scope.c.p.code[pos] = initStack(0)
   223  	}
   224  }
   225  
   226  func (b *binding) emitInitPAtScope(scope *scope, pos int) {
   227  	if !b.isVar && scope.outer == nil {
   228  		scope.c.p.code[pos] = initGlobalP(b.name)
   229  	} else {
   230  		b.markAccessPointAtScope(scope, pos)
   231  		scope.c.p.code[pos] = initStackP(0)
   232  	}
   233  }
   234  
   235  func (b *binding) emitGetVar(callee bool) {
   236  	b.markAccessPoint()
   237  	if b.isVar && !b.isArg {
   238  		b.scope.c.emit(&loadMixed{name: b.name, callee: callee})
   239  	} else {
   240  		b.scope.c.emit(&loadMixedLex{name: b.name, callee: callee})
   241  	}
   242  }
   243  
   244  func (b *binding) emitResolveVar(strict bool) {
   245  	b.markAccessPoint()
   246  	if b.isVar && !b.isArg {
   247  		b.scope.c.emit(&resolveMixed{name: b.name, strict: strict, typ: varTypeVar})
   248  	} else {
   249  		var typ varType
   250  		if b.isConst {
   251  			if b.isStrict {
   252  				typ = varTypeStrictConst
   253  			} else {
   254  				typ = varTypeConst
   255  			}
   256  		} else {
   257  			typ = varTypeLet
   258  		}
   259  		b.scope.c.emit(&resolveMixed{name: b.name, strict: strict, typ: typ})
   260  	}
   261  }
   262  
   263  func (b *binding) moveToStash() {
   264  	if b.isArg && !b.scope.argsInStash {
   265  		b.scope.moveArgsToStash()
   266  	} else {
   267  		b.inStash = true
   268  		b.scope.needStash = true
   269  	}
   270  }
   271  
   272  func (b *binding) useCount() (count int) {
   273  	for _, a := range b.accessPoints {
   274  		count += len(*a)
   275  	}
   276  	return
   277  }
   278  
   279  type scope struct {
   280  	c          *compiler
   281  	prg        *Program
   282  	outer      *scope
   283  	nested     []*scope
   284  	boundNames map[unistring.String]*binding
   285  	bindings   []*binding
   286  	base       int
   287  	numArgs    int
   288  
   289  	// function type. If not funcNone, this is a function or a top-level lexical environment
   290  	funcType funcType
   291  
   292  	// in strict mode
   293  	strict bool
   294  	// eval top-level scope
   295  	eval bool
   296  	// at least one inner scope has direct eval() which can lookup names dynamically (by name)
   297  	dynLookup bool
   298  	// at least one binding has been marked for placement in stash
   299  	needStash bool
   300  
   301  	// is a variable environment, i.e. the target for dynamically created var bindings
   302  	variable bool
   303  	// a function scope that has at least one direct eval() and non-strict, so the variables can be added dynamically
   304  	dynamic bool
   305  	// arguments have been marked for placement in stash (functions only)
   306  	argsInStash bool
   307  	// need 'arguments' object (functions only)
   308  	argsNeeded bool
   309  }
   310  
   311  type block struct {
   312  	typ        blockType
   313  	label      unistring.String
   314  	cont       int
   315  	breaks     []int
   316  	conts      []int
   317  	outer      *block
   318  	breaking   *block // set when the 'finally' block is an empty break statement sequence
   319  	needResult bool
   320  }
   321  
   322  func (c *compiler) leaveScopeBlock(enter *enterBlock) {
   323  	c.updateEnterBlock(enter)
   324  	leave := &leaveBlock{
   325  		stackSize: enter.stackSize,
   326  		popStash:  enter.stashSize > 0,
   327  	}
   328  	c.emit(leave)
   329  	for _, pc := range c.block.breaks {
   330  		c.p.code[pc] = leave
   331  	}
   332  	c.block.breaks = nil
   333  	c.leaveBlock()
   334  }
   335  
   336  func (c *compiler) leaveBlock() {
   337  	lbl := len(c.p.code)
   338  	for _, item := range c.block.breaks {
   339  		c.p.code[item] = jump(lbl - item)
   340  	}
   341  	if t := c.block.typ; t == blockLoop || t == blockLoopEnum {
   342  		for _, item := range c.block.conts {
   343  			c.p.code[item] = jump(c.block.cont - item)
   344  		}
   345  	}
   346  	c.block = c.block.outer
   347  }
   348  
   349  func (e *CompilerSyntaxError) Error() string {
   350  	if e.File != nil {
   351  		return fmt.Sprintf("SyntaxError: %s at %s", e.Message, e.File.Position(e.Offset))
   352  	}
   353  	return fmt.Sprintf("SyntaxError: %s", e.Message)
   354  }
   355  
   356  func (e *CompilerReferenceError) Error() string {
   357  	return fmt.Sprintf("ReferenceError: %s", e.Message)
   358  }
   359  
   360  func (c *compiler) newScope() {
   361  	strict := false
   362  	if c.scope != nil {
   363  		strict = c.scope.strict
   364  	}
   365  	c.scope = &scope{
   366  		c:      c,
   367  		prg:    c.p,
   368  		outer:  c.scope,
   369  		strict: strict,
   370  	}
   371  }
   372  
   373  func (c *compiler) newBlockScope() {
   374  	c.newScope()
   375  	if outer := c.scope.outer; outer != nil {
   376  		outer.nested = append(outer.nested, c.scope)
   377  	}
   378  	c.scope.base = len(c.p.code)
   379  }
   380  
   381  func (c *compiler) popScope() {
   382  	c.scope = c.scope.outer
   383  }
   384  
   385  func newCompiler() *compiler {
   386  	c := &compiler{
   387  		p: &Program{},
   388  	}
   389  
   390  	c.enumGetExpr.init(c, file.Idx(0))
   391  
   392  	return c
   393  }
   394  
   395  func (p *Program) defineLiteralValue(val Value) uint32 {
   396  	for idx, v := range p.values {
   397  		if v.SameAs(val) {
   398  			return uint32(idx)
   399  		}
   400  	}
   401  	idx := uint32(len(p.values))
   402  	p.values = append(p.values, val)
   403  	return idx
   404  }
   405  
   406  func (p *Program) dumpCode(logger func(format string, args ...interface{})) {
   407  	p._dumpCode("", logger)
   408  }
   409  
   410  func (p *Program) _dumpCode(indent string, logger func(format string, args ...interface{})) {
   411  	logger("values: %+v", p.values)
   412  	dumpInitFields := func(initFields *Program) {
   413  		i := indent + ">"
   414  		logger("%s ---- init_fields:", i)
   415  		initFields._dumpCode(i, logger)
   416  		logger("%s ----", i)
   417  	}
   418  	for pc, ins := range p.code {
   419  		logger("%s %d: %T(%v)", indent, pc, ins, ins)
   420  		var prg *Program
   421  		switch f := ins.(type) {
   422  		case newFuncInstruction:
   423  			prg = f.getPrg()
   424  		case *newDerivedClass:
   425  			if f.initFields != nil {
   426  				dumpInitFields(f.initFields)
   427  			}
   428  			prg = f.ctor
   429  		case *newClass:
   430  			if f.initFields != nil {
   431  				dumpInitFields(f.initFields)
   432  			}
   433  			prg = f.ctor
   434  		case *newStaticFieldInit:
   435  			if f.initFields != nil {
   436  				dumpInitFields(f.initFields)
   437  			}
   438  		}
   439  		if prg != nil {
   440  			prg._dumpCode(indent+">", logger)
   441  		}
   442  	}
   443  }
   444  
   445  func (p *Program) sourceOffset(pc int) int {
   446  	i := sort.Search(len(p.srcMap), func(idx int) bool {
   447  		return p.srcMap[idx].pc > pc
   448  	}) - 1
   449  	if i >= 0 {
   450  		return p.srcMap[i].srcPos
   451  	}
   452  
   453  	return 0
   454  }
   455  
   456  func (p *Program) addSrcMap(srcPos int) {
   457  	if len(p.srcMap) > 0 && p.srcMap[len(p.srcMap)-1].srcPos == srcPos {
   458  		return
   459  	}
   460  	p.srcMap = append(p.srcMap, srcMapItem{pc: len(p.code), srcPos: srcPos})
   461  }
   462  
   463  func (s *scope) lookupName(name unistring.String) (binding *binding, noDynamics bool) {
   464  	noDynamics = true
   465  	toStash := false
   466  	for curScope := s; ; curScope = curScope.outer {
   467  		if curScope.outer != nil {
   468  			if b, exists := curScope.boundNames[name]; exists {
   469  				if toStash && !b.inStash {
   470  					b.moveToStash()
   471  				}
   472  				binding = b
   473  				return
   474  			}
   475  		} else {
   476  			noDynamics = false
   477  			return
   478  		}
   479  		if curScope.dynamic {
   480  			noDynamics = false
   481  		}
   482  		if name == "arguments" && curScope.funcType != funcNone && curScope.funcType != funcArrow {
   483  			if curScope.funcType == funcClsInit {
   484  				s.c.throwSyntaxError(0, "'arguments' is not allowed in class field initializer or static initialization block")
   485  			}
   486  			curScope.argsNeeded = true
   487  			binding, _ = curScope.bindName(name)
   488  			return
   489  		}
   490  		if curScope.isFunction() {
   491  			toStash = true
   492  		}
   493  	}
   494  }
   495  
   496  func (s *scope) lookupThis() (*binding, bool) {
   497  	toStash := false
   498  	for curScope := s; curScope != nil; curScope = curScope.outer {
   499  		if curScope.outer == nil {
   500  			if curScope.eval {
   501  				return nil, true
   502  			}
   503  		}
   504  		if b, exists := curScope.boundNames[thisBindingName]; exists {
   505  			if toStash && !b.inStash {
   506  				b.moveToStash()
   507  			}
   508  			return b, false
   509  		}
   510  		if curScope.isFunction() {
   511  			toStash = true
   512  		}
   513  	}
   514  	return nil, false
   515  }
   516  
   517  func (s *scope) ensureBoundNamesCreated() {
   518  	if s.boundNames == nil {
   519  		s.boundNames = make(map[unistring.String]*binding)
   520  	}
   521  }
   522  
   523  func (s *scope) addBinding(offset int) *binding {
   524  	if len(s.bindings) >= (1<<24)-1 {
   525  		s.c.throwSyntaxError(offset, "Too many variables")
   526  	}
   527  	b := &binding{
   528  		scope: s,
   529  	}
   530  	s.bindings = append(s.bindings, b)
   531  	return b
   532  }
   533  
   534  func (s *scope) bindNameLexical(name unistring.String, unique bool, offset int) (*binding, bool) {
   535  	if b := s.boundNames[name]; b != nil {
   536  		if unique {
   537  			s.c.throwSyntaxError(offset, "Identifier '%s' has already been declared", name)
   538  		}
   539  		return b, false
   540  	}
   541  	b := s.addBinding(offset)
   542  	b.name = name
   543  	s.ensureBoundNamesCreated()
   544  	s.boundNames[name] = b
   545  	return b, true
   546  }
   547  
   548  func (s *scope) createThisBinding() *binding {
   549  	thisBinding, _ := s.bindNameLexical(thisBindingName, false, 0)
   550  	thisBinding.isVar = true // don't check on load
   551  	return thisBinding
   552  }
   553  
   554  func (s *scope) bindName(name unistring.String) (*binding, bool) {
   555  	if !s.isFunction() && !s.variable && s.outer != nil {
   556  		return s.outer.bindName(name)
   557  	}
   558  	b, created := s.bindNameLexical(name, false, 0)
   559  	if created {
   560  		b.isVar = true
   561  	}
   562  	return b, created
   563  }
   564  
   565  func (s *scope) bindNameShadow(name unistring.String) (*binding, bool) {
   566  	if !s.isFunction() && s.outer != nil {
   567  		return s.outer.bindNameShadow(name)
   568  	}
   569  
   570  	_, exists := s.boundNames[name]
   571  	b := &binding{
   572  		scope: s,
   573  		name:  name,
   574  	}
   575  	s.bindings = append(s.bindings, b)
   576  	s.ensureBoundNamesCreated()
   577  	s.boundNames[name] = b
   578  	return b, !exists
   579  }
   580  
   581  func (s *scope) nearestFunction() *scope {
   582  	for sc := s; sc != nil; sc = sc.outer {
   583  		if sc.isFunction() {
   584  			return sc
   585  		}
   586  	}
   587  	return nil
   588  }
   589  
   590  func (s *scope) nearestThis() *scope {
   591  	for sc := s; sc != nil; sc = sc.outer {
   592  		if sc.eval || sc.isFunction() && sc.funcType != funcArrow {
   593  			return sc
   594  		}
   595  	}
   596  	return nil
   597  }
   598  
   599  func (s *scope) finaliseVarAlloc(stackOffset int) (stashSize, stackSize int) {
   600  	argsInStash := false
   601  	if f := s.nearestFunction(); f != nil {
   602  		argsInStash = f.argsInStash
   603  	}
   604  	stackIdx, stashIdx := 0, 0
   605  	allInStash := s.isDynamic()
   606  	var derivedCtor bool
   607  	if fs := s.nearestThis(); fs != nil && fs.funcType == funcDerivedCtor {
   608  		derivedCtor = true
   609  	}
   610  	for i, b := range s.bindings {
   611  		var this bool
   612  		if b.name == thisBindingName {
   613  			this = true
   614  		}
   615  		if allInStash || b.inStash {
   616  			for scope, aps := range b.accessPoints {
   617  				var level uint32
   618  				for sc := scope; sc != nil && sc != s; sc = sc.outer {
   619  					if sc.needStash || sc.isDynamic() {
   620  						level++
   621  					}
   622  				}
   623  				if level > 255 {
   624  					s.c.throwSyntaxError(0, "Maximum nesting level (256) exceeded")
   625  				}
   626  				idx := (level << 24) | uint32(stashIdx)
   627  				base := scope.base
   628  				code := scope.prg.code
   629  				if this {
   630  					if derivedCtor {
   631  						for _, pc := range *aps {
   632  							ap := &code[base+pc]
   633  							switch (*ap).(type) {
   634  							case loadStack:
   635  								*ap = loadThisStash(idx)
   636  							case initStack:
   637  								*ap = initStash(idx)
   638  							case resolveThisStack:
   639  								*ap = resolveThisStash(idx)
   640  							case _ret:
   641  								*ap = cret(idx)
   642  							default:
   643  								s.c.assert(false, s.c.p.sourceOffset(pc), "Unsupported instruction for 'this'")
   644  							}
   645  						}
   646  					} else {
   647  						for _, pc := range *aps {
   648  							ap := &code[base+pc]
   649  							switch (*ap).(type) {
   650  							case loadStack:
   651  								*ap = loadStash(idx)
   652  							case initStack:
   653  								*ap = initStash(idx)
   654  							default:
   655  								s.c.assert(false, s.c.p.sourceOffset(pc), "Unsupported instruction for 'this'")
   656  							}
   657  						}
   658  					}
   659  				} else {
   660  					for _, pc := range *aps {
   661  						ap := &code[base+pc]
   662  						switch i := (*ap).(type) {
   663  						case loadStack:
   664  							*ap = loadStash(idx)
   665  						case storeStack:
   666  							*ap = storeStash(idx)
   667  						case storeStackP:
   668  							*ap = storeStashP(idx)
   669  						case loadStackLex:
   670  							*ap = loadStashLex(idx)
   671  						case storeStackLex:
   672  							*ap = storeStashLex(idx)
   673  						case storeStackLexP:
   674  							*ap = storeStashLexP(idx)
   675  						case initStackP:
   676  							*ap = initStashP(idx)
   677  						case initStack:
   678  							*ap = initStash(idx)
   679  						case *loadMixed:
   680  							i.idx = idx
   681  						case *loadMixedLex:
   682  							i.idx = idx
   683  						case *resolveMixed:
   684  							i.idx = idx
   685  						default:
   686  							s.c.assert(false, s.c.p.sourceOffset(pc), "Unsupported instruction for binding: %T", i)
   687  						}
   688  					}
   689  				}
   690  			}
   691  			stashIdx++
   692  		} else {
   693  			var idx int
   694  			if !this {
   695  				if i < s.numArgs {
   696  					idx = -(i + 1)
   697  				} else {
   698  					stackIdx++
   699  					idx = stackIdx + stackOffset
   700  				}
   701  			}
   702  			for scope, aps := range b.accessPoints {
   703  				var level int
   704  				for sc := scope; sc != nil && sc != s; sc = sc.outer {
   705  					if sc.needStash || sc.isDynamic() {
   706  						level++
   707  					}
   708  				}
   709  				if level > 255 {
   710  					s.c.throwSyntaxError(0, "Maximum nesting level (256) exceeded")
   711  				}
   712  				code := scope.prg.code
   713  				base := scope.base
   714  				if this {
   715  					if derivedCtor {
   716  						for _, pc := range *aps {
   717  							ap := &code[base+pc]
   718  							switch (*ap).(type) {
   719  							case loadStack:
   720  								*ap = loadThisStack{}
   721  							case initStack:
   722  								// no-op
   723  							case resolveThisStack:
   724  								// no-op
   725  							case _ret:
   726  								// no-op, already in the right place
   727  							default:
   728  								s.c.assert(false, s.c.p.sourceOffset(pc), "Unsupported instruction for 'this'")
   729  							}
   730  						}
   731  					} /*else {
   732  						no-op
   733  					}*/
   734  				} else if argsInStash {
   735  					for _, pc := range *aps {
   736  						ap := &code[base+pc]
   737  						switch i := (*ap).(type) {
   738  						case loadStack:
   739  							*ap = loadStack1(idx)
   740  						case storeStack:
   741  							*ap = storeStack1(idx)
   742  						case storeStackP:
   743  							*ap = storeStack1P(idx)
   744  						case loadStackLex:
   745  							*ap = loadStack1Lex(idx)
   746  						case storeStackLex:
   747  							*ap = storeStack1Lex(idx)
   748  						case storeStackLexP:
   749  							*ap = storeStack1LexP(idx)
   750  						case initStackP:
   751  							*ap = initStack1P(idx)
   752  						case initStack:
   753  							*ap = initStack1(idx)
   754  						case *loadMixed:
   755  							*ap = &loadMixedStack1{name: i.name, idx: idx, level: uint8(level), callee: i.callee}
   756  						case *loadMixedLex:
   757  							*ap = &loadMixedStack1Lex{name: i.name, idx: idx, level: uint8(level), callee: i.callee}
   758  						case *resolveMixed:
   759  							*ap = &resolveMixedStack1{typ: i.typ, name: i.name, idx: idx, level: uint8(level), strict: i.strict}
   760  						default:
   761  							s.c.assert(false, s.c.p.sourceOffset(pc), "Unsupported instruction for binding: %T", i)
   762  						}
   763  					}
   764  				} else {
   765  					for _, pc := range *aps {
   766  						ap := &code[base+pc]
   767  						switch i := (*ap).(type) {
   768  						case loadStack:
   769  							*ap = loadStack(idx)
   770  						case storeStack:
   771  							*ap = storeStack(idx)
   772  						case storeStackP:
   773  							*ap = storeStackP(idx)
   774  						case loadStackLex:
   775  							*ap = loadStackLex(idx)
   776  						case storeStackLex:
   777  							*ap = storeStackLex(idx)
   778  						case storeStackLexP:
   779  							*ap = storeStackLexP(idx)
   780  						case initStack:
   781  							*ap = initStack(idx)
   782  						case initStackP:
   783  							*ap = initStackP(idx)
   784  						case *loadMixed:
   785  							*ap = &loadMixedStack{name: i.name, idx: idx, level: uint8(level), callee: i.callee}
   786  						case *loadMixedLex:
   787  							*ap = &loadMixedStackLex{name: i.name, idx: idx, level: uint8(level), callee: i.callee}
   788  						case *resolveMixed:
   789  							*ap = &resolveMixedStack{typ: i.typ, name: i.name, idx: idx, level: uint8(level), strict: i.strict}
   790  						default:
   791  							s.c.assert(false, s.c.p.sourceOffset(pc), "Unsupported instruction for binding: %T", i)
   792  						}
   793  					}
   794  				}
   795  			}
   796  		}
   797  	}
   798  	for _, nested := range s.nested {
   799  		nested.finaliseVarAlloc(stackIdx + stackOffset)
   800  	}
   801  	return stashIdx, stackIdx
   802  }
   803  
   804  func (s *scope) moveArgsToStash() {
   805  	for _, b := range s.bindings {
   806  		if !b.isArg {
   807  			break
   808  		}
   809  		b.inStash = true
   810  	}
   811  	s.argsInStash = true
   812  	s.needStash = true
   813  }
   814  
   815  func (c *compiler) trimCode(delta int) {
   816  	src := c.p.code[delta:]
   817  	newCode := make([]instruction, len(src))
   818  	copy(newCode, src)
   819  	if cap(c.codeScratchpad) < cap(c.p.code) {
   820  		c.codeScratchpad = c.p.code[:0]
   821  	}
   822  	c.p.code = newCode
   823  }
   824  
   825  func (s *scope) trimCode(delta int) {
   826  	s.c.trimCode(delta)
   827  	if delta != 0 {
   828  		srcMap := s.c.p.srcMap
   829  		for i := range srcMap {
   830  			srcMap[i].pc -= delta
   831  		}
   832  		s.adjustBase(-delta)
   833  	}
   834  }
   835  
   836  func (s *scope) adjustBase(delta int) {
   837  	s.base += delta
   838  	for _, nested := range s.nested {
   839  		nested.adjustBase(delta)
   840  	}
   841  }
   842  
   843  func (s *scope) makeNamesMap() map[unistring.String]uint32 {
   844  	l := len(s.bindings)
   845  	if l == 0 {
   846  		return nil
   847  	}
   848  	names := make(map[unistring.String]uint32, l)
   849  	for i, b := range s.bindings {
   850  		idx := uint32(i)
   851  		if b.isConst {
   852  			idx |= maskConst
   853  			if b.isStrict {
   854  				idx |= maskStrict
   855  			}
   856  		}
   857  		if b.isVar {
   858  			idx |= maskVar
   859  		}
   860  		names[b.name] = idx
   861  	}
   862  	return names
   863  }
   864  
   865  func (s *scope) isDynamic() bool {
   866  	return s.dynLookup || s.dynamic
   867  }
   868  
   869  func (s *scope) isFunction() bool {
   870  	return s.funcType != funcNone && !s.eval
   871  }
   872  
   873  func (s *scope) deleteBinding(b *binding) {
   874  	idx := 0
   875  	for i, bb := range s.bindings {
   876  		if bb == b {
   877  			idx = i
   878  			goto found
   879  		}
   880  	}
   881  	return
   882  found:
   883  	delete(s.boundNames, b.name)
   884  	copy(s.bindings[idx:], s.bindings[idx+1:])
   885  	l := len(s.bindings) - 1
   886  	s.bindings[l] = nil
   887  	s.bindings = s.bindings[:l]
   888  }
   889  
   890  func (c *compiler) compile(in *ast.Program, strict, inGlobal bool, evalVm *vm) {
   891  	c.ctxVM = evalVm
   892  
   893  	eval := evalVm != nil
   894  	c.p.src = in.File
   895  	c.newScope()
   896  	scope := c.scope
   897  	scope.dynamic = true
   898  	scope.eval = eval
   899  	if !strict && len(in.Body) > 0 {
   900  		strict = c.isStrict(in.Body) != nil
   901  	}
   902  	scope.strict = strict
   903  	ownVarScope := eval && strict
   904  	ownLexScope := !inGlobal || eval
   905  	if ownVarScope {
   906  		c.newBlockScope()
   907  		scope = c.scope
   908  		scope.variable = true
   909  	}
   910  	if eval && !inGlobal {
   911  		for s := evalVm.stash; s != nil; s = s.outer {
   912  			if ft := s.funcType; ft != funcNone && ft != funcArrow {
   913  				scope.funcType = ft
   914  				break
   915  			}
   916  		}
   917  	}
   918  	funcs := c.extractFunctions(in.Body)
   919  	c.createFunctionBindings(funcs)
   920  	numFuncs := len(scope.bindings)
   921  	if inGlobal && !ownVarScope {
   922  		if numFuncs == len(funcs) {
   923  			c.compileFunctionsGlobalAllUnique(funcs)
   924  		} else {
   925  			c.compileFunctionsGlobal(funcs)
   926  		}
   927  	}
   928  	c.compileDeclList(in.DeclarationList, false)
   929  	numVars := len(scope.bindings) - numFuncs
   930  	vars := make([]unistring.String, len(scope.bindings))
   931  	for i, b := range scope.bindings {
   932  		vars[i] = b.name
   933  	}
   934  	if len(vars) > 0 && !ownVarScope && ownLexScope {
   935  		if inGlobal {
   936  			c.emit(&bindGlobal{
   937  				vars:      vars[numFuncs:],
   938  				funcs:     vars[:numFuncs],
   939  				deletable: eval,
   940  			})
   941  		} else {
   942  			c.emit(&bindVars{names: vars, deletable: eval})
   943  		}
   944  	}
   945  	var enter *enterBlock
   946  	if c.compileLexicalDeclarations(in.Body, ownVarScope || !ownLexScope) {
   947  		if ownLexScope {
   948  			c.block = &block{
   949  				outer:      c.block,
   950  				typ:        blockScope,
   951  				needResult: true,
   952  			}
   953  			enter = &enterBlock{}
   954  			c.emit(enter)
   955  		}
   956  	}
   957  	if len(scope.bindings) > 0 && !ownLexScope {
   958  		var lets, consts []unistring.String
   959  		for _, b := range c.scope.bindings[numFuncs+numVars:] {
   960  			if b.isConst {
   961  				consts = append(consts, b.name)
   962  			} else {
   963  				lets = append(lets, b.name)
   964  			}
   965  		}
   966  		c.emit(&bindGlobal{
   967  			vars:   vars[numFuncs:],
   968  			funcs:  vars[:numFuncs],
   969  			lets:   lets,
   970  			consts: consts,
   971  		})
   972  	}
   973  	if !inGlobal || ownVarScope {
   974  		c.compileFunctions(funcs)
   975  	}
   976  	c.compileStatements(in.Body, true)
   977  	if enter != nil {
   978  		c.leaveScopeBlock(enter)
   979  		c.popScope()
   980  	}
   981  
   982  	scope.finaliseVarAlloc(0)
   983  }
   984  
   985  func (c *compiler) compileDeclList(v []*ast.VariableDeclaration, inFunc bool) {
   986  	for _, value := range v {
   987  		c.createVarBindings(value, inFunc)
   988  	}
   989  }
   990  
   991  func (c *compiler) extractLabelled(st ast.Statement) ast.Statement {
   992  	if st, ok := st.(*ast.LabelledStatement); ok {
   993  		return c.extractLabelled(st.Statement)
   994  	}
   995  	return st
   996  }
   997  
   998  func (c *compiler) extractFunctions(list []ast.Statement) (funcs []*ast.FunctionDeclaration) {
   999  	for _, st := range list {
  1000  		var decl *ast.FunctionDeclaration
  1001  		switch st := c.extractLabelled(st).(type) {
  1002  		case *ast.FunctionDeclaration:
  1003  			decl = st
  1004  		case *ast.LabelledStatement:
  1005  			if st1, ok := st.Statement.(*ast.FunctionDeclaration); ok {
  1006  				decl = st1
  1007  			} else {
  1008  				continue
  1009  			}
  1010  		default:
  1011  			continue
  1012  		}
  1013  		funcs = append(funcs, decl)
  1014  	}
  1015  	return
  1016  }
  1017  
  1018  func (c *compiler) createFunctionBindings(funcs []*ast.FunctionDeclaration) {
  1019  	s := c.scope
  1020  	if s.outer != nil {
  1021  		unique := !s.isFunction() && !s.variable && s.strict
  1022  		if !unique {
  1023  			hasNonStandard := false
  1024  			for _, decl := range funcs {
  1025  				if !decl.Function.Async && !decl.Function.Generator {
  1026  					s.bindNameLexical(decl.Function.Name.Name, false, int(decl.Function.Name.Idx1())-1)
  1027  				} else {
  1028  					hasNonStandard = true
  1029  				}
  1030  			}
  1031  			if hasNonStandard {
  1032  				for _, decl := range funcs {
  1033  					if decl.Function.Async || decl.Function.Generator {
  1034  						s.bindNameLexical(decl.Function.Name.Name, true, int(decl.Function.Name.Idx1())-1)
  1035  					}
  1036  				}
  1037  			}
  1038  		} else {
  1039  			for _, decl := range funcs {
  1040  				s.bindNameLexical(decl.Function.Name.Name, true, int(decl.Function.Name.Idx1())-1)
  1041  			}
  1042  		}
  1043  	} else {
  1044  		for _, decl := range funcs {
  1045  			s.bindName(decl.Function.Name.Name)
  1046  		}
  1047  	}
  1048  }
  1049  
  1050  func (c *compiler) compileFunctions(list []*ast.FunctionDeclaration) {
  1051  	for _, decl := range list {
  1052  		c.compileFunction(decl)
  1053  	}
  1054  }
  1055  
  1056  func (c *compiler) compileFunctionsGlobalAllUnique(list []*ast.FunctionDeclaration) {
  1057  	for _, decl := range list {
  1058  		c.compileFunctionLiteral(decl.Function, false).emitGetter(true)
  1059  	}
  1060  }
  1061  
  1062  func (c *compiler) compileFunctionsGlobal(list []*ast.FunctionDeclaration) {
  1063  	m := make(map[unistring.String]int, len(list))
  1064  	for i := len(list) - 1; i >= 0; i-- {
  1065  		name := list[i].Function.Name.Name
  1066  		if _, exists := m[name]; !exists {
  1067  			m[name] = i
  1068  		}
  1069  	}
  1070  	idx := 0
  1071  	for i, decl := range list {
  1072  		name := decl.Function.Name.Name
  1073  		if m[name] == i {
  1074  			c.compileFunctionLiteral(decl.Function, false).emitGetter(true)
  1075  			c.scope.bindings[idx] = c.scope.boundNames[name]
  1076  			idx++
  1077  		} else {
  1078  			leave := c.enterDummyMode()
  1079  			c.compileFunctionLiteral(decl.Function, false).emitGetter(false)
  1080  			leave()
  1081  		}
  1082  	}
  1083  }
  1084  
  1085  func (c *compiler) createVarIdBinding(name unistring.String, offset int, inFunc bool) {
  1086  	if c.scope.strict {
  1087  		c.checkIdentifierLName(name, offset)
  1088  		c.checkIdentifierName(name, offset)
  1089  	}
  1090  	if !inFunc || name != "arguments" {
  1091  		c.scope.bindName(name)
  1092  	}
  1093  }
  1094  
  1095  func (c *compiler) createBindings(target ast.Expression, createIdBinding func(name unistring.String, offset int)) {
  1096  	switch target := target.(type) {
  1097  	case *ast.Identifier:
  1098  		createIdBinding(target.Name, int(target.Idx)-1)
  1099  	case *ast.ObjectPattern:
  1100  		for _, prop := range target.Properties {
  1101  			switch prop := prop.(type) {
  1102  			case *ast.PropertyShort:
  1103  				createIdBinding(prop.Name.Name, int(prop.Name.Idx)-1)
  1104  			case *ast.PropertyKeyed:
  1105  				c.createBindings(prop.Value, createIdBinding)
  1106  			default:
  1107  				c.throwSyntaxError(int(target.Idx0()-1), "unsupported property type in ObjectPattern: %T", prop)
  1108  			}
  1109  		}
  1110  		if target.Rest != nil {
  1111  			c.createBindings(target.Rest, createIdBinding)
  1112  		}
  1113  	case *ast.ArrayPattern:
  1114  		for _, elt := range target.Elements {
  1115  			if elt != nil {
  1116  				c.createBindings(elt, createIdBinding)
  1117  			}
  1118  		}
  1119  		if target.Rest != nil {
  1120  			c.createBindings(target.Rest, createIdBinding)
  1121  		}
  1122  	case *ast.AssignExpression:
  1123  		c.createBindings(target.Left, createIdBinding)
  1124  	default:
  1125  		c.throwSyntaxError(int(target.Idx0()-1), "unsupported binding target: %T", target)
  1126  	}
  1127  }
  1128  
  1129  func (c *compiler) createVarBinding(target ast.Expression, inFunc bool) {
  1130  	c.createBindings(target, func(name unistring.String, offset int) {
  1131  		c.createVarIdBinding(name, offset, inFunc)
  1132  	})
  1133  }
  1134  
  1135  func (c *compiler) createVarBindings(v *ast.VariableDeclaration, inFunc bool) {
  1136  	for _, item := range v.List {
  1137  		c.createVarBinding(item.Target, inFunc)
  1138  	}
  1139  }
  1140  
  1141  func (c *compiler) createLexicalIdBinding(name unistring.String, isConst bool, offset int) *binding {
  1142  	if name == "let" {
  1143  		c.throwSyntaxError(offset, "let is disallowed as a lexically bound name")
  1144  	}
  1145  	if c.scope.strict {
  1146  		c.checkIdentifierLName(name, offset)
  1147  		c.checkIdentifierName(name, offset)
  1148  	}
  1149  	b, _ := c.scope.bindNameLexical(name, true, offset)
  1150  	if isConst {
  1151  		b.isConst, b.isStrict = true, true
  1152  	}
  1153  	return b
  1154  }
  1155  
  1156  func (c *compiler) createLexicalIdBindingFuncBody(name unistring.String, isConst bool, offset int, calleeBinding *binding) *binding {
  1157  	if name == "let" {
  1158  		c.throwSyntaxError(offset, "let is disallowed as a lexically bound name")
  1159  	}
  1160  	if c.scope.strict {
  1161  		c.checkIdentifierLName(name, offset)
  1162  		c.checkIdentifierName(name, offset)
  1163  	}
  1164  	paramScope := c.scope.outer
  1165  	parentBinding := paramScope.boundNames[name]
  1166  	if parentBinding != nil {
  1167  		if parentBinding != calleeBinding && (name != "arguments" || !paramScope.argsNeeded) {
  1168  			c.throwSyntaxError(offset, "Identifier '%s' has already been declared", name)
  1169  		}
  1170  	}
  1171  	b, _ := c.scope.bindNameLexical(name, true, offset)
  1172  	if isConst {
  1173  		b.isConst, b.isStrict = true, true
  1174  	}
  1175  	return b
  1176  }
  1177  
  1178  func (c *compiler) createLexicalBinding(target ast.Expression, isConst bool) {
  1179  	c.createBindings(target, func(name unistring.String, offset int) {
  1180  		c.createLexicalIdBinding(name, isConst, offset)
  1181  	})
  1182  }
  1183  
  1184  func (c *compiler) createLexicalBindings(lex *ast.LexicalDeclaration) {
  1185  	for _, d := range lex.List {
  1186  		c.createLexicalBinding(d.Target, lex.Token == token.CONST)
  1187  	}
  1188  }
  1189  
  1190  func (c *compiler) compileLexicalDeclarations(list []ast.Statement, scopeDeclared bool) bool {
  1191  	for _, st := range list {
  1192  		if lex, ok := st.(*ast.LexicalDeclaration); ok {
  1193  			if !scopeDeclared {
  1194  				c.newBlockScope()
  1195  				scopeDeclared = true
  1196  			}
  1197  			c.createLexicalBindings(lex)
  1198  		} else if cls, ok := st.(*ast.ClassDeclaration); ok {
  1199  			if !scopeDeclared {
  1200  				c.newBlockScope()
  1201  				scopeDeclared = true
  1202  			}
  1203  			c.createLexicalIdBinding(cls.Class.Name.Name, false, int(cls.Class.Name.Idx)-1)
  1204  		}
  1205  	}
  1206  	return scopeDeclared
  1207  }
  1208  
  1209  func (c *compiler) compileLexicalDeclarationsFuncBody(list []ast.Statement, calleeBinding *binding) {
  1210  	for _, st := range list {
  1211  		if lex, ok := st.(*ast.LexicalDeclaration); ok {
  1212  			isConst := lex.Token == token.CONST
  1213  			for _, d := range lex.List {
  1214  				c.createBindings(d.Target, func(name unistring.String, offset int) {
  1215  					c.createLexicalIdBindingFuncBody(name, isConst, offset, calleeBinding)
  1216  				})
  1217  			}
  1218  		}
  1219  	}
  1220  }
  1221  
  1222  func (c *compiler) compileFunction(v *ast.FunctionDeclaration) {
  1223  	name := v.Function.Name.Name
  1224  	b := c.scope.boundNames[name]
  1225  	if b == nil || b.isVar {
  1226  		e := &compiledIdentifierExpr{
  1227  			name: v.Function.Name.Name,
  1228  		}
  1229  		e.init(c, v.Function.Idx0())
  1230  		e.emitSetter(c.compileFunctionLiteral(v.Function, false), false)
  1231  	} else {
  1232  		c.compileFunctionLiteral(v.Function, false).emitGetter(true)
  1233  		b.emitInitP()
  1234  	}
  1235  }
  1236  
  1237  func (c *compiler) compileStandaloneFunctionDecl(v *ast.FunctionDeclaration) {
  1238  	if v.Function.Async {
  1239  		c.throwSyntaxError(int(v.Idx0())-1, "Async functions can only be declared at top level or inside a block.")
  1240  	}
  1241  	if v.Function.Generator {
  1242  		c.throwSyntaxError(int(v.Idx0())-1, "Generators can only be declared at top level or inside a block.")
  1243  	}
  1244  	if c.scope.strict {
  1245  		c.throwSyntaxError(int(v.Idx0())-1, "In strict mode code, functions can only be declared at top level or inside a block.")
  1246  	}
  1247  	c.throwSyntaxError(int(v.Idx0())-1, "In non-strict mode code, functions can only be declared at top level, inside a block, or as the body of an if statement.")
  1248  }
  1249  
  1250  func (c *compiler) emit(instructions ...instruction) {
  1251  	c.p.code = append(c.p.code, instructions...)
  1252  }
  1253  
  1254  func (c *compiler) throwSyntaxError(offset int, format string, args ...interface{}) {
  1255  	panic(&CompilerSyntaxError{
  1256  		CompilerError: CompilerError{
  1257  			File:    c.p.src,
  1258  			Offset:  offset,
  1259  			Message: fmt.Sprintf(format, args...),
  1260  		},
  1261  	})
  1262  }
  1263  
  1264  func (c *compiler) isStrict(list []ast.Statement) *ast.StringLiteral {
  1265  	for _, st := range list {
  1266  		if st, ok := st.(*ast.ExpressionStatement); ok {
  1267  			if e, ok := st.Expression.(*ast.StringLiteral); ok {
  1268  				if e.Literal == `"use strict"` || e.Literal == `'use strict'` {
  1269  					return e
  1270  				}
  1271  			} else {
  1272  				break
  1273  			}
  1274  		} else {
  1275  			break
  1276  		}
  1277  	}
  1278  	return nil
  1279  }
  1280  
  1281  func (c *compiler) isStrictStatement(s ast.Statement) *ast.StringLiteral {
  1282  	if s, ok := s.(*ast.BlockStatement); ok {
  1283  		return c.isStrict(s.List)
  1284  	}
  1285  	return nil
  1286  }
  1287  
  1288  func (c *compiler) checkIdentifierName(name unistring.String, offset int) {
  1289  	switch name {
  1290  	case "implements", "interface", "let", "package", "private", "protected", "public", "static", "yield":
  1291  		c.throwSyntaxError(offset, "Unexpected strict mode reserved word")
  1292  	}
  1293  }
  1294  
  1295  func (c *compiler) checkIdentifierLName(name unistring.String, offset int) {
  1296  	switch name {
  1297  	case "eval", "arguments":
  1298  		c.throwSyntaxError(offset, "Assignment to eval or arguments is not allowed in strict mode")
  1299  	}
  1300  }
  1301  
  1302  // Enter a 'dummy' compilation mode. Any code produced after this method is called will be discarded after
  1303  // leaveFunc is called with no additional side effects. This is useful for compiling code inside a
  1304  // constant falsy condition 'if' branch or a loop (i.e 'if (false) { ... } or while (false) { ... }).
  1305  // Such code should not be included in the final compilation result as it's never called, but it must
  1306  // still produce compilation errors if there are any.
  1307  // TODO: make sure variable lookups do not de-optimise parent scopes
  1308  func (c *compiler) enterDummyMode() (leaveFunc func()) {
  1309  	savedBlock, savedProgram := c.block, c.p
  1310  	if savedBlock != nil {
  1311  		c.block = &block{
  1312  			typ:      savedBlock.typ,
  1313  			label:    savedBlock.label,
  1314  			outer:    savedBlock.outer,
  1315  			breaking: savedBlock.breaking,
  1316  		}
  1317  	}
  1318  	c.p = &Program{
  1319  		src: c.p.src,
  1320  	}
  1321  	c.newScope()
  1322  	return func() {
  1323  		c.block, c.p = savedBlock, savedProgram
  1324  		c.popScope()
  1325  	}
  1326  }
  1327  
  1328  func (c *compiler) compileStatementDummy(statement ast.Statement) {
  1329  	leave := c.enterDummyMode()
  1330  	c.compileStatement(statement, false)
  1331  	leave()
  1332  }
  1333  
  1334  func (c *compiler) assert(cond bool, offset int, msg string, args ...interface{}) {
  1335  	if !cond {
  1336  		c.throwSyntaxError(offset, "Compiler bug: "+msg, args...)
  1337  	}
  1338  }
  1339  
  1340  func privateIdString(desc unistring.String) unistring.String {
  1341  	return asciiString("#").Concat(stringValueFromRaw(desc)).string()
  1342  }
  1343  
  1344  type privateName struct {
  1345  	idx                  int
  1346  	isStatic             bool
  1347  	isMethod             bool
  1348  	hasGetter, hasSetter bool
  1349  }
  1350  
  1351  type resolvedPrivateName struct {
  1352  	name     unistring.String
  1353  	idx      uint32
  1354  	level    uint8
  1355  	isStatic bool
  1356  	isMethod bool
  1357  }
  1358  
  1359  func (r *resolvedPrivateName) string() unistring.String {
  1360  	return privateIdString(r.name)
  1361  }
  1362  
  1363  type privateEnvRegistry struct {
  1364  	fields, methods []unistring.String
  1365  }
  1366  
  1367  type classScope struct {
  1368  	c            *compiler
  1369  	privateNames map[unistring.String]*privateName
  1370  
  1371  	instanceEnv, staticEnv privateEnvRegistry
  1372  
  1373  	outer *classScope
  1374  }
  1375  
  1376  func (r *privateEnvRegistry) createPrivateMethodId(name unistring.String) int {
  1377  	r.methods = append(r.methods, name)
  1378  	return len(r.methods) - 1
  1379  }
  1380  
  1381  func (r *privateEnvRegistry) createPrivateFieldId(name unistring.String) int {
  1382  	r.fields = append(r.fields, name)
  1383  	return len(r.fields) - 1
  1384  }
  1385  
  1386  func (s *classScope) declarePrivateId(name unistring.String, kind ast.PropertyKind, isStatic bool, offset int) {
  1387  	pn := s.privateNames[name]
  1388  	if pn != nil {
  1389  		if pn.isStatic == isStatic {
  1390  			switch kind {
  1391  			case ast.PropertyKindGet:
  1392  				if pn.hasSetter && !pn.hasGetter {
  1393  					pn.hasGetter = true
  1394  					return
  1395  				}
  1396  			case ast.PropertyKindSet:
  1397  				if pn.hasGetter && !pn.hasSetter {
  1398  					pn.hasSetter = true
  1399  					return
  1400  				}
  1401  			}
  1402  		}
  1403  		s.c.throwSyntaxError(offset, "Identifier '#%s' has already been declared", name)
  1404  		panic("unreachable")
  1405  	}
  1406  	var env *privateEnvRegistry
  1407  	if isStatic {
  1408  		env = &s.staticEnv
  1409  	} else {
  1410  		env = &s.instanceEnv
  1411  	}
  1412  
  1413  	pn = &privateName{
  1414  		isStatic:  isStatic,
  1415  		hasGetter: kind == ast.PropertyKindGet,
  1416  		hasSetter: kind == ast.PropertyKindSet,
  1417  	}
  1418  	if kind != ast.PropertyKindValue {
  1419  		pn.idx = env.createPrivateMethodId(name)
  1420  		pn.isMethod = true
  1421  	} else {
  1422  		pn.idx = env.createPrivateFieldId(name)
  1423  	}
  1424  
  1425  	if s.privateNames == nil {
  1426  		s.privateNames = make(map[unistring.String]*privateName)
  1427  	}
  1428  	s.privateNames[name] = pn
  1429  }
  1430  
  1431  func (s *classScope) getDeclaredPrivateId(name unistring.String) *privateName {
  1432  	if n := s.privateNames[name]; n != nil {
  1433  		return n
  1434  	}
  1435  	s.c.assert(false, 0, "getDeclaredPrivateId() for undeclared id")
  1436  	panic("unreachable")
  1437  }
  1438  
  1439  func (c *compiler) resolvePrivateName(name unistring.String, offset int) (*resolvedPrivateName, *privateId) {
  1440  	level := 0
  1441  	for s := c.classScope; s != nil; s = s.outer {
  1442  		if len(s.privateNames) > 0 {
  1443  			if pn := s.privateNames[name]; pn != nil {
  1444  				return &resolvedPrivateName{
  1445  					name:     name,
  1446  					idx:      uint32(pn.idx),
  1447  					level:    uint8(level),
  1448  					isStatic: pn.isStatic,
  1449  					isMethod: pn.isMethod,
  1450  				}, nil
  1451  			}
  1452  			level++
  1453  		}
  1454  	}
  1455  	if c.ctxVM != nil {
  1456  		for s := c.ctxVM.privEnv; s != nil; s = s.outer {
  1457  			if id := s.names[name]; id != nil {
  1458  				return nil, id
  1459  			}
  1460  		}
  1461  	}
  1462  	c.throwSyntaxError(offset, "Private field '#%s' must be declared in an enclosing class", name)
  1463  	panic("unreachable")
  1464  }