1package goja
2
3import (
4	"hash/maphash"
5	"math"
6	"reflect"
7	"strconv"
8	"unsafe"
9
10	"github.com/dop251/goja/ftoa"
11	"github.com/dop251/goja/unistring"
12)
13
14var (
15	// Not goroutine-safe, do not use for anything other than package level init
16	pkgHasher maphash.Hash
17
18	hashFalse = randomHash()
19	hashTrue  = randomHash()
20	hashNull  = randomHash()
21	hashUndef = randomHash()
22)
23
24// Not goroutine-safe, do not use for anything other than package level init
25func randomHash() uint64 {
26	pkgHasher.WriteByte(0)
27	return pkgHasher.Sum64()
28}
29
30var (
31	valueFalse    Value = valueBool(false)
32	valueTrue     Value = valueBool(true)
33	_null         Value = valueNull{}
34	_NaN          Value = valueFloat(math.NaN())
35	_positiveInf  Value = valueFloat(math.Inf(+1))
36	_negativeInf  Value = valueFloat(math.Inf(-1))
37	_positiveZero Value = valueInt(0)
38	negativeZero        = math.Float64frombits(0 | (1 << 63))
39	_negativeZero Value = valueFloat(negativeZero)
40	_epsilon            = valueFloat(2.2204460492503130808472633361816e-16)
41	_undefined    Value = valueUndefined{}
42)
43
44var (
45	reflectTypeInt    = reflect.TypeOf(int64(0))
46	reflectTypeBool   = reflect.TypeOf(false)
47	reflectTypeNil    = reflect.TypeOf(nil)
48	reflectTypeFloat  = reflect.TypeOf(float64(0))
49	reflectTypeMap    = reflect.TypeOf(map[string]interface{}{})
50	reflectTypeArray  = reflect.TypeOf([]interface{}{})
51	reflectTypeString = reflect.TypeOf("")
52)
53
54var intCache [256]Value
55
56type Value interface {
57	ToInteger() int64
58	toString() valueString
59	string() unistring.String
60	ToString() Value
61	String() string
62	ToFloat() float64
63	ToNumber() Value
64	ToBoolean() bool
65	ToObject(*Runtime) *Object
66	SameAs(Value) bool
67	Equals(Value) bool
68	StrictEquals(Value) bool
69	Export() interface{}
70	ExportType() reflect.Type
71
72	baseObject(r *Runtime) *Object
73
74	hash(hasher *maphash.Hash) uint64
75}
76
77type valueContainer interface {
78	toValue(*Runtime) Value
79}
80
81type typeError string
82type rangeError string
83type referenceError string
84
85type valueInt int64
86type valueFloat float64
87type valueBool bool
88type valueNull struct{}
89type valueUndefined struct {
90	valueNull
91}
92
93// *Symbol is a Value containing ECMAScript Symbol primitive. Symbols must only be created
94// using NewSymbol(). Zero values and copying of values (i.e. *s1 = *s2) are not permitted.
95// Well-known Symbols can be accessed using Sym* package variables (SymIterator, etc...)
96// Symbols can be shared by multiple Runtimes.
97type Symbol struct {
98	h    uintptr
99	desc valueString
100}
101
102type valueUnresolved struct {
103	r   *Runtime
104	ref unistring.String
105}
106
107type memberUnresolved struct {
108	valueUnresolved
109}
110
111type valueProperty struct {
112	value        Value
113	writable     bool
114	configurable bool
115	enumerable   bool
116	accessor     bool
117	getterFunc   *Object
118	setterFunc   *Object
119}
120
121var (
122	errAccessBeforeInit = referenceError("Cannot access a variable before initialization")
123	errAssignToConst    = typeError("Assignment to constant variable.")
124)
125
126func propGetter(o Value, v Value, r *Runtime) *Object {
127	if v == _undefined {
128		return nil
129	}
130	if obj, ok := v.(*Object); ok {
131		if _, ok := obj.self.assertCallable(); ok {
132			return obj
133		}
134	}
135	r.typeErrorResult(true, "Getter must be a function: %s", v.toString())
136	return nil
137}
138
139func propSetter(o Value, v Value, r *Runtime) *Object {
140	if v == _undefined {
141		return nil
142	}
143	if obj, ok := v.(*Object); ok {
144		if _, ok := obj.self.assertCallable(); ok {
145			return obj
146		}
147	}
148	r.typeErrorResult(true, "Setter must be a function: %s", v.toString())
149	return nil
150}
151
152func fToStr(num float64, mode ftoa.FToStrMode, prec int) string {
153	var buf1 [128]byte
154	return string(ftoa.FToStr(num, mode, prec, buf1[:0]))
155}
156
157func (i valueInt) ToInteger() int64 {
158	return int64(i)
159}
160
161func (i valueInt) toString() valueString {
162	return asciiString(i.String())
163}
164
165func (i valueInt) string() unistring.String {
166	return unistring.String(i.String())
167}
168
169func (i valueInt) ToString() Value {
170	return i
171}
172
173func (i valueInt) String() string {
174	return strconv.FormatInt(int64(i), 10)
175}
176
177func (i valueInt) ToFloat() float64 {
178	return float64(i)
179}
180
181func (i valueInt) ToBoolean() bool {
182	return i != 0
183}
184
185func (i valueInt) ToObject(r *Runtime) *Object {
186	return r.newPrimitiveObject(i, r.global.NumberPrototype, classNumber)
187}
188
189func (i valueInt) ToNumber() Value {
190	return i
191}
192
193func (i valueInt) SameAs(other Value) bool {
194	return i == other
195}
196
197func (i valueInt) Equals(other Value) bool {
198	switch o := other.(type) {
199	case valueInt:
200		return i == o
201	case valueFloat:
202		return float64(i) == float64(o)
203	case valueString:
204		return o.ToNumber().Equals(i)
205	case valueBool:
206		return int64(i) == o.ToInteger()
207	case *Object:
208		return i.Equals(o.toPrimitive())
209	}
210
211	return false
212}
213
214func (i valueInt) StrictEquals(other Value) bool {
215	switch o := other.(type) {
216	case valueInt:
217		return i == o
218	case valueFloat:
219		return float64(i) == float64(o)
220	}
221
222	return false
223}
224
225func (i valueInt) baseObject(r *Runtime) *Object {
226	return r.global.NumberPrototype
227}
228
229func (i valueInt) Export() interface{} {
230	return int64(i)
231}
232
233func (i valueInt) ExportType() reflect.Type {
234	return reflectTypeInt
235}
236
237func (i valueInt) hash(*maphash.Hash) uint64 {
238	return uint64(i)
239}
240
241func (b valueBool) ToInteger() int64 {
242	if b {
243		return 1
244	}
245	return 0
246}
247
248func (b valueBool) toString() valueString {
249	if b {
250		return stringTrue
251	}
252	return stringFalse
253}
254
255func (b valueBool) ToString() Value {
256	return b
257}
258
259func (b valueBool) String() string {
260	if b {
261		return "true"
262	}
263	return "false"
264}
265
266func (b valueBool) string() unistring.String {
267	return unistring.String(b.String())
268}
269
270func (b valueBool) ToFloat() float64 {
271	if b {
272		return 1.0
273	}
274	return 0
275}
276
277func (b valueBool) ToBoolean() bool {
278	return bool(b)
279}
280
281func (b valueBool) ToObject(r *Runtime) *Object {
282	return r.newPrimitiveObject(b, r.global.BooleanPrototype, "Boolean")
283}
284
285func (b valueBool) ToNumber() Value {
286	if b {
287		return valueInt(1)
288	}
289	return valueInt(0)
290}
291
292func (b valueBool) SameAs(other Value) bool {
293	if other, ok := other.(valueBool); ok {
294		return b == other
295	}
296	return false
297}
298
299func (b valueBool) Equals(other Value) bool {
300	if o, ok := other.(valueBool); ok {
301		return b == o
302	}
303
304	if b {
305		return other.Equals(intToValue(1))
306	} else {
307		return other.Equals(intToValue(0))
308	}
309
310}
311
312func (b valueBool) StrictEquals(other Value) bool {
313	if other, ok := other.(valueBool); ok {
314		return b == other
315	}
316	return false
317}
318
319func (b valueBool) baseObject(r *Runtime) *Object {
320	return r.global.BooleanPrototype
321}
322
323func (b valueBool) Export() interface{} {
324	return bool(b)
325}
326
327func (b valueBool) ExportType() reflect.Type {
328	return reflectTypeBool
329}
330
331func (b valueBool) hash(*maphash.Hash) uint64 {
332	if b {
333		return hashTrue
334	}
335
336	return hashFalse
337}
338
339func (n valueNull) ToInteger() int64 {
340	return 0
341}
342
343func (n valueNull) toString() valueString {
344	return stringNull
345}
346
347func (n valueNull) string() unistring.String {
348	return stringNull.string()
349}
350
351func (n valueNull) ToString() Value {
352	return n
353}
354
355func (n valueNull) String() string {
356	return "null"
357}
358
359func (u valueUndefined) toString() valueString {
360	return stringUndefined
361}
362
363func (u valueUndefined) ToString() Value {
364	return u
365}
366
367func (u valueUndefined) String() string {
368	return "undefined"
369}
370
371func (u valueUndefined) string() unistring.String {
372	return "undefined"
373}
374
375func (u valueUndefined) ToNumber() Value {
376	return _NaN
377}
378
379func (u valueUndefined) SameAs(other Value) bool {
380	_, same := other.(valueUndefined)
381	return same
382}
383
384func (u valueUndefined) StrictEquals(other Value) bool {
385	_, same := other.(valueUndefined)
386	return same
387}
388
389func (u valueUndefined) ToFloat() float64 {
390	return math.NaN()
391}
392
393func (u valueUndefined) hash(*maphash.Hash) uint64 {
394	return hashUndef
395}
396
397func (n valueNull) ToFloat() float64 {
398	return 0
399}
400
401func (n valueNull) ToBoolean() bool {
402	return false
403}
404
405func (n valueNull) ToObject(r *Runtime) *Object {
406	r.typeErrorResult(true, "Cannot convert undefined or null to object")
407	return nil
408	//return r.newObject()
409}
410
411func (n valueNull) ToNumber() Value {
412	return intToValue(0)
413}
414
415func (n valueNull) SameAs(other Value) bool {
416	_, same := other.(valueNull)
417	return same
418}
419
420func (n valueNull) Equals(other Value) bool {
421	switch other.(type) {
422	case valueUndefined, valueNull:
423		return true
424	}
425	return false
426}
427
428func (n valueNull) StrictEquals(other Value) bool {
429	_, same := other.(valueNull)
430	return same
431}
432
433func (n valueNull) baseObject(*Runtime) *Object {
434	return nil
435}
436
437func (n valueNull) Export() interface{} {
438	return nil
439}
440
441func (n valueNull) ExportType() reflect.Type {
442	return reflectTypeNil
443}
444
445func (n valueNull) hash(*maphash.Hash) uint64 {
446	return hashNull
447}
448
449func (p *valueProperty) ToInteger() int64 {
450	return 0
451}
452
453func (p *valueProperty) toString() valueString {
454	return stringEmpty
455}
456
457func (p *valueProperty) string() unistring.String {
458	return ""
459}
460
461func (p *valueProperty) ToString() Value {
462	return _undefined
463}
464
465func (p *valueProperty) String() string {
466	return ""
467}
468
469func (p *valueProperty) ToFloat() float64 {
470	return math.NaN()
471}
472
473func (p *valueProperty) ToBoolean() bool {
474	return false
475}
476
477func (p *valueProperty) ToObject(*Runtime) *Object {
478	return nil
479}
480
481func (p *valueProperty) ToNumber() Value {
482	return nil
483}
484
485func (p *valueProperty) isWritable() bool {
486	return p.writable || p.setterFunc != nil
487}
488
489func (p *valueProperty) get(this Value) Value {
490	if p.getterFunc == nil {
491		if p.value != nil {
492			return p.value
493		}
494		return _undefined
495	}
496	call, _ := p.getterFunc.self.assertCallable()
497	return call(FunctionCall{
498		This: this,
499	})
500}
501
502func (p *valueProperty) set(this, v Value) {
503	if p.setterFunc == nil {
504		p.value = v
505		return
506	}
507	call, _ := p.setterFunc.self.assertCallable()
508	call(FunctionCall{
509		This:      this,
510		Arguments: []Value{v},
511	})
512}
513
514func (p *valueProperty) SameAs(other Value) bool {
515	if otherProp, ok := other.(*valueProperty); ok {
516		return p == otherProp
517	}
518	return false
519}
520
521func (p *valueProperty) Equals(Value) bool {
522	return false
523}
524
525func (p *valueProperty) StrictEquals(Value) bool {
526	return false
527}
528
529func (p *valueProperty) baseObject(r *Runtime) *Object {
530	r.typeErrorResult(true, "BUG: baseObject() is called on valueProperty") // TODO error message
531	return nil
532}
533
534func (p *valueProperty) Export() interface{} {
535	panic("Cannot export valueProperty")
536}
537
538func (p *valueProperty) ExportType() reflect.Type {
539	panic("Cannot export valueProperty")
540}
541
542func (p *valueProperty) hash(*maphash.Hash) uint64 {
543	panic("valueProperty should never be used in maps or sets")
544}
545
546func floatToIntClip(n float64) int64 {
547	switch {
548	case math.IsNaN(n):
549		return 0
550	case n >= math.MaxInt64:
551		return math.MaxInt64
552	case n <= math.MinInt64:
553		return math.MinInt64
554	}
555	return int64(n)
556}
557
558func (f valueFloat) ToInteger() int64 {
559	return floatToIntClip(float64(f))
560}
561
562func (f valueFloat) toString() valueString {
563	return asciiString(f.String())
564}
565
566func (f valueFloat) string() unistring.String {
567	return unistring.String(f.String())
568}
569
570func (f valueFloat) ToString() Value {
571	return f
572}
573
574func (f valueFloat) String() string {
575	return fToStr(float64(f), ftoa.ModeStandard, 0)
576}
577
578func (f valueFloat) ToFloat() float64 {
579	return float64(f)
580}
581
582func (f valueFloat) ToBoolean() bool {
583	return float64(f) != 0.0 && !math.IsNaN(float64(f))
584}
585
586func (f valueFloat) ToObject(r *Runtime) *Object {
587	return r.newPrimitiveObject(f, r.global.NumberPrototype, "Number")
588}
589
590func (f valueFloat) ToNumber() Value {
591	return f
592}
593
594func (f valueFloat) SameAs(other Value) bool {
595	switch o := other.(type) {
596	case valueFloat:
597		this := float64(f)
598		o1 := float64(o)
599		if math.IsNaN(this) && math.IsNaN(o1) {
600			return true
601		} else {
602			ret := this == o1
603			if ret && this == 0 {
604				ret = math.Signbit(this) == math.Signbit(o1)
605			}
606			return ret
607		}
608	case valueInt:
609		this := float64(f)
610		ret := this == float64(o)
611		if ret && this == 0 {
612			ret = !math.Signbit(this)
613		}
614		return ret
615	}
616
617	return false
618}
619
620func (f valueFloat) Equals(other Value) bool {
621	switch o := other.(type) {
622	case valueFloat:
623		return f == o
624	case valueInt:
625		return float64(f) == float64(o)
626	case valueString, valueBool:
627		return float64(f) == o.ToFloat()
628	case *Object:
629		return f.Equals(o.toPrimitive())
630	}
631
632	return false
633}
634
635func (f valueFloat) StrictEquals(other Value) bool {
636	switch o := other.(type) {
637	case valueFloat:
638		return f == o
639	case valueInt:
640		return float64(f) == float64(o)
641	}
642
643	return false
644}
645
646func (f valueFloat) baseObject(r *Runtime) *Object {
647	return r.global.NumberPrototype
648}
649
650func (f valueFloat) Export() interface{} {
651	return float64(f)
652}
653
654func (f valueFloat) ExportType() reflect.Type {
655	return reflectTypeFloat
656}
657
658func (f valueFloat) hash(*maphash.Hash) uint64 {
659	if f == _negativeZero {
660		return 0
661	}
662	return math.Float64bits(float64(f))
663}
664
665func (o *Object) ToInteger() int64 {
666	return o.toPrimitiveNumber().ToNumber().ToInteger()
667}
668
669func (o *Object) toString() valueString {
670	return o.toPrimitiveString().toString()
671}
672
673func (o *Object) string() unistring.String {
674	return o.toPrimitiveString().string()
675}
676
677func (o *Object) ToString() Value {
678	return o.toPrimitiveString().ToString()
679}
680
681func (o *Object) String() string {
682	return o.toPrimitiveString().String()
683}
684
685func (o *Object) ToFloat() float64 {
686	return o.toPrimitiveNumber().ToFloat()
687}
688
689func (o *Object) ToBoolean() bool {
690	return true
691}
692
693func (o *Object) ToObject(*Runtime) *Object {
694	return o
695}
696
697func (o *Object) ToNumber() Value {
698	return o.toPrimitiveNumber().ToNumber()
699}
700
701func (o *Object) SameAs(other Value) bool {
702	if other, ok := other.(*Object); ok {
703		return o == other
704	}
705	return false
706}
707
708func (o *Object) Equals(other Value) bool {
709	if other, ok := other.(*Object); ok {
710		return o == other || o.self.equal(other.self)
711	}
712
713	switch o1 := other.(type) {
714	case valueInt, valueFloat, valueString, *Symbol:
715		return o.toPrimitive().Equals(other)
716	case valueBool:
717		return o.Equals(o1.ToNumber())
718	}
719
720	return false
721}
722
723func (o *Object) StrictEquals(other Value) bool {
724	if other, ok := other.(*Object); ok {
725		return o == other || o.self.equal(other.self)
726	}
727	return false
728}
729
730func (o *Object) baseObject(*Runtime) *Object {
731	return o
732}
733
734// Export the Object to a plain Go type. The returned value will be map[string]interface{} unless
735// the Object is a wrapped Go value (created using ToValue()).
736// This method will panic with an *Exception if a JavaScript exception is thrown in the process.
737func (o *Object) Export() (ret interface{}) {
738	o.runtime.tryPanic(func() {
739		ret = o.self.export(&objectExportCtx{})
740	})
741
742	return
743}
744
745func (o *Object) ExportType() reflect.Type {
746	return o.self.exportType()
747}
748
749func (o *Object) hash(*maphash.Hash) uint64 {
750	return o.getId()
751}
752
753// Get an object's property by name.
754// This method will panic with an *Exception if a JavaScript exception is thrown in the process.
755func (o *Object) Get(name string) Value {
756	return o.self.getStr(unistring.NewFromString(name), nil)
757}
758
759// GetSymbol returns the value of a symbol property. Use one of the Sym* values for well-known
760// symbols (such as SymIterator, SymToStringTag, etc...).
761// This method will panic with an *Exception if a JavaScript exception is thrown in the process.
762func (o *Object) GetSymbol(sym *Symbol) Value {
763	return o.self.getSym(sym, nil)
764}
765
766// Keys returns a list of Object's enumerable keys.
767// This method will panic with an *Exception if a JavaScript exception is thrown in the process.
768func (o *Object) Keys() (keys []string) {
769	iter := &enumerableIter{
770		wrapped: o.self.enumerateOwnKeys(),
771	}
772	for item, next := iter.next(); next != nil; item, next = next() {
773		keys = append(keys, item.name.String())
774	}
775
776	return
777}
778
779// Symbols returns a list of Object's enumerable symbol properties.
780// This method will panic with an *Exception if a JavaScript exception is thrown in the process.
781func (o *Object) Symbols() []*Symbol {
782	symbols := o.self.ownSymbols(false, nil)
783	ret := make([]*Symbol, len(symbols))
784	for i, sym := range symbols {
785		ret[i], _ = sym.(*Symbol)
786	}
787	return ret
788}
789
790// DefineDataProperty is a Go equivalent of Object.defineProperty(o, name, {value: value, writable: writable,
791// configurable: configurable, enumerable: enumerable})
792func (o *Object) DefineDataProperty(name string, value Value, writable, configurable, enumerable Flag) error {
793	return o.runtime.try(func() {
794		o.self.defineOwnPropertyStr(unistring.NewFromString(name), PropertyDescriptor{
795			Value:        value,
796			Writable:     writable,
797			Configurable: configurable,
798			Enumerable:   enumerable,
799		}, true)
800	})
801}
802
803// DefineAccessorProperty is a Go equivalent of Object.defineProperty(o, name, {get: getter, set: setter,
804// configurable: configurable, enumerable: enumerable})
805func (o *Object) DefineAccessorProperty(name string, getter, setter Value, configurable, enumerable Flag) error {
806	return o.runtime.try(func() {
807		o.self.defineOwnPropertyStr(unistring.NewFromString(name), PropertyDescriptor{
808			Getter:       getter,
809			Setter:       setter,
810			Configurable: configurable,
811			Enumerable:   enumerable,
812		}, true)
813	})
814}
815
816// DefineDataPropertySymbol is a Go equivalent of Object.defineProperty(o, name, {value: value, writable: writable,
817// configurable: configurable, enumerable: enumerable})
818func (o *Object) DefineDataPropertySymbol(name *Symbol, value Value, writable, configurable, enumerable Flag) error {
819	return o.runtime.try(func() {
820		o.self.defineOwnPropertySym(name, PropertyDescriptor{
821			Value:        value,
822			Writable:     writable,
823			Configurable: configurable,
824			Enumerable:   enumerable,
825		}, true)
826	})
827}
828
829// DefineAccessorPropertySymbol is a Go equivalent of Object.defineProperty(o, name, {get: getter, set: setter,
830// configurable: configurable, enumerable: enumerable})
831func (o *Object) DefineAccessorPropertySymbol(name *Symbol, getter, setter Value, configurable, enumerable Flag) error {
832	return o.runtime.try(func() {
833		o.self.defineOwnPropertySym(name, PropertyDescriptor{
834			Getter:       getter,
835			Setter:       setter,
836			Configurable: configurable,
837			Enumerable:   enumerable,
838		}, true)
839	})
840}
841
842func (o *Object) Set(name string, value interface{}) error {
843	return o.runtime.try(func() {
844		o.self.setOwnStr(unistring.NewFromString(name), o.runtime.ToValue(value), true)
845	})
846}
847
848func (o *Object) SetSymbol(name *Symbol, value interface{}) error {
849	return o.runtime.try(func() {
850		o.self.setOwnSym(name, o.runtime.ToValue(value), true)
851	})
852}
853
854func (o *Object) Delete(name string) error {
855	return o.runtime.try(func() {
856		o.self.deleteStr(unistring.NewFromString(name), true)
857	})
858}
859
860func (o *Object) DeleteSymbol(name *Symbol) error {
861	return o.runtime.try(func() {
862		o.self.deleteSym(name, true)
863	})
864}
865
866// Prototype returns the Object's prototype, same as Object.getPrototypeOf(). If the prototype is null
867// returns nil.
868func (o *Object) Prototype() *Object {
869	return o.self.proto()
870}
871
872// SetPrototype sets the Object's prototype, same as Object.setPrototypeOf(). Setting proto to nil
873// is an equivalent of Object.setPrototypeOf(null).
874func (o *Object) SetPrototype(proto *Object) error {
875	return o.runtime.try(func() {
876		o.self.setProto(proto, true)
877	})
878}
879
880// MarshalJSON returns JSON representation of the Object. It is equivalent to JSON.stringify(o).
881// Note, this implements json.Marshaler so that json.Marshal() can be used without the need to Export().
882func (o *Object) MarshalJSON() ([]byte, error) {
883	ctx := _builtinJSON_stringifyContext{
884		r: o.runtime,
885	}
886	ex := o.runtime.vm.try(func() {
887		if !ctx.do(o) {
888			ctx.buf.WriteString("null")
889		}
890	})
891	if ex != nil {
892		return nil, ex
893	}
894	return ctx.buf.Bytes(), nil
895}
896
897// ClassName returns the class name
898func (o *Object) ClassName() string {
899	return o.self.className()
900}
901
902func (o valueUnresolved) throw() {
903	o.r.throwReferenceError(o.ref)
904}
905
906func (o valueUnresolved) ToInteger() int64 {
907	o.throw()
908	return 0
909}
910
911func (o valueUnresolved) toString() valueString {
912	o.throw()
913	return nil
914}
915
916func (o valueUnresolved) string() unistring.String {
917	o.throw()
918	return ""
919}
920
921func (o valueUnresolved) ToString() Value {
922	o.throw()
923	return nil
924}
925
926func (o valueUnresolved) String() string {
927	o.throw()
928	return ""
929}
930
931func (o valueUnresolved) ToFloat() float64 {
932	o.throw()
933	return 0
934}
935
936func (o valueUnresolved) ToBoolean() bool {
937	o.throw()
938	return false
939}
940
941func (o valueUnresolved) ToObject(*Runtime) *Object {
942	o.throw()
943	return nil
944}
945
946func (o valueUnresolved) ToNumber() Value {
947	o.throw()
948	return nil
949}
950
951func (o valueUnresolved) SameAs(Value) bool {
952	o.throw()
953	return false
954}
955
956func (o valueUnresolved) Equals(Value) bool {
957	o.throw()
958	return false
959}
960
961func (o valueUnresolved) StrictEquals(Value) bool {
962	o.throw()
963	return false
964}
965
966func (o valueUnresolved) baseObject(*Runtime) *Object {
967	o.throw()
968	return nil
969}
970
971func (o valueUnresolved) Export() interface{} {
972	o.throw()
973	return nil
974}
975
976func (o valueUnresolved) ExportType() reflect.Type {
977	o.throw()
978	return nil
979}
980
981func (o valueUnresolved) hash(*maphash.Hash) uint64 {
982	o.throw()
983	return 0
984}
985
986func (s *Symbol) ToInteger() int64 {
987	panic(typeError("Cannot convert a Symbol value to a number"))
988}
989
990func (s *Symbol) toString() valueString {
991	panic(typeError("Cannot convert a Symbol value to a string"))
992}
993
994func (s *Symbol) ToString() Value {
995	return s
996}
997
998func (s *Symbol) String() string {
999	if s.desc != nil {
1000		return s.desc.String()
1001	}
1002	return ""
1003}
1004
1005func (s *Symbol) string() unistring.String {
1006	if s.desc != nil {
1007		return s.desc.string()
1008	}
1009	return ""
1010}
1011
1012func (s *Symbol) ToFloat() float64 {
1013	panic(typeError("Cannot convert a Symbol value to a number"))
1014}
1015
1016func (s *Symbol) ToNumber() Value {
1017	panic(typeError("Cannot convert a Symbol value to a number"))
1018}
1019
1020func (s *Symbol) ToBoolean() bool {
1021	return true
1022}
1023
1024func (s *Symbol) ToObject(r *Runtime) *Object {
1025	return s.baseObject(r)
1026}
1027
1028func (s *Symbol) SameAs(other Value) bool {
1029	if s1, ok := other.(*Symbol); ok {
1030		return s == s1
1031	}
1032	return false
1033}
1034
1035func (s *Symbol) Equals(o Value) bool {
1036	switch o := o.(type) {
1037	case *Object:
1038		return s.Equals(o.toPrimitive())
1039	}
1040	return s.SameAs(o)
1041}
1042
1043func (s *Symbol) StrictEquals(o Value) bool {
1044	return s.SameAs(o)
1045}
1046
1047func (s *Symbol) Export() interface{} {
1048	return s.String()
1049}
1050
1051func (s *Symbol) ExportType() reflect.Type {
1052	return reflectTypeString
1053}
1054
1055func (s *Symbol) baseObject(r *Runtime) *Object {
1056	return r.newPrimitiveObject(s, r.global.SymbolPrototype, "Symbol")
1057}
1058
1059func (s *Symbol) hash(*maphash.Hash) uint64 {
1060	return uint64(s.h)
1061}
1062
1063func exportValue(v Value, ctx *objectExportCtx) interface{} {
1064	if obj, ok := v.(*Object); ok {
1065		return obj.self.export(ctx)
1066	}
1067	return v.Export()
1068}
1069
1070func newSymbol(s valueString) *Symbol {
1071	r := &Symbol{
1072		desc: s,
1073	}
1074	// This may need to be reconsidered in the future.
1075	// Depending on changes in Go's allocation policy and/or introduction of a compacting GC
1076	// this may no longer provide sufficient dispersion. The alternative, however, is a globally
1077	// synchronised random generator/hasher/sequencer and I don't want to go down that route just yet.
1078	r.h = uintptr(unsafe.Pointer(r))
1079	return r
1080}
1081
1082func NewSymbol(s string) *Symbol {
1083	return newSymbol(newStringValue(s))
1084}
1085
1086func (s *Symbol) descriptiveString() valueString {
1087	desc := s.desc
1088	if desc == nil {
1089		desc = stringEmpty
1090	}
1091	return asciiString("Symbol(").concat(desc).concat(asciiString(")"))
1092}
1093
1094func funcName(prefix string, n Value) valueString {
1095	var b valueStringBuilder
1096	b.WriteString(asciiString(prefix))
1097	if sym, ok := n.(*Symbol); ok {
1098		if sym.desc != nil {
1099			b.WriteRune('[')
1100			b.WriteString(sym.desc)
1101			b.WriteRune(']')
1102		}
1103	} else {
1104		b.WriteString(n.toString())
1105	}
1106	return b.String()
1107}
1108
1109func init() {
1110	for i := 0; i < 256; i++ {
1111		intCache[i] = valueInt(i - 128)
1112	}
1113	_positiveZero = intToValue(0)
1114}
1115