1/* Copyright JS Foundation and other contributors, http://js.foundation
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16/**
17 * Implementation of ECMA GetValue and PutValue
18 */
19
20#include "ecma-builtins.h"
21#include "ecma-exceptions.h"
22#include "ecma-gc.h"
23#include "ecma-helpers.h"
24#include "ecma-lex-env.h"
25#include "ecma-objects.h"
26#include "ecma-function-object.h"
27#include "ecma-objects-general.h"
28#include "ecma-try-catch-macro.h"
29#include "ecma-reference.h"
30
31/** \addtogroup ecma ECMA
32 * @{
33 *
34 * \addtogroup lexicalenvironment Lexical environment
35 * @{
36 */
37
38/**
39 * GetValue operation part
40 *
41 * See also: ECMA-262 v5, 8.7.1, sections 3 and 5
42 *
43 * @return ecma value
44 *         Returned value must be freed with ecma_free_value.
45 */
46ecma_value_t
47ecma_op_get_value_lex_env_base (ecma_object_t *lex_env_p, /**< lexical environment */
48                                ecma_object_t **ref_base_lex_env_p, /**< [out] reference's base (lexical environment) */
49                                ecma_string_t *name_p) /**< variable name */
50{
51  JERRY_ASSERT (lex_env_p != NULL
52                && ecma_is_lexical_environment (lex_env_p));
53
54  while (true)
55  {
56    switch (ecma_get_lex_env_type (lex_env_p))
57    {
58      case ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE:
59      {
60        ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p);
61
62        if (property_p != NULL)
63        {
64          *ref_base_lex_env_p = lex_env_p;
65          ecma_property_value_t *property_value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
66
67#if ENABLED (JERRY_ES2015)
68          if (JERRY_UNLIKELY (property_value_p->value == ECMA_VALUE_UNINITIALIZED))
69          {
70            return ecma_raise_reference_error (ECMA_ERR_MSG ("Variables declared by let/const must be"
71                                                             " initialized before reading their value."));
72          }
73#endif /* ENABLED (JERRY_ES2015) */
74
75          return ecma_fast_copy_value (property_value_p->value);
76        }
77        break;
78      }
79#if ENABLED (JERRY_ES2015)
80      case ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND:
81      {
82        break;
83      }
84#endif /* ENABLED (JERRY_ES2015) */
85      default:
86      {
87        JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
88
89        ecma_value_t result = ecma_op_object_bound_environment_resolve_reference_value (lex_env_p, name_p);
90
91        if (ecma_is_value_found (result))
92        {
93          /* Note: the result may contains ECMA_VALUE_ERROR */
94          *ref_base_lex_env_p = lex_env_p;
95          return result;
96        }
97
98        break;
99      }
100    }
101
102    if (lex_env_p->u2.outer_reference_cp == JMEM_CP_NULL)
103    {
104      break;
105    }
106
107    lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp);
108  }
109
110  *ref_base_lex_env_p = NULL;
111#if ENABLED (JERRY_ERROR_MESSAGES)
112  return ecma_raise_standard_error_with_format (ECMA_ERROR_REFERENCE,
113                                                "% is not defined",
114                                                ecma_make_string_value (name_p));
115#else /* ENABLED (JERRY_ERROR_MESSAGES) */
116  return ecma_raise_reference_error (NULL);
117#endif /* ENABLED (JERRY_ERROR_MESSAGES) */
118
119} /* ecma_op_get_value_lex_env_base */
120
121/**
122 * GetValue operation part (object base).
123 *
124 * See also: ECMA-262 v5, 8.7.1, section 4
125 *
126 * @return ecma value
127 *         Returned value must be freed with ecma_free_value.
128 */
129ecma_value_t
130ecma_op_get_value_object_base (ecma_value_t base_value, /**< base value */
131                               ecma_string_t *property_name_p) /**< property name */
132{
133  ecma_object_t *obj_p;
134
135  if (JERRY_UNLIKELY (ecma_is_value_object (base_value)))
136  {
137    obj_p = ecma_get_object_from_value (base_value);
138  }
139  else
140  {
141    ecma_builtin_id_t id = ECMA_BUILTIN_ID_OBJECT_PROTOTYPE;
142
143    if (JERRY_LIKELY (ecma_is_value_string (base_value)))
144    {
145      ecma_string_t *string_p = ecma_get_string_from_value (base_value);
146
147      if (ecma_string_is_length (property_name_p))
148      {
149        return ecma_make_uint32_value (ecma_string_get_length (string_p));
150      }
151
152      uint32_t index = ecma_string_get_array_index (property_name_p);
153
154      if (index != ECMA_STRING_NOT_ARRAY_INDEX
155          && index < ecma_string_get_length (string_p))
156      {
157        ecma_char_t char_at_idx = ecma_string_get_char_at_pos (string_p, index);
158        return ecma_make_string_value (ecma_new_ecma_string_from_code_unit (char_at_idx));
159      }
160
161#if ENABLED (JERRY_BUILTIN_STRING)
162      id = ECMA_BUILTIN_ID_STRING_PROTOTYPE;
163#endif /* ENABLED (JERRY_BUILTIN_STRING) */
164    }
165    else if (ecma_is_value_number (base_value))
166    {
167#if ENABLED (JERRY_BUILTIN_NUMBER)
168      id = ECMA_BUILTIN_ID_NUMBER_PROTOTYPE;
169#endif /* ENABLED (JERRY_BUILTIN_NUMBER) */
170    }
171#if ENABLED (JERRY_ES2015)
172    else if (ecma_is_value_symbol (base_value))
173    {
174      id = ECMA_BUILTIN_ID_SYMBOL_PROTOTYPE;
175    }
176#endif /* ENABLED (JERRY_ES2015) */
177    else
178    {
179      JERRY_ASSERT (ecma_is_value_boolean (base_value));
180#if ENABLED (JERRY_BUILTIN_BOOLEAN)
181      id = ECMA_BUILTIN_ID_BOOLEAN_PROTOTYPE;
182#endif /* ENABLED (JERRY_BUILTIN_BOOLEAN) */
183    }
184
185    obj_p = ecma_builtin_get (id);
186  }
187
188  return ecma_op_object_get_with_receiver (obj_p, property_name_p, base_value);
189} /* ecma_op_get_value_object_base */
190
191/**
192 * PutValue operation part
193 *
194 * See also: ECMA-262 v5, 8.7.2, sections 3 and 5
195 *
196 * @return ecma value
197 *         Returned value must be freed with ecma_free_value.
198 */
199ecma_value_t
200ecma_op_put_value_lex_env_base (ecma_object_t *lex_env_p, /**< lexical environment */
201                                ecma_string_t *name_p, /**< variable name */
202                                bool is_strict, /**< flag indicating strict mode */
203                                ecma_value_t value) /**< ECMA-value */
204{
205  JERRY_ASSERT (lex_env_p != NULL
206                && ecma_is_lexical_environment (lex_env_p));
207
208  while (true)
209  {
210    switch (ecma_get_lex_env_type (lex_env_p))
211    {
212      case ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE:
213      {
214        ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p);
215
216        if (property_p != NULL)
217        {
218          if (ecma_is_property_writable (*property_p))
219          {
220            ecma_property_value_t *property_value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
221
222#if ENABLED (JERRY_ES2015)
223            if (JERRY_UNLIKELY (property_value_p->value == ECMA_VALUE_UNINITIALIZED))
224            {
225              return ecma_raise_reference_error (ECMA_ERR_MSG ("Variables declared by let/const must be"
226                                                               " initialized before writing their value."));
227            }
228#endif /* ENABLED (JERRY_ES2015) */
229
230            ecma_named_data_property_assign_value (lex_env_p, property_value_p, value);
231          }
232#if ENABLED (JERRY_ES2015)
233          else if (ecma_is_property_enumerable (*property_p))
234          {
235            return ecma_raise_type_error (ECMA_ERR_MSG ("Constant bindings cannot be reassigned."));
236          }
237#endif /* ENABLED (JERRY_ES2015) */
238          else if (is_strict)
239          {
240            return ecma_raise_type_error (ECMA_ERR_MSG ("Binding cannot be set."));
241          }
242          return ECMA_VALUE_EMPTY;
243        }
244        break;
245      }
246#if ENABLED (JERRY_ES2015)
247      case ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND:
248      {
249        break;
250      }
251#endif /* ENABLED (JERRY_ES2015) */
252      default:
253      {
254        JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
255
256        ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p);
257
258        ecma_value_t has_property = ecma_op_object_has_property (binding_obj_p, name_p);
259
260#if ENABLED (JERRY_ES2015_BUILTIN_PROXY)
261        if (ECMA_IS_VALUE_ERROR (has_property))
262        {
263          return has_property;
264        }
265#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */
266
267        if (ecma_is_value_true (has_property))
268        {
269          ecma_value_t completion = ecma_op_object_put (binding_obj_p,
270                                                        name_p,
271                                                        value,
272                                                        is_strict);
273
274          if (ECMA_IS_VALUE_ERROR (completion))
275          {
276            return completion;
277          }
278
279          JERRY_ASSERT (ecma_is_value_boolean (completion));
280          return ECMA_VALUE_EMPTY;
281        }
282
283        break;
284      }
285    }
286
287    if (lex_env_p->u2.outer_reference_cp == JMEM_CP_NULL)
288    {
289      break;
290    }
291
292    lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp);
293  }
294
295  if (is_strict)
296  {
297#if ENABLED (JERRY_ERROR_MESSAGES)
298    return ecma_raise_standard_error_with_format (ECMA_ERROR_REFERENCE,
299                                                  "% is not defined",
300                                                  ecma_make_string_value (name_p));
301#else /* !ENABLED (JERRY_ERROR_MESSAGES) */
302    return ecma_raise_reference_error (NULL);
303#endif /* ENABLED (JERRY_ERROR_MESSAGES) */
304  }
305
306  ecma_value_t completion = ecma_op_object_put (ecma_builtin_get_global (),
307                                                name_p,
308                                                value,
309                                                false);
310
311  JERRY_ASSERT (ecma_is_value_boolean (completion));
312
313  return ECMA_VALUE_EMPTY;
314} /* ecma_op_put_value_lex_env_base */
315
316/**
317 * @}
318 * @}
319 */
320