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