1package goja
2
3import "github.com/dop251/goja/unistring"
4
5type argumentsObject struct {
6	baseObject
7	length int
8}
9
10type mappedProperty struct {
11	valueProperty
12	v *Value
13}
14
15func (a *argumentsObject) getStr(name unistring.String, receiver Value) Value {
16	return a.getStrWithOwnProp(a.getOwnPropStr(name), name, receiver)
17}
18
19func (a *argumentsObject) getOwnPropStr(name unistring.String) Value {
20	if mapped, ok := a.values[name].(*mappedProperty); ok {
21		if mapped.writable && mapped.enumerable && mapped.configurable {
22			return *mapped.v
23		}
24		return &valueProperty{
25			value:        *mapped.v,
26			writable:     mapped.writable,
27			configurable: mapped.configurable,
28			enumerable:   mapped.enumerable,
29		}
30	}
31
32	return a.baseObject.getOwnPropStr(name)
33}
34
35func (a *argumentsObject) init() {
36	a.baseObject.init()
37	a._putProp("length", intToValue(int64(a.length)), true, false, true)
38}
39
40func (a *argumentsObject) setOwnStr(name unistring.String, val Value, throw bool) bool {
41	if prop, ok := a.values[name].(*mappedProperty); ok {
42		if !prop.writable {
43			a.val.runtime.typeErrorResult(throw, "Property is not writable: %s", name)
44			return false
45		}
46		*prop.v = val
47		return true
48	}
49	return a.baseObject.setOwnStr(name, val, throw)
50}
51
52func (a *argumentsObject) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) {
53	return a._setForeignStr(name, a.getOwnPropStr(name), val, receiver, throw)
54}
55
56func (a *argumentsObject) deleteStr(name unistring.String, throw bool) bool {
57	if prop, ok := a.values[name].(*mappedProperty); ok {
58		if !a.checkDeleteProp(name, &prop.valueProperty, throw) {
59			return false
60		}
61		a._delete(name)
62		return true
63	}
64
65	return a.baseObject.deleteStr(name, throw)
66}
67
68type argumentsPropIter struct {
69	wrapped iterNextFunc
70}
71
72func (i *argumentsPropIter) next() (propIterItem, iterNextFunc) {
73	var item propIterItem
74	item, i.wrapped = i.wrapped()
75	if i.wrapped == nil {
76		return propIterItem{}, nil
77	}
78	if prop, ok := item.value.(*mappedProperty); ok {
79		item.value = *prop.v
80	}
81	return item, i.next
82}
83
84func (a *argumentsObject) enumerateOwnKeys() iterNextFunc {
85	return (&argumentsPropIter{
86		wrapped: a.baseObject.enumerateOwnKeys(),
87	}).next
88}
89
90func (a *argumentsObject) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
91	if mapped, ok := a.values[name].(*mappedProperty); ok {
92		existing := &valueProperty{
93			configurable: mapped.configurable,
94			writable:     true,
95			enumerable:   mapped.enumerable,
96			value:        *mapped.v,
97		}
98
99		val, ok := a.baseObject._defineOwnProperty(name, existing, descr, throw)
100		if !ok {
101			return false
102		}
103
104		if prop, ok := val.(*valueProperty); ok {
105			if !prop.accessor {
106				*mapped.v = prop.value
107			}
108			if prop.accessor || !prop.writable {
109				a._put(name, prop)
110				return true
111			}
112			mapped.configurable = prop.configurable
113			mapped.enumerable = prop.enumerable
114		} else {
115			*mapped.v = val
116			mapped.configurable = true
117			mapped.enumerable = true
118		}
119
120		return true
121	}
122
123	return a.baseObject.defineOwnPropertyStr(name, descr, throw)
124}
125
126func (a *argumentsObject) export(ctx *objectExportCtx) interface{} {
127	if v, exists := ctx.get(a); exists {
128		return v
129	}
130	arr := make([]interface{}, a.length)
131	ctx.put(a, arr)
132	for i := range arr {
133		v := a.getIdx(valueInt(int64(i)), nil)
134		if v != nil {
135			arr[i] = exportValue(v, ctx)
136		}
137	}
138	return arr
139}
140