go.ketch.com/lib/goja@v0.0.1/compiler.go (about)

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