1425bb815Sopenharmony_ci/* Copyright JS Foundation and other contributors, http://js.foundation
2425bb815Sopenharmony_ci *
3425bb815Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4425bb815Sopenharmony_ci * you may not use this file except in compliance with the License.
5425bb815Sopenharmony_ci * You may obtain a copy of the License at
6425bb815Sopenharmony_ci *
7425bb815Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8425bb815Sopenharmony_ci *
9425bb815Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10425bb815Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS
11425bb815Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12425bb815Sopenharmony_ci * See the License for the specific language governing permissions and
13425bb815Sopenharmony_ci * limitations under the License.
14425bb815Sopenharmony_ci */
15425bb815Sopenharmony_ci
16425bb815Sopenharmony_ci/**
17425bb815Sopenharmony_ci * Implementation of ECMA GetValue and PutValue
18425bb815Sopenharmony_ci */
19425bb815Sopenharmony_ci
20425bb815Sopenharmony_ci#include "ecma-builtins.h"
21425bb815Sopenharmony_ci#include "ecma-exceptions.h"
22425bb815Sopenharmony_ci#include "ecma-gc.h"
23425bb815Sopenharmony_ci#include "ecma-helpers.h"
24425bb815Sopenharmony_ci#include "ecma-lex-env.h"
25425bb815Sopenharmony_ci#include "ecma-objects.h"
26425bb815Sopenharmony_ci#include "ecma-function-object.h"
27425bb815Sopenharmony_ci#include "ecma-objects-general.h"
28425bb815Sopenharmony_ci#include "ecma-try-catch-macro.h"
29425bb815Sopenharmony_ci#include "ecma-reference.h"
30425bb815Sopenharmony_ci
31425bb815Sopenharmony_ci/** \addtogroup ecma ECMA
32425bb815Sopenharmony_ci * @{
33425bb815Sopenharmony_ci *
34425bb815Sopenharmony_ci * \addtogroup lexicalenvironment Lexical environment
35425bb815Sopenharmony_ci * @{
36425bb815Sopenharmony_ci */
37425bb815Sopenharmony_ci
38425bb815Sopenharmony_ci/**
39425bb815Sopenharmony_ci * GetValue operation part
40425bb815Sopenharmony_ci *
41425bb815Sopenharmony_ci * See also: ECMA-262 v5, 8.7.1, sections 3 and 5
42425bb815Sopenharmony_ci *
43425bb815Sopenharmony_ci * @return ecma value
44425bb815Sopenharmony_ci *         Returned value must be freed with ecma_free_value.
45425bb815Sopenharmony_ci */
46425bb815Sopenharmony_ciecma_value_t
47425bb815Sopenharmony_ciecma_op_get_value_lex_env_base (ecma_object_t *lex_env_p, /**< lexical environment */
48425bb815Sopenharmony_ci                                ecma_object_t **ref_base_lex_env_p, /**< [out] reference's base (lexical environment) */
49425bb815Sopenharmony_ci                                ecma_string_t *name_p) /**< variable name */
50425bb815Sopenharmony_ci{
51425bb815Sopenharmony_ci  JERRY_ASSERT (lex_env_p != NULL
52425bb815Sopenharmony_ci                && ecma_is_lexical_environment (lex_env_p));
53425bb815Sopenharmony_ci
54425bb815Sopenharmony_ci  while (true)
55425bb815Sopenharmony_ci  {
56425bb815Sopenharmony_ci    switch (ecma_get_lex_env_type (lex_env_p))
57425bb815Sopenharmony_ci    {
58425bb815Sopenharmony_ci      case ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE:
59425bb815Sopenharmony_ci      {
60425bb815Sopenharmony_ci        ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p);
61425bb815Sopenharmony_ci
62425bb815Sopenharmony_ci        if (property_p != NULL)
63425bb815Sopenharmony_ci        {
64425bb815Sopenharmony_ci          *ref_base_lex_env_p = lex_env_p;
65425bb815Sopenharmony_ci          ecma_property_value_t *property_value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
66425bb815Sopenharmony_ci
67425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015)
68425bb815Sopenharmony_ci          if (JERRY_UNLIKELY (property_value_p->value == ECMA_VALUE_UNINITIALIZED))
69425bb815Sopenharmony_ci          {
70425bb815Sopenharmony_ci            return ecma_raise_reference_error (ECMA_ERR_MSG ("Variables declared by let/const must be"
71425bb815Sopenharmony_ci                                                             " initialized before reading their value."));
72425bb815Sopenharmony_ci          }
73425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015) */
74425bb815Sopenharmony_ci
75425bb815Sopenharmony_ci          return ecma_fast_copy_value (property_value_p->value);
76425bb815Sopenharmony_ci        }
77425bb815Sopenharmony_ci        break;
78425bb815Sopenharmony_ci      }
79425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015)
80425bb815Sopenharmony_ci      case ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND:
81425bb815Sopenharmony_ci      {
82425bb815Sopenharmony_ci        break;
83425bb815Sopenharmony_ci      }
84425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015) */
85425bb815Sopenharmony_ci      default:
86425bb815Sopenharmony_ci      {
87425bb815Sopenharmony_ci        JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
88425bb815Sopenharmony_ci
89425bb815Sopenharmony_ci        ecma_value_t result = ecma_op_object_bound_environment_resolve_reference_value (lex_env_p, name_p);
90425bb815Sopenharmony_ci
91425bb815Sopenharmony_ci        if (ecma_is_value_found (result))
92425bb815Sopenharmony_ci        {
93425bb815Sopenharmony_ci          /* Note: the result may contains ECMA_VALUE_ERROR */
94425bb815Sopenharmony_ci          *ref_base_lex_env_p = lex_env_p;
95425bb815Sopenharmony_ci          return result;
96425bb815Sopenharmony_ci        }
97425bb815Sopenharmony_ci
98425bb815Sopenharmony_ci        break;
99425bb815Sopenharmony_ci      }
100425bb815Sopenharmony_ci    }
101425bb815Sopenharmony_ci
102425bb815Sopenharmony_ci    if (lex_env_p->u2.outer_reference_cp == JMEM_CP_NULL)
103425bb815Sopenharmony_ci    {
104425bb815Sopenharmony_ci      break;
105425bb815Sopenharmony_ci    }
106425bb815Sopenharmony_ci
107425bb815Sopenharmony_ci    lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp);
108425bb815Sopenharmony_ci  }
109425bb815Sopenharmony_ci
110425bb815Sopenharmony_ci  *ref_base_lex_env_p = NULL;
111425bb815Sopenharmony_ci#if ENABLED (JERRY_ERROR_MESSAGES)
112425bb815Sopenharmony_ci  return ecma_raise_standard_error_with_format (ECMA_ERROR_REFERENCE,
113425bb815Sopenharmony_ci                                                "% is not defined",
114425bb815Sopenharmony_ci                                                ecma_make_string_value (name_p));
115425bb815Sopenharmony_ci#else /* ENABLED (JERRY_ERROR_MESSAGES) */
116425bb815Sopenharmony_ci  return ecma_raise_reference_error (NULL);
117425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ERROR_MESSAGES) */
118425bb815Sopenharmony_ci
119425bb815Sopenharmony_ci} /* ecma_op_get_value_lex_env_base */
120425bb815Sopenharmony_ci
121425bb815Sopenharmony_ci/**
122425bb815Sopenharmony_ci * GetValue operation part (object base).
123425bb815Sopenharmony_ci *
124425bb815Sopenharmony_ci * See also: ECMA-262 v5, 8.7.1, section 4
125425bb815Sopenharmony_ci *
126425bb815Sopenharmony_ci * @return ecma value
127425bb815Sopenharmony_ci *         Returned value must be freed with ecma_free_value.
128425bb815Sopenharmony_ci */
129425bb815Sopenharmony_ciecma_value_t
130425bb815Sopenharmony_ciecma_op_get_value_object_base (ecma_value_t base_value, /**< base value */
131425bb815Sopenharmony_ci                               ecma_string_t *property_name_p) /**< property name */
132425bb815Sopenharmony_ci{
133425bb815Sopenharmony_ci  ecma_object_t *obj_p;
134425bb815Sopenharmony_ci
135425bb815Sopenharmony_ci  if (JERRY_UNLIKELY (ecma_is_value_object (base_value)))
136425bb815Sopenharmony_ci  {
137425bb815Sopenharmony_ci    obj_p = ecma_get_object_from_value (base_value);
138425bb815Sopenharmony_ci  }
139425bb815Sopenharmony_ci  else
140425bb815Sopenharmony_ci  {
141425bb815Sopenharmony_ci    ecma_builtin_id_t id = ECMA_BUILTIN_ID_OBJECT_PROTOTYPE;
142425bb815Sopenharmony_ci
143425bb815Sopenharmony_ci    if (JERRY_LIKELY (ecma_is_value_string (base_value)))
144425bb815Sopenharmony_ci    {
145425bb815Sopenharmony_ci      ecma_string_t *string_p = ecma_get_string_from_value (base_value);
146425bb815Sopenharmony_ci
147425bb815Sopenharmony_ci      if (ecma_string_is_length (property_name_p))
148425bb815Sopenharmony_ci      {
149425bb815Sopenharmony_ci        return ecma_make_uint32_value (ecma_string_get_length (string_p));
150425bb815Sopenharmony_ci      }
151425bb815Sopenharmony_ci
152425bb815Sopenharmony_ci      uint32_t index = ecma_string_get_array_index (property_name_p);
153425bb815Sopenharmony_ci
154425bb815Sopenharmony_ci      if (index != ECMA_STRING_NOT_ARRAY_INDEX
155425bb815Sopenharmony_ci          && index < ecma_string_get_length (string_p))
156425bb815Sopenharmony_ci      {
157425bb815Sopenharmony_ci        ecma_char_t char_at_idx = ecma_string_get_char_at_pos (string_p, index);
158425bb815Sopenharmony_ci        return ecma_make_string_value (ecma_new_ecma_string_from_code_unit (char_at_idx));
159425bb815Sopenharmony_ci      }
160425bb815Sopenharmony_ci
161425bb815Sopenharmony_ci#if ENABLED (JERRY_BUILTIN_STRING)
162425bb815Sopenharmony_ci      id = ECMA_BUILTIN_ID_STRING_PROTOTYPE;
163425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_BUILTIN_STRING) */
164425bb815Sopenharmony_ci    }
165425bb815Sopenharmony_ci    else if (ecma_is_value_number (base_value))
166425bb815Sopenharmony_ci    {
167425bb815Sopenharmony_ci#if ENABLED (JERRY_BUILTIN_NUMBER)
168425bb815Sopenharmony_ci      id = ECMA_BUILTIN_ID_NUMBER_PROTOTYPE;
169425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_BUILTIN_NUMBER) */
170425bb815Sopenharmony_ci    }
171425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015)
172425bb815Sopenharmony_ci    else if (ecma_is_value_symbol (base_value))
173425bb815Sopenharmony_ci    {
174425bb815Sopenharmony_ci      id = ECMA_BUILTIN_ID_SYMBOL_PROTOTYPE;
175425bb815Sopenharmony_ci    }
176425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015) */
177425bb815Sopenharmony_ci    else
178425bb815Sopenharmony_ci    {
179425bb815Sopenharmony_ci      JERRY_ASSERT (ecma_is_value_boolean (base_value));
180425bb815Sopenharmony_ci#if ENABLED (JERRY_BUILTIN_BOOLEAN)
181425bb815Sopenharmony_ci      id = ECMA_BUILTIN_ID_BOOLEAN_PROTOTYPE;
182425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_BUILTIN_BOOLEAN) */
183425bb815Sopenharmony_ci    }
184425bb815Sopenharmony_ci
185425bb815Sopenharmony_ci    obj_p = ecma_builtin_get (id);
186425bb815Sopenharmony_ci  }
187425bb815Sopenharmony_ci
188425bb815Sopenharmony_ci  return ecma_op_object_get_with_receiver (obj_p, property_name_p, base_value);
189425bb815Sopenharmony_ci} /* ecma_op_get_value_object_base */
190425bb815Sopenharmony_ci
191425bb815Sopenharmony_ci/**
192425bb815Sopenharmony_ci * PutValue operation part
193425bb815Sopenharmony_ci *
194425bb815Sopenharmony_ci * See also: ECMA-262 v5, 8.7.2, sections 3 and 5
195425bb815Sopenharmony_ci *
196425bb815Sopenharmony_ci * @return ecma value
197425bb815Sopenharmony_ci *         Returned value must be freed with ecma_free_value.
198425bb815Sopenharmony_ci */
199425bb815Sopenharmony_ciecma_value_t
200425bb815Sopenharmony_ciecma_op_put_value_lex_env_base (ecma_object_t *lex_env_p, /**< lexical environment */
201425bb815Sopenharmony_ci                                ecma_string_t *name_p, /**< variable name */
202425bb815Sopenharmony_ci                                bool is_strict, /**< flag indicating strict mode */
203425bb815Sopenharmony_ci                                ecma_value_t value) /**< ECMA-value */
204425bb815Sopenharmony_ci{
205425bb815Sopenharmony_ci  JERRY_ASSERT (lex_env_p != NULL
206425bb815Sopenharmony_ci                && ecma_is_lexical_environment (lex_env_p));
207425bb815Sopenharmony_ci
208425bb815Sopenharmony_ci  while (true)
209425bb815Sopenharmony_ci  {
210425bb815Sopenharmony_ci    switch (ecma_get_lex_env_type (lex_env_p))
211425bb815Sopenharmony_ci    {
212425bb815Sopenharmony_ci      case ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE:
213425bb815Sopenharmony_ci      {
214425bb815Sopenharmony_ci        ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p);
215425bb815Sopenharmony_ci
216425bb815Sopenharmony_ci        if (property_p != NULL)
217425bb815Sopenharmony_ci        {
218425bb815Sopenharmony_ci          if (ecma_is_property_writable (*property_p))
219425bb815Sopenharmony_ci          {
220425bb815Sopenharmony_ci            ecma_property_value_t *property_value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
221425bb815Sopenharmony_ci
222425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015)
223425bb815Sopenharmony_ci            if (JERRY_UNLIKELY (property_value_p->value == ECMA_VALUE_UNINITIALIZED))
224425bb815Sopenharmony_ci            {
225425bb815Sopenharmony_ci              return ecma_raise_reference_error (ECMA_ERR_MSG ("Variables declared by let/const must be"
226425bb815Sopenharmony_ci                                                               " initialized before writing their value."));
227425bb815Sopenharmony_ci            }
228425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015) */
229425bb815Sopenharmony_ci
230425bb815Sopenharmony_ci            ecma_named_data_property_assign_value (lex_env_p, property_value_p, value);
231425bb815Sopenharmony_ci          }
232425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015)
233425bb815Sopenharmony_ci          else if (ecma_is_property_enumerable (*property_p))
234425bb815Sopenharmony_ci          {
235425bb815Sopenharmony_ci            return ecma_raise_type_error (ECMA_ERR_MSG ("Constant bindings cannot be reassigned."));
236425bb815Sopenharmony_ci          }
237425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015) */
238425bb815Sopenharmony_ci          else if (is_strict)
239425bb815Sopenharmony_ci          {
240425bb815Sopenharmony_ci            return ecma_raise_type_error (ECMA_ERR_MSG ("Binding cannot be set."));
241425bb815Sopenharmony_ci          }
242425bb815Sopenharmony_ci          return ECMA_VALUE_EMPTY;
243425bb815Sopenharmony_ci        }
244425bb815Sopenharmony_ci        break;
245425bb815Sopenharmony_ci      }
246425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015)
247425bb815Sopenharmony_ci      case ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND:
248425bb815Sopenharmony_ci      {
249425bb815Sopenharmony_ci        break;
250425bb815Sopenharmony_ci      }
251425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015) */
252425bb815Sopenharmony_ci      default:
253425bb815Sopenharmony_ci      {
254425bb815Sopenharmony_ci        JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
255425bb815Sopenharmony_ci
256425bb815Sopenharmony_ci        ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p);
257425bb815Sopenharmony_ci
258425bb815Sopenharmony_ci        ecma_value_t has_property = ecma_op_object_has_property (binding_obj_p, name_p);
259425bb815Sopenharmony_ci
260425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015_BUILTIN_PROXY)
261425bb815Sopenharmony_ci        if (ECMA_IS_VALUE_ERROR (has_property))
262425bb815Sopenharmony_ci        {
263425bb815Sopenharmony_ci          return has_property;
264425bb815Sopenharmony_ci        }
265425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */
266425bb815Sopenharmony_ci
267425bb815Sopenharmony_ci        if (ecma_is_value_true (has_property))
268425bb815Sopenharmony_ci        {
269425bb815Sopenharmony_ci          ecma_value_t completion = ecma_op_object_put (binding_obj_p,
270425bb815Sopenharmony_ci                                                        name_p,
271425bb815Sopenharmony_ci                                                        value,
272425bb815Sopenharmony_ci                                                        is_strict);
273425bb815Sopenharmony_ci
274425bb815Sopenharmony_ci          if (ECMA_IS_VALUE_ERROR (completion))
275425bb815Sopenharmony_ci          {
276425bb815Sopenharmony_ci            return completion;
277425bb815Sopenharmony_ci          }
278425bb815Sopenharmony_ci
279425bb815Sopenharmony_ci          JERRY_ASSERT (ecma_is_value_boolean (completion));
280425bb815Sopenharmony_ci          return ECMA_VALUE_EMPTY;
281425bb815Sopenharmony_ci        }
282425bb815Sopenharmony_ci
283425bb815Sopenharmony_ci        break;
284425bb815Sopenharmony_ci      }
285425bb815Sopenharmony_ci    }
286425bb815Sopenharmony_ci
287425bb815Sopenharmony_ci    if (lex_env_p->u2.outer_reference_cp == JMEM_CP_NULL)
288425bb815Sopenharmony_ci    {
289425bb815Sopenharmony_ci      break;
290425bb815Sopenharmony_ci    }
291425bb815Sopenharmony_ci
292425bb815Sopenharmony_ci    lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp);
293425bb815Sopenharmony_ci  }
294425bb815Sopenharmony_ci
295425bb815Sopenharmony_ci  if (is_strict)
296425bb815Sopenharmony_ci  {
297425bb815Sopenharmony_ci#if ENABLED (JERRY_ERROR_MESSAGES)
298425bb815Sopenharmony_ci    return ecma_raise_standard_error_with_format (ECMA_ERROR_REFERENCE,
299425bb815Sopenharmony_ci                                                  "% is not defined",
300425bb815Sopenharmony_ci                                                  ecma_make_string_value (name_p));
301425bb815Sopenharmony_ci#else /* !ENABLED (JERRY_ERROR_MESSAGES) */
302425bb815Sopenharmony_ci    return ecma_raise_reference_error (NULL);
303425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ERROR_MESSAGES) */
304425bb815Sopenharmony_ci  }
305425bb815Sopenharmony_ci
306425bb815Sopenharmony_ci  ecma_value_t completion = ecma_op_object_put (ecma_builtin_get_global (),
307425bb815Sopenharmony_ci                                                name_p,
308425bb815Sopenharmony_ci                                                value,
309425bb815Sopenharmony_ci                                                false);
310425bb815Sopenharmony_ci
311425bb815Sopenharmony_ci  JERRY_ASSERT (ecma_is_value_boolean (completion));
312425bb815Sopenharmony_ci
313425bb815Sopenharmony_ci  return ECMA_VALUE_EMPTY;
314425bb815Sopenharmony_ci} /* ecma_op_put_value_lex_env_base */
315425bb815Sopenharmony_ci
316425bb815Sopenharmony_ci/**
317425bb815Sopenharmony_ci * @}
318425bb815Sopenharmony_ci * @}
319425bb815Sopenharmony_ci */
320