1package goja
2
3import (
4	"math"
5	"reflect"
6	"regexp"
7	"strconv"
8)
9
10var (
11	valueFalse    Value = valueBool(false)
12	valueTrue     Value = valueBool(true)
13	_null         Value = valueNull{}
14	_NaN          Value = valueFloat(math.NaN())
15	_positiveInf  Value = valueFloat(math.Inf(+1))
16	_negativeInf  Value = valueFloat(math.Inf(-1))
17	_positiveZero Value
18	_negativeZero Value = valueFloat(math.Float64frombits(0 | (1 << 63)))
19	_epsilon            = valueFloat(2.2204460492503130808472633361816e-16)
20	_undefined    Value = valueUndefined{}
21)
22
23var (
24	reflectTypeInt    = reflect.TypeOf(int64(0))
25	reflectTypeBool   = reflect.TypeOf(false)
26	reflectTypeNil    = reflect.TypeOf(nil)
27	reflectTypeFloat  = reflect.TypeOf(float64(0))
28	reflectTypeMap    = reflect.TypeOf(map[string]interface{}{})
29	reflectTypeArray  = reflect.TypeOf([]interface{}{})
30	reflectTypeString = reflect.TypeOf("")
31)
32
33var intCache [256]Value
34
35type Value interface {
36	ToInteger() int64
37	ToString() valueString
38	String() string
39	ToFloat() float64
40	ToNumber() Value
41	ToBoolean() bool
42	ToObject(*Runtime) *Object
43	SameAs(Value) bool
44	Equals(Value) bool
45	StrictEquals(Value) bool
46	Export() interface{}
47	ExportType() reflect.Type
48
49	assertInt() (int64, bool)
50	assertString() (valueString, bool)
51	assertFloat() (float64, bool)
52
53	baseObject(r *Runtime) *Object
54}
55
56type valueInt int64
57type valueFloat float64
58type valueBool bool
59type valueNull struct{}
60type valueUndefined struct {
61	valueNull
62}
63
64type valueUnresolved struct {
65	r   *Runtime
66	ref string
67}
68
69type memberUnresolved struct {
70	valueUnresolved
71}
72
73type valueProperty struct {
74	value        Value
75	writable     bool
76	configurable bool
77	enumerable   bool
78	accessor     bool
79	getterFunc   *Object
80	setterFunc   *Object
81}
82
83func propGetter(o Value, v Value, r *Runtime) *Object {
84	if v == _undefined {
85		return nil
86	}
87	if obj, ok := v.(*Object); ok {
88		if _, ok := obj.self.assertCallable(); ok {
89			return obj
90		}
91	}
92	r.typeErrorResult(true, "Getter must be a function: %s", v.ToString())
93	return nil
94}
95
96func propSetter(o Value, v Value, r *Runtime) *Object {
97	if v == _undefined {
98		return nil
99	}
100	if obj, ok := v.(*Object); ok {
101		if _, ok := obj.self.assertCallable(); ok {
102			return obj
103		}
104	}
105	r.typeErrorResult(true, "Setter must be a function: %s", v.ToString())
106	return nil
107}
108
109func (i valueInt) ToInteger() int64 {
110	return int64(i)
111}
112
113func (i valueInt) ToString() valueString {
114	return asciiString(i.String())
115}
116
117func (i valueInt) String() string {
118	return strconv.FormatInt(int64(i), 10)
119}
120
121func (i valueInt) ToFloat() float64 {
122	return float64(int64(i))
123}
124
125func (i valueInt) ToBoolean() bool {
126	return i != 0
127}
128
129func (i valueInt) ToObject(r *Runtime) *Object {
130	return r.newPrimitiveObject(i, r.global.NumberPrototype, classNumber)
131}
132
133func (i valueInt) ToNumber() Value {
134	return i
135}
136
137func (i valueInt) SameAs(other Value) bool {
138	if otherInt, ok := other.assertInt(); ok {
139		return int64(i) == otherInt
140	}
141	return false
142}
143
144func (i valueInt) Equals(other Value) bool {
145	if o, ok := other.assertInt(); ok {
146		return int64(i) == o
147	}
148	if o, ok := other.assertFloat(); ok {
149		return float64(i) == o
150	}
151	if o, ok := other.assertString(); ok {
152		return o.ToNumber().Equals(i)
153	}
154	if o, ok := other.(valueBool); ok {
155		return int64(i) == o.ToInteger()
156	}
157	if o, ok := other.(*Object); ok {
158		return i.Equals(o.self.toPrimitiveNumber())
159	}
160	return false
161}
162
163func (i valueInt) StrictEquals(other Value) bool {
164	if otherInt, ok := other.assertInt(); ok {
165		return int64(i) == otherInt
166	} else if otherFloat, ok := other.assertFloat(); ok {
167		return float64(i) == otherFloat
168	}
169	return false
170}
171
172func (i valueInt) assertInt() (int64, bool) {
173	return int64(i), true
174}
175
176func (i valueInt) assertFloat() (float64, bool) {
177	return 0, false
178}
179
180func (i valueInt) assertString() (valueString, bool) {
181	return nil, false
182}
183
184func (i valueInt) baseObject(r *Runtime) *Object {
185	return r.global.NumberPrototype
186}
187
188func (i valueInt) Export() interface{} {
189	return int64(i)
190}
191
192func (i valueInt) ExportType() reflect.Type {
193	return reflectTypeInt
194}
195
196func (o valueBool) ToInteger() int64 {
197	if o {
198		return 1
199	}
200	return 0
201}
202
203func (o valueBool) ToString() valueString {
204	if o {
205		return stringTrue
206	}
207	return stringFalse
208}
209
210func (o valueBool) String() string {
211	if o {
212		return "true"
213	}
214	return "false"
215}
216
217func (o valueBool) ToFloat() float64 {
218	if o {
219		return 1.0
220	}
221	return 0
222}
223
224func (o valueBool) ToBoolean() bool {
225	return bool(o)
226}
227
228func (o valueBool) ToObject(r *Runtime) *Object {
229	return r.newPrimitiveObject(o, r.global.BooleanPrototype, "Boolean")
230}
231
232func (o valueBool) ToNumber() Value {
233	if o {
234		return valueInt(1)
235	}
236	return valueInt(0)
237}
238
239func (o valueBool) SameAs(other Value) bool {
240	if other, ok := other.(valueBool); ok {
241		return o == other
242	}
243	return false
244}
245
246func (b valueBool) Equals(other Value) bool {
247	if o, ok := other.(valueBool); ok {
248		return b == o
249	}
250
251	if b {
252		return other.Equals(intToValue(1))
253	} else {
254		return other.Equals(intToValue(0))
255	}
256
257}
258
259func (o valueBool) StrictEquals(other Value) bool {
260	if other, ok := other.(valueBool); ok {
261		return o == other
262	}
263	return false
264}
265
266func (o valueBool) assertInt() (int64, bool) {
267	return 0, false
268}
269
270func (o valueBool) assertFloat() (float64, bool) {
271	return 0, false
272}
273
274func (o valueBool) assertString() (valueString, bool) {
275	return nil, false
276}
277
278func (o valueBool) baseObject(r *Runtime) *Object {
279	return r.global.BooleanPrototype
280}
281
282func (o valueBool) Export() interface{} {
283	return bool(o)
284}
285
286func (o valueBool) ExportType() reflect.Type {
287	return reflectTypeBool
288}
289
290func (n valueNull) ToInteger() int64 {
291	return 0
292}
293
294func (n valueNull) ToString() valueString {
295	return stringNull
296}
297
298func (n valueNull) String() string {
299	return "null"
300}
301
302func (u valueUndefined) ToString() valueString {
303	return stringUndefined
304}
305
306func (u valueUndefined) String() string {
307	return "undefined"
308}
309
310func (u valueUndefined) ToNumber() Value {
311	return _NaN
312}
313
314func (u valueUndefined) SameAs(other Value) bool {
315	_, same := other.(valueUndefined)
316	return same
317}
318
319func (u valueUndefined) StrictEquals(other Value) bool {
320	_, same := other.(valueUndefined)
321	return same
322}
323
324func (u valueUndefined) ToFloat() float64 {
325	return math.NaN()
326}
327
328func (n valueNull) ToFloat() float64 {
329	return 0
330}
331
332func (n valueNull) ToBoolean() bool {
333	return false
334}
335
336func (n valueNull) ToObject(r *Runtime) *Object {
337	r.typeErrorResult(true, "Cannot convert undefined or null to object")
338	return nil
339	//return r.newObject()
340}
341
342func (n valueNull) ToNumber() Value {
343	return intToValue(0)
344}
345
346func (n valueNull) SameAs(other Value) bool {
347	_, same := other.(valueNull)
348	return same
349}
350
351func (n valueNull) Equals(other Value) bool {
352	switch other.(type) {
353	case valueUndefined, valueNull:
354		return true
355	}
356	return false
357}
358
359func (n valueNull) StrictEquals(other Value) bool {
360	_, same := other.(valueNull)
361	return same
362}
363
364func (n valueNull) assertInt() (int64, bool) {
365	return 0, false
366}
367
368func (n valueNull) assertFloat() (float64, bool) {
369	return 0, false
370}
371
372func (n valueNull) assertString() (valueString, bool) {
373	return nil, false
374}
375
376func (n valueNull) baseObject(r *Runtime) *Object {
377	return nil
378}
379
380func (n valueNull) Export() interface{} {
381	return nil
382}
383
384func (n valueNull) ExportType() reflect.Type {
385	return reflectTypeNil
386}
387
388func (p *valueProperty) ToInteger() int64 {
389	return 0
390}
391
392func (p *valueProperty) ToString() valueString {
393	return stringEmpty
394}
395
396func (p *valueProperty) String() string {
397	return ""
398}
399
400func (p *valueProperty) ToFloat() float64 {
401	return math.NaN()
402}
403
404func (p *valueProperty) ToBoolean() bool {
405	return false
406}
407
408func (p *valueProperty) ToObject(r *Runtime) *Object {
409	return nil
410}
411
412func (p *valueProperty) ToNumber() Value {
413	return nil
414}
415
416func (p *valueProperty) assertInt() (int64, bool) {
417	return 0, false
418}
419
420func (p *valueProperty) assertFloat() (float64, bool) {
421	return 0, false
422}
423
424func (p *valueProperty) assertString() (valueString, bool) {
425	return nil, false
426}
427
428func (p *valueProperty) isWritable() bool {
429	return p.writable || p.setterFunc != nil
430}
431
432func (p *valueProperty) get(this Value) Value {
433	if p.getterFunc == nil {
434		if p.value != nil {
435			return p.value
436		}
437		return _undefined
438	}
439	call, _ := p.getterFunc.self.assertCallable()
440	return call(FunctionCall{
441		This: this,
442	})
443}
444
445func (p *valueProperty) set(this, v Value) {
446	if p.setterFunc == nil {
447		p.value = v
448		return
449	}
450	call, _ := p.setterFunc.self.assertCallable()
451	call(FunctionCall{
452		This:      this,
453		Arguments: []Value{v},
454	})
455}
456
457func (p *valueProperty) SameAs(other Value) bool {
458	if otherProp, ok := other.(*valueProperty); ok {
459		return p == otherProp
460	}
461	return false
462}
463
464func (p *valueProperty) Equals(other Value) bool {
465	return false
466}
467
468func (p *valueProperty) StrictEquals(other Value) bool {
469	return false
470}
471
472func (n *valueProperty) baseObject(r *Runtime) *Object {
473	r.typeErrorResult(true, "BUG: baseObject() is called on valueProperty") // TODO error message
474	return nil
475}
476
477func (n *valueProperty) Export() interface{} {
478	panic("Cannot export valueProperty")
479}
480
481func (n *valueProperty) ExportType() reflect.Type {
482	panic("Cannot export valueProperty")
483}
484
485func (f valueFloat) ToInteger() int64 {
486	switch {
487	case math.IsNaN(float64(f)):
488		return 0
489	case math.IsInf(float64(f), 1):
490		return int64(math.MaxInt64)
491	case math.IsInf(float64(f), -1):
492		return int64(math.MinInt64)
493	}
494	return int64(f)
495}
496
497func (f valueFloat) ToString() valueString {
498	return asciiString(f.String())
499}
500
501var matchLeading0Exponent = regexp.MustCompile(`([eE][\+\-])0+([1-9])`) // 1e-07 => 1e-7
502
503func (f valueFloat) String() string {
504	value := float64(f)
505	if math.IsNaN(value) {
506		return "NaN"
507	} else if math.IsInf(value, 0) {
508		if math.Signbit(value) {
509			return "-Infinity"
510		}
511		return "Infinity"
512	} else if f == _negativeZero {
513		return "0"
514	}
515	exponent := math.Log10(math.Abs(value))
516	if exponent >= 21 || exponent < -6 {
517		return matchLeading0Exponent.ReplaceAllString(strconv.FormatFloat(value, 'g', -1, 64), "$1$2")
518	}
519	return strconv.FormatFloat(value, 'f', -1, 64)
520}
521
522func (f valueFloat) ToFloat() float64 {
523	return float64(f)
524}
525
526func (f valueFloat) ToBoolean() bool {
527	return float64(f) != 0.0 && !math.IsNaN(float64(f))
528}
529
530func (f valueFloat) ToObject(r *Runtime) *Object {
531	return r.newPrimitiveObject(f, r.global.NumberPrototype, "Number")
532}
533
534func (f valueFloat) ToNumber() Value {
535	return f
536}
537
538func (f valueFloat) SameAs(other Value) bool {
539	if o, ok := other.assertFloat(); ok {
540		this := float64(f)
541		if math.IsNaN(this) && math.IsNaN(o) {
542			return true
543		} else {
544			ret := this == o
545			if ret && this == 0 {
546				ret = math.Signbit(this) == math.Signbit(o)
547			}
548			return ret
549		}
550	} else if o, ok := other.assertInt(); ok {
551		this := float64(f)
552		ret := this == float64(o)
553		if ret && this == 0 {
554			ret = !math.Signbit(this)
555		}
556		return ret
557	}
558	return false
559}
560
561func (f valueFloat) Equals(other Value) bool {
562	if o, ok := other.assertFloat(); ok {
563		return float64(f) == o
564	}
565
566	if o, ok := other.assertInt(); ok {
567		return float64(f) == float64(o)
568	}
569
570	if _, ok := other.assertString(); ok {
571		return float64(f) == other.ToFloat()
572	}
573
574	if o, ok := other.(valueBool); ok {
575		return float64(f) == o.ToFloat()
576	}
577
578	if o, ok := other.(*Object); ok {
579		return f.Equals(o.self.toPrimitiveNumber())
580	}
581
582	return false
583}
584
585func (f valueFloat) StrictEquals(other Value) bool {
586	if o, ok := other.assertFloat(); ok {
587		return float64(f) == o
588	} else if o, ok := other.assertInt(); ok {
589		return float64(f) == float64(o)
590	}
591	return false
592}
593
594func (f valueFloat) assertInt() (int64, bool) {
595	return 0, false
596}
597
598func (f valueFloat) assertFloat() (float64, bool) {
599	return float64(f), true
600}
601
602func (f valueFloat) assertString() (valueString, bool) {
603	return nil, false
604}
605
606func (f valueFloat) baseObject(r *Runtime) *Object {
607	return r.global.NumberPrototype
608}
609
610func (f valueFloat) Export() interface{} {
611	return float64(f)
612}
613
614func (f valueFloat) ExportType() reflect.Type {
615	return reflectTypeFloat
616}
617
618func (o *Object) ToInteger() int64 {
619	return o.self.toPrimitiveNumber().ToNumber().ToInteger()
620}
621
622func (o *Object) ToString() valueString {
623	return o.self.toPrimitiveString().ToString()
624}
625
626func (o *Object) String() string {
627	return o.self.toPrimitiveString().String()
628}
629
630func (o *Object) ToFloat() float64 {
631	return o.self.toPrimitiveNumber().ToFloat()
632}
633
634func (o *Object) ToBoolean() bool {
635	return true
636}
637
638func (o *Object) ToObject(r *Runtime) *Object {
639	return o
640}
641
642func (o *Object) ToNumber() Value {
643	return o.self.toPrimitiveNumber().ToNumber()
644}
645
646func (o *Object) SameAs(other Value) bool {
647	if other, ok := other.(*Object); ok {
648		return o == other
649	}
650	return false
651}
652
653func (o *Object) Equals(other Value) bool {
654	if other, ok := other.(*Object); ok {
655		return o == other || o.self.equal(other.self)
656	}
657
658	if _, ok := other.assertInt(); ok {
659		return o.self.toPrimitive().Equals(other)
660	}
661
662	if _, ok := other.assertFloat(); ok {
663		return o.self.toPrimitive().Equals(other)
664	}
665
666	if other, ok := other.(valueBool); ok {
667		return o.Equals(other.ToNumber())
668	}
669
670	if _, ok := other.assertString(); ok {
671		return o.self.toPrimitive().Equals(other)
672	}
673	return false
674}
675
676func (o *Object) StrictEquals(other Value) bool {
677	if other, ok := other.(*Object); ok {
678		return o == other || o.self.equal(other.self)
679	}
680	return false
681}
682
683func (o *Object) assertInt() (int64, bool) {
684	return 0, false
685}
686
687func (o *Object) assertFloat() (float64, bool) {
688	return 0, false
689}
690
691func (o *Object) assertString() (valueString, bool) {
692	return nil, false
693}
694
695func (o *Object) baseObject(r *Runtime) *Object {
696	return o
697}
698
699func (o *Object) Export() interface{} {
700	return o.self.export()
701}
702
703func (o *Object) ExportType() reflect.Type {
704	return o.self.exportType()
705}
706
707func (o *Object) Get(name string) Value {
708	return o.self.getStr(name)
709}
710
711func (o *Object) Keys() (keys []string) {
712	for item, f := o.self.enumerate(false, false)(); f != nil; item, f = f() {
713		keys = append(keys, item.name)
714	}
715
716	return
717}
718
719// DefineDataProperty is a Go equivalent of Object.defineProperty(o, name, {value: value, writable: writable,
720// configurable: configurable, enumerable: enumerable})
721func (o *Object) DefineDataProperty(name string, value Value, writable, configurable, enumerable Flag) error {
722	return tryFunc(func() {
723		o.self.defineOwnProperty(newStringValue(name), propertyDescr{
724			Value:        value,
725			Writable:     writable,
726			Configurable: configurable,
727			Enumerable:   enumerable,
728		}, true)
729	})
730}
731
732// DefineAccessorProperty is a Go equivalent of Object.defineProperty(o, name, {get: getter, set: setter,
733// configurable: configurable, enumerable: enumerable})
734func (o *Object) DefineAccessorProperty(name string, getter, setter Value, configurable, enumerable Flag) error {
735	return tryFunc(func() {
736		o.self.defineOwnProperty(newStringValue(name), propertyDescr{
737			Getter:       getter,
738			Setter:       setter,
739			Configurable: configurable,
740			Enumerable:   enumerable,
741		}, true)
742	})
743}
744
745func (o *Object) Set(name string, value interface{}) error {
746	return tryFunc(func() {
747		o.self.putStr(name, o.runtime.ToValue(value), true)
748	})
749}
750
751// MarshalJSON returns JSON representation of the Object. It is equivalent to JSON.stringify(o).
752// Note, this implements json.Marshaler so that json.Marshal() can be used without the need to Export().
753func (o *Object) MarshalJSON() ([]byte, error) {
754	ctx := _builtinJSON_stringifyContext{
755		r: o.runtime,
756	}
757	ex := o.runtime.vm.try(func() {
758		if !ctx.do(o) {
759			ctx.buf.WriteString("null")
760		}
761	})
762	if ex != nil {
763		return nil, ex
764	}
765	return ctx.buf.Bytes(), nil
766}
767
768func (o valueUnresolved) throw() {
769	o.r.throwReferenceError(o.ref)
770}
771
772func (o valueUnresolved) ToInteger() int64 {
773	o.throw()
774	return 0
775}
776
777func (o valueUnresolved) ToString() valueString {
778	o.throw()
779	return nil
780}
781
782func (o valueUnresolved) String() string {
783	o.throw()
784	return ""
785}
786
787func (o valueUnresolved) ToFloat() float64 {
788	o.throw()
789	return 0
790}
791
792func (o valueUnresolved) ToBoolean() bool {
793	o.throw()
794	return false
795}
796
797func (o valueUnresolved) ToObject(r *Runtime) *Object {
798	o.throw()
799	return nil
800}
801
802func (o valueUnresolved) ToNumber() Value {
803	o.throw()
804	return nil
805}
806
807func (o valueUnresolved) SameAs(other Value) bool {
808	o.throw()
809	return false
810}
811
812func (o valueUnresolved) Equals(other Value) bool {
813	o.throw()
814	return false
815}
816
817func (o valueUnresolved) StrictEquals(other Value) bool {
818	o.throw()
819	return false
820}
821
822func (o valueUnresolved) assertInt() (int64, bool) {
823	o.throw()
824	return 0, false
825}
826
827func (o valueUnresolved) assertFloat() (float64, bool) {
828	o.throw()
829	return 0, false
830}
831
832func (o valueUnresolved) assertString() (valueString, bool) {
833	o.throw()
834	return nil, false
835}
836
837func (o valueUnresolved) baseObject(r *Runtime) *Object {
838	o.throw()
839	return nil
840}
841
842func (o valueUnresolved) Export() interface{} {
843	o.throw()
844	return nil
845}
846
847func (o valueUnresolved) ExportType() reflect.Type {
848	o.throw()
849	return nil
850}
851
852func init() {
853	for i := 0; i < 256; i++ {
854		intCache[i] = valueInt(i - 128)
855	}
856	_positiveZero = intToValue(0)
857}
858