List scope chain levels and their variables to the selected stack frame. (#2557)
It supports to list the scope chain of the current execution context and see which variables are available. JerryScript-DCO-1.0-Signed-off-by: Robert Sipka rsipka.uszeged@partner.samsung.com
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
#include "ecma-builtin-helpers.h"
|
||||
#include "ecma-conversion.h"
|
||||
#include "ecma-eval.h"
|
||||
#include "ecma-function-object.h"
|
||||
#include "ecma-objects.h"
|
||||
#include "jcontext.h"
|
||||
#include "jerryscript-port.h"
|
||||
@@ -37,9 +38,9 @@ typedef struct
|
||||
* The number of message types in the debugger should reflect the
|
||||
* debugger versioning.
|
||||
*/
|
||||
JERRY_STATIC_ASSERT (JERRY_DEBUGGER_MESSAGES_OUT_MAX_COUNT == 28
|
||||
&& JERRY_DEBUGGER_MESSAGES_IN_MAX_COUNT == 19
|
||||
&& JERRY_DEBUGGER_VERSION == 6,
|
||||
JERRY_STATIC_ASSERT (JERRY_DEBUGGER_MESSAGES_OUT_MAX_COUNT == 32
|
||||
&& JERRY_DEBUGGER_MESSAGES_IN_MAX_COUNT == 21
|
||||
&& JERRY_DEBUGGER_VERSION == 7,
|
||||
debugger_version_correlates_to_message_type_count);
|
||||
|
||||
/**
|
||||
@@ -195,6 +196,332 @@ jerry_debugger_send_backtrace (const uint8_t *recv_buffer_p) /**< pointer to the
|
||||
jerry_debugger_send (sizeof (jerry_debugger_send_type_t) + message_size);
|
||||
} /* jerry_debugger_send_backtrace */
|
||||
|
||||
/**
|
||||
* Send the scope chain types.
|
||||
*/
|
||||
static void
|
||||
jerry_debugger_send_scope_chain (void)
|
||||
{
|
||||
vm_frame_ctx_t *iter_frame_ctx_p = JERRY_CONTEXT (vm_top_context_p);
|
||||
|
||||
const size_t max_byte_count = JERRY_DEBUGGER_SEND_MAX (uint8_t);
|
||||
const size_t max_message_size = JERRY_DEBUGGER_SEND_SIZE (max_byte_count, uint8_t);
|
||||
|
||||
JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_string_t, message_type_p);
|
||||
message_type_p->type = JERRY_DEBUGGER_SCOPE_CHAIN;
|
||||
|
||||
size_t buffer_pos = 0;
|
||||
bool next_func_is_local = true;
|
||||
ecma_object_t *lex_env_p = iter_frame_ctx_p->lex_env_p;
|
||||
|
||||
while (true)
|
||||
{
|
||||
JERRY_ASSERT (ecma_is_lexical_environment (lex_env_p));
|
||||
|
||||
if (buffer_pos == max_byte_count)
|
||||
{
|
||||
if (!jerry_debugger_send (max_message_size))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
buffer_pos = 0;
|
||||
}
|
||||
|
||||
if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
|
||||
{
|
||||
if ((lex_env_p->type_flags_refs & ECMA_OBJECT_FLAG_NON_CLOSURE) != 0)
|
||||
{
|
||||
message_type_p->string[buffer_pos++] = JERRY_DEBUGGER_SCOPE_NON_CLOSURE;
|
||||
}
|
||||
else if (next_func_is_local)
|
||||
{
|
||||
message_type_p->string[buffer_pos++] = JERRY_DEBUGGER_SCOPE_LOCAL;
|
||||
next_func_is_local = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
message_type_p->string[buffer_pos++] = JERRY_DEBUGGER_SCOPE_CLOSURE;
|
||||
}
|
||||
}
|
||||
else if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND)
|
||||
{
|
||||
if (ecma_get_lex_env_outer_reference (lex_env_p) == NULL)
|
||||
{
|
||||
message_type_p->string[buffer_pos++] = JERRY_DEBUGGER_SCOPE_GLOBAL;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
message_type_p->string[buffer_pos++] = JERRY_DEBUGGER_SCOPE_WITH;
|
||||
}
|
||||
}
|
||||
|
||||
lex_env_p = ecma_get_lex_env_outer_reference (lex_env_p);
|
||||
}
|
||||
|
||||
message_type_p->type = JERRY_DEBUGGER_SCOPE_CHAIN_END;
|
||||
|
||||
jerry_debugger_send (sizeof (jerry_debugger_send_type_t) + buffer_pos);
|
||||
} /* jerry_debugger_send_scope_chain */
|
||||
|
||||
/**
|
||||
* Get type of the scope variable property.
|
||||
*/
|
||||
static jerry_debugger_scope_variable_type_t
|
||||
jerry_debugger_get_variable_type (ecma_value_t value) /**< input ecma value */
|
||||
{
|
||||
jerry_debugger_scope_variable_type_t ret_value = JERRY_DEBUGGER_VALUE_NONE;
|
||||
|
||||
if (ecma_is_value_undefined (value))
|
||||
{
|
||||
ret_value = JERRY_DEBUGGER_VALUE_UNDEFINED;
|
||||
}
|
||||
else if (ecma_is_value_null (value))
|
||||
{
|
||||
ret_value = JERRY_DEBUGGER_VALUE_NULL;
|
||||
}
|
||||
else if (ecma_is_value_boolean (value))
|
||||
{
|
||||
ret_value = JERRY_DEBUGGER_VALUE_BOOLEAN;
|
||||
}
|
||||
else if (ecma_is_value_number (value))
|
||||
{
|
||||
ret_value = JERRY_DEBUGGER_VALUE_NUMBER;
|
||||
}
|
||||
else if (ecma_is_value_string (value))
|
||||
{
|
||||
ret_value = JERRY_DEBUGGER_VALUE_STRING;
|
||||
}
|
||||
else
|
||||
{
|
||||
JERRY_ASSERT (ecma_is_value_object (value));
|
||||
|
||||
if (ecma_object_get_class_name (ecma_get_object_from_value (value)) == LIT_MAGIC_STRING_ARRAY_UL)
|
||||
{
|
||||
ret_value = JERRY_DEBUGGER_VALUE_ARRAY;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret_value = ecma_op_is_callable (value) ? JERRY_DEBUGGER_VALUE_FUNCTION : JERRY_DEBUGGER_VALUE_OBJECT;
|
||||
}
|
||||
}
|
||||
|
||||
JERRY_ASSERT (ret_value != JERRY_DEBUGGER_VALUE_NONE);
|
||||
|
||||
return ret_value;
|
||||
} /* jerry_debugger_get_variable_type */
|
||||
|
||||
/**
|
||||
* Helper function for jerry_debugger_send_scope_variables.
|
||||
*
|
||||
* It will copies the given scope values type, length and value into the outgoing message string.
|
||||
*
|
||||
* @return true - if the copy was successfully
|
||||
* false - otherwise
|
||||
*/
|
||||
static bool
|
||||
jerry_debugger_copy_variables_to_string_message (jerry_debugger_scope_variable_type_t variable_type, /**< type */
|
||||
ecma_string_t *value_str, /**< property name or value string */
|
||||
jerry_debugger_send_string_t *message_string_p, /**< msg pointer */
|
||||
size_t *buffer_pos) /**< string data position of the message */
|
||||
{
|
||||
const size_t max_byte_count = JERRY_DEBUGGER_SEND_MAX (uint8_t);
|
||||
const size_t max_message_size = JERRY_DEBUGGER_SEND_SIZE (max_byte_count, uint8_t);
|
||||
|
||||
ECMA_STRING_TO_UTF8_STRING (value_str, str_buff, str_buff_size);
|
||||
|
||||
size_t str_size = 0;
|
||||
size_t str_limit = 255;
|
||||
bool result = true;
|
||||
|
||||
bool type_processed = false;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (*buffer_pos == max_byte_count)
|
||||
{
|
||||
if (!jerry_debugger_send (max_message_size))
|
||||
{
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
*buffer_pos = 0;
|
||||
}
|
||||
|
||||
if (!type_processed)
|
||||
{
|
||||
if (variable_type != JERRY_DEBUGGER_VALUE_NONE)
|
||||
{
|
||||
message_string_p->string[*buffer_pos] = variable_type;
|
||||
*buffer_pos += 1;
|
||||
}
|
||||
type_processed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (variable_type == JERRY_DEBUGGER_VALUE_FUNCTION)
|
||||
{
|
||||
str_size = 0; // do not copy function values
|
||||
}
|
||||
else
|
||||
{
|
||||
str_size = (str_buff_size > str_limit) ? str_limit : str_buff_size;
|
||||
}
|
||||
|
||||
message_string_p->string[*buffer_pos] = (uint8_t) str_size;
|
||||
*buffer_pos += 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
size_t free_bytes = max_byte_count - *buffer_pos;
|
||||
const uint8_t *string_p = str_buff;
|
||||
|
||||
while (str_size > free_bytes)
|
||||
{
|
||||
memcpy (message_string_p->string + *buffer_pos, string_p, free_bytes);
|
||||
|
||||
if (!jerry_debugger_send (max_message_size))
|
||||
{
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
string_p += free_bytes;
|
||||
str_size -= free_bytes;
|
||||
free_bytes = max_byte_count;
|
||||
*buffer_pos = 0;
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
memcpy (message_string_p->string + *buffer_pos, string_p, str_size);
|
||||
*buffer_pos += str_size;
|
||||
}
|
||||
}
|
||||
|
||||
ECMA_FINALIZE_UTF8_STRING (str_buff, str_buff_size);
|
||||
|
||||
return result;
|
||||
} /* jerry_debugger_copy_variables_to_string_message */
|
||||
|
||||
/**
|
||||
* Send variables of the given scope chain level.
|
||||
*/
|
||||
static void
|
||||
jerry_debugger_send_scope_variables (const uint8_t *recv_buffer_p) /**< pointer to the received data */
|
||||
{
|
||||
JERRY_DEBUGGER_RECEIVE_BUFFER_AS (jerry_debugger_receive_get_scope_variables_t, get_scope_variables_p);
|
||||
|
||||
uint32_t chain_index;
|
||||
memcpy (&chain_index, get_scope_variables_p->chain_index, sizeof (uint32_t));
|
||||
|
||||
vm_frame_ctx_t *iter_frame_ctx_p = JERRY_CONTEXT (vm_top_context_p);
|
||||
ecma_object_t *lex_env_p = iter_frame_ctx_p->lex_env_p;
|
||||
|
||||
while (chain_index != 0)
|
||||
{
|
||||
lex_env_p = ecma_get_lex_env_outer_reference (lex_env_p);
|
||||
|
||||
if (JERRY_UNLIKELY (lex_env_p == NULL))
|
||||
{
|
||||
jerry_debugger_send_type (JERRY_DEBUGGER_SCOPE_VARIABLES_END);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND)
|
||||
|| (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE))
|
||||
{
|
||||
chain_index--;
|
||||
}
|
||||
}
|
||||
|
||||
ecma_property_header_t *prop_iter_p;
|
||||
|
||||
if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
|
||||
{
|
||||
prop_iter_p = ecma_get_property_list (lex_env_p);
|
||||
}
|
||||
else
|
||||
{
|
||||
JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND);
|
||||
ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p);
|
||||
prop_iter_p = ecma_get_property_list (binding_obj_p);
|
||||
}
|
||||
|
||||
JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_string_t, message_string_p);
|
||||
message_string_p->type = JERRY_DEBUGGER_SCOPE_VARIABLES;
|
||||
|
||||
size_t buffer_pos = 0;
|
||||
|
||||
while (prop_iter_p != NULL)
|
||||
{
|
||||
JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p));
|
||||
|
||||
ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p;
|
||||
|
||||
for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++)
|
||||
{
|
||||
if (ECMA_PROPERTY_IS_NAMED_PROPERTY (prop_iter_p->types[i]))
|
||||
{
|
||||
if (ECMA_PROPERTY_GET_NAME_TYPE (prop_iter_p->types[i]) == ECMA_DIRECT_STRING_MAGIC
|
||||
&& prop_pair_p->names_cp[i] >= LIT_NON_INTERNAL_MAGIC_STRING__COUNT)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ecma_string_t *prop_name = ecma_string_from_property_name (prop_iter_p->types[i],
|
||||
prop_pair_p->names_cp[i]);
|
||||
|
||||
if (!jerry_debugger_copy_variables_to_string_message (JERRY_DEBUGGER_VALUE_NONE,
|
||||
prop_name,
|
||||
message_string_p,
|
||||
&buffer_pos))
|
||||
{
|
||||
ecma_deref_ecma_string (prop_name);
|
||||
return;
|
||||
}
|
||||
|
||||
ecma_deref_ecma_string (prop_name);
|
||||
|
||||
ecma_property_value_t prop_value_p = prop_pair_p->values[i];
|
||||
ecma_value_t property_value;
|
||||
|
||||
jerry_debugger_scope_variable_type_t variable_type = jerry_debugger_get_variable_type (prop_value_p.value);
|
||||
|
||||
if (variable_type == JERRY_DEBUGGER_VALUE_OBJECT)
|
||||
{
|
||||
property_value = ecma_builtin_json_string_from_object (prop_value_p.value);
|
||||
}
|
||||
else
|
||||
{
|
||||
property_value = ecma_op_to_string (prop_value_p.value);
|
||||
}
|
||||
|
||||
if (!jerry_debugger_copy_variables_to_string_message (variable_type,
|
||||
ecma_get_string_from_value (property_value),
|
||||
message_string_p,
|
||||
&buffer_pos))
|
||||
{
|
||||
ecma_free_value (property_value);
|
||||
return;
|
||||
}
|
||||
|
||||
ecma_free_value (property_value);
|
||||
}
|
||||
}
|
||||
|
||||
prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t,
|
||||
prop_iter_p->next_property_cp);
|
||||
}
|
||||
|
||||
message_string_p->type = JERRY_DEBUGGER_SCOPE_VARIABLES_END;
|
||||
jerry_debugger_send (sizeof (jerry_debugger_send_type_t) + buffer_pos);
|
||||
} /* jerry_debugger_send_scope_variables */
|
||||
|
||||
/**
|
||||
* Send result of evaluated expression or throw an error.
|
||||
*
|
||||
@@ -525,6 +852,24 @@ jerry_debugger_process_message (const uint8_t *recv_buffer_p, /**< pointer to th
|
||||
return true;
|
||||
}
|
||||
|
||||
case JERRY_DEBUGGER_GET_SCOPE_CHAIN:
|
||||
{
|
||||
JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t);
|
||||
|
||||
jerry_debugger_send_scope_chain ();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case JERRY_DEBUGGER_GET_SCOPE_VARIABLES:
|
||||
{
|
||||
JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_get_scope_variables_t);
|
||||
|
||||
jerry_debugger_send_scope_variables (recv_buffer_p);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case JERRY_DEBUGGER_EXCEPTION_CONFIG:
|
||||
{
|
||||
JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_exception_config_t);
|
||||
|
||||
@@ -152,7 +152,10 @@ typedef enum
|
||||
JERRY_DEBUGGER_WAIT_FOR_SOURCE = 25, /**< engine waiting for source code */
|
||||
JERRY_DEBUGGER_OUTPUT_RESULT = 26, /**< output sent by the program to the debugger */
|
||||
JERRY_DEBUGGER_OUTPUT_RESULT_END = 27, /**< last output result data */
|
||||
|
||||
JERRY_DEBUGGER_SCOPE_CHAIN = 28, /**< scope chain */
|
||||
JERRY_DEBUGGER_SCOPE_CHAIN_END = 29, /**< last output of scope chain */
|
||||
JERRY_DEBUGGER_SCOPE_VARIABLES = 30, /**< scope variables */
|
||||
JERRY_DEBUGGER_SCOPE_VARIABLES_END = 31, /**< last output of scope variables */
|
||||
JERRY_DEBUGGER_MESSAGES_OUT_MAX_COUNT, /**< number of different type of output messages by the debugger */
|
||||
|
||||
/* Messages sent by the client to server. */
|
||||
@@ -182,7 +185,8 @@ typedef enum
|
||||
JERRY_DEBUGGER_GET_BACKTRACE = 16, /**< get backtrace */
|
||||
JERRY_DEBUGGER_EVAL = 17, /**< first message of evaluating a string */
|
||||
JERRY_DEBUGGER_EVAL_PART = 18, /**< next message of evaluating a string */
|
||||
|
||||
JERRY_DEBUGGER_GET_SCOPE_CHAIN = 19, /**< get type names of the scope chain */
|
||||
JERRY_DEBUGGER_GET_SCOPE_VARIABLES = 20, /**< get variables of a scope */
|
||||
JERRY_DEBUGGER_MESSAGES_IN_MAX_COUNT, /**< number of different type of input messages */
|
||||
} jerry_debugger_header_type_t;
|
||||
|
||||
@@ -229,6 +233,34 @@ typedef enum
|
||||
JERRY_DEBUGGER_OUTPUT_TRACE = 5, /**< output result, trace */
|
||||
} jerry_debugger_output_subtype_t;
|
||||
|
||||
/**
|
||||
* Types of scopes.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
JERRY_DEBUGGER_SCOPE_WITH = 1, /**< with */
|
||||
JERRY_DEBUGGER_SCOPE_LOCAL = 2, /**< local */
|
||||
JERRY_DEBUGGER_SCOPE_CLOSURE = 3, /**< closure */
|
||||
JERRY_DEBUGGER_SCOPE_GLOBAL = 4, /**< global */
|
||||
JERRY_DEBUGGER_SCOPE_NON_CLOSURE = 5 /**< non closure */
|
||||
} jerry_debugger_scope_chain_type_t;
|
||||
|
||||
/**
|
||||
* Type of scope variables.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
JERRY_DEBUGGER_VALUE_NONE = 1,
|
||||
JERRY_DEBUGGER_VALUE_UNDEFINED = 2,
|
||||
JERRY_DEBUGGER_VALUE_NULL = 3,
|
||||
JERRY_DEBUGGER_VALUE_BOOLEAN = 4,
|
||||
JERRY_DEBUGGER_VALUE_NUMBER = 5,
|
||||
JERRY_DEBUGGER_VALUE_STRING = 6,
|
||||
JERRY_DEBUGGER_VALUE_FUNCTION = 7,
|
||||
JERRY_DEBUGGER_VALUE_ARRAY = 8,
|
||||
JERRY_DEBUGGER_VALUE_OBJECT = 9
|
||||
} jerry_debugger_scope_variable_type_t;
|
||||
|
||||
/**
|
||||
* Byte data for evaluating expressions and receiving client source.
|
||||
*/
|
||||
@@ -364,6 +396,15 @@ typedef struct
|
||||
jerry_debugger_frame_t frames[]; /**< frames */
|
||||
} jerry_debugger_send_backtrace_t;
|
||||
|
||||
/**
|
||||
* Outgoing message: scope chain.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t type; /**< type of the message */
|
||||
uint8_t scope_types[]; /**< scope types */
|
||||
} jerry_debugger_send_scope_chain_t;
|
||||
|
||||
/**
|
||||
* Outgoing message: number of total frames in backtrace.
|
||||
*/
|
||||
@@ -411,6 +452,15 @@ typedef struct
|
||||
uint8_t eval_size[sizeof (uint32_t)]; /**< total size of the message */
|
||||
} jerry_debugger_receive_eval_first_t;
|
||||
|
||||
/**
|
||||
* Incoming message: get scope variables
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t type; /**< type of the message */
|
||||
uint8_t chain_index[sizeof (uint32_t)]; /**< index element of the scope */
|
||||
} jerry_debugger_receive_get_scope_variables_t;
|
||||
|
||||
/**
|
||||
* Incoming message: first message of client source.
|
||||
*/
|
||||
|
||||
@@ -700,6 +700,13 @@ typedef enum
|
||||
*/
|
||||
#define ECMA_OBJECT_FLAG_EXTENSIBLE 0x20
|
||||
|
||||
/**
|
||||
* Non closure flag for debugger.
|
||||
*/
|
||||
#ifdef JERRY_DEBUGGER
|
||||
#define ECMA_OBJECT_FLAG_NON_CLOSURE 0x20
|
||||
#endif /* JERRY_DEBUGGER */
|
||||
|
||||
/**
|
||||
* Value for increasing or decreasing the object reference counter.
|
||||
*/
|
||||
@@ -719,7 +726,7 @@ typedef struct
|
||||
/** type : 4 bit : ecma_object_type_t or ecma_lexical_environment_type_t
|
||||
depending on ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV
|
||||
flags : 2 bit : ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV,
|
||||
ECMA_OBJECT_FLAG_EXTENSIBLE
|
||||
ECMA_OBJECT_FLAG_EXTENSIBLE or ECMA_OBJECT_FLAG_NON_CLOSURE
|
||||
refs : 10 bit (max 1023) */
|
||||
uint16_t type_flags_refs;
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ extern "C"
|
||||
/**
|
||||
* JerryScript debugger protocol version.
|
||||
*/
|
||||
#define JERRY_DEBUGGER_VERSION (6)
|
||||
#define JERRY_DEBUGGER_VERSION (7)
|
||||
|
||||
/**
|
||||
* Types for the client source wait and run method.
|
||||
|
||||
@@ -3315,6 +3315,9 @@ error:
|
||||
}
|
||||
|
||||
ecma_object_t *catch_env_p = ecma_create_decl_lex_env (frame_ctx_p->lex_env_p);
|
||||
#ifdef JERRY_DEBUGGER
|
||||
catch_env_p->type_flags_refs |= (uint16_t) ECMA_OBJECT_FLAG_NON_CLOSURE;
|
||||
#endif /* JERRY_DEBUGGER */
|
||||
|
||||
ecma_string_t *catch_name_p = ecma_get_string_from_value (literal_start_p[literal_index]);
|
||||
ecma_op_create_mutable_binding (catch_env_p, catch_name_p, false);
|
||||
|
||||
@@ -118,6 +118,11 @@ class DebuggerPrompt(Cmd):
|
||||
self.stop = True
|
||||
do_bt = do_backtrace
|
||||
|
||||
def do_variables(self, args):
|
||||
""" Get scope variables from debugger """
|
||||
write(self.debugger.scope_variables(args))
|
||||
self.stop = True
|
||||
|
||||
def do_src(self, args):
|
||||
""" Get current source code """
|
||||
if args:
|
||||
@@ -172,6 +177,11 @@ class DebuggerPrompt(Cmd):
|
||||
self.stop = True
|
||||
do_ms = do_memstats
|
||||
|
||||
def do_scopes(self, _):
|
||||
""" Memory statistics """
|
||||
self.debugger.scope_chain()
|
||||
self.stop = True
|
||||
|
||||
def do_abort(self, args):
|
||||
""" Throw an exception """
|
||||
self.debugger.abort(args)
|
||||
|
||||
@@ -24,7 +24,7 @@ import struct
|
||||
import sys
|
||||
|
||||
# Expected debugger protocol version.
|
||||
JERRY_DEBUGGER_VERSION = 6
|
||||
JERRY_DEBUGGER_VERSION = 7
|
||||
|
||||
# Messages sent by the server to client.
|
||||
JERRY_DEBUGGER_CONFIGURATION = 1
|
||||
@@ -54,6 +54,10 @@ JERRY_DEBUGGER_EVAL_RESULT_END = 24
|
||||
JERRY_DEBUGGER_WAIT_FOR_SOURCE = 25
|
||||
JERRY_DEBUGGER_OUTPUT_RESULT = 26
|
||||
JERRY_DEBUGGER_OUTPUT_RESULT_END = 27
|
||||
JERRY_DEBUGGER_SCOPE_CHAIN = 28
|
||||
JERRY_DEBUGGER_SCOPE_CHAIN_END = 29
|
||||
JERRY_DEBUGGER_SCOPE_VARIABLES = 30
|
||||
JERRY_DEBUGGER_SCOPE_VARIABLES_END = 31
|
||||
|
||||
# Debugger option flags
|
||||
JERRY_DEBUGGER_LITTLE_ENDIAN = 0x1
|
||||
@@ -94,11 +98,28 @@ JERRY_DEBUGGER_FINISH = 15
|
||||
JERRY_DEBUGGER_GET_BACKTRACE = 16
|
||||
JERRY_DEBUGGER_EVAL = 17
|
||||
JERRY_DEBUGGER_EVAL_PART = 18
|
||||
JERRY_DEBUGGER_GET_SCOPE_CHAIN = 19
|
||||
JERRY_DEBUGGER_GET_SCOPE_VARIABLES = 20
|
||||
|
||||
MAX_BUFFER_SIZE = 128
|
||||
WEBSOCKET_BINARY_FRAME = 2
|
||||
WEBSOCKET_FIN_BIT = 0x80
|
||||
|
||||
JERRY_DEBUGGER_SCOPE_WITH = 1
|
||||
JERRY_DEBUGGER_SCOPE_LOCAL = 2
|
||||
JERRY_DEBUGGER_SCOPE_CLOSURE = 3
|
||||
JERRY_DEBUGGER_SCOPE_GLOBAL = 4
|
||||
JERRY_DEBUGGER_SCOPE_NON_CLOSURE = 5
|
||||
|
||||
JERRY_DEBUGGER_VALUE_NONE = 1
|
||||
JERRY_DEBUGGER_VALUE_UNDEFINED = 2
|
||||
JERRY_DEBUGGER_VALUE_NULL = 3
|
||||
JERRY_DEBUGGER_VALUE_BOOLEAN = 4
|
||||
JERRY_DEBUGGER_VALUE_NUMBER = 5
|
||||
JERRY_DEBUGGER_VALUE_STRING = 6
|
||||
JERRY_DEBUGGER_VALUE_FUNCTION = 7
|
||||
JERRY_DEBUGGER_VALUE_ARRAY = 8
|
||||
JERRY_DEBUGGER_VALUE_OBJECT = 9
|
||||
|
||||
def arguments_parse():
|
||||
parser = argparse.ArgumentParser(description="JerryScript debugger client")
|
||||
@@ -264,6 +285,8 @@ class JerryDebugger(object):
|
||||
self.source_name = ''
|
||||
self.exception_string = ''
|
||||
self.frame_index = 0
|
||||
self.scope_vars = ""
|
||||
self.scopes = ""
|
||||
self.client_sources = []
|
||||
self.last_breakpoint_hit = None
|
||||
self.next_breakpoint_index = 0
|
||||
@@ -394,6 +417,10 @@ class JerryDebugger(object):
|
||||
self.prompt = False
|
||||
self._exec_command(JERRY_DEBUGGER_MEMSTATS)
|
||||
|
||||
def scope_chain(self):
|
||||
self.prompt = False
|
||||
self._exec_command(JERRY_DEBUGGER_GET_SCOPE_CHAIN)
|
||||
|
||||
def set_break(self, args):
|
||||
if not args:
|
||||
return "Error: Breakpoint index expected"
|
||||
@@ -500,6 +527,28 @@ class JerryDebugger(object):
|
||||
self.prompt = False
|
||||
return ""
|
||||
|
||||
def scope_variables(self, args):
|
||||
index = 0
|
||||
if args:
|
||||
try:
|
||||
index = int(args)
|
||||
if index < 0:
|
||||
print ("Error: A non negative integer number expected")
|
||||
return
|
||||
|
||||
except ValueError as val_errno:
|
||||
return "Error: Non negative integer number expected, %s\n" % (val_errno)
|
||||
|
||||
message = struct.pack(self.byte_order + "BBIB" + self.idx_format,
|
||||
WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
|
||||
WEBSOCKET_FIN_BIT + 1 + 4,
|
||||
0,
|
||||
JERRY_DEBUGGER_GET_SCOPE_VARIABLES,
|
||||
index)
|
||||
self.send_message(message)
|
||||
self.prompt = False
|
||||
return ""
|
||||
|
||||
def eval(self, code):
|
||||
self._send_string(JERRY_DEBUGGER_EVAL_EVAL + code, JERRY_DEBUGGER_EVAL)
|
||||
self.prompt = False
|
||||
@@ -724,7 +773,6 @@ class JerryDebugger(object):
|
||||
|
||||
while True:
|
||||
data = self.get_message(False)
|
||||
|
||||
if not self.non_interactive:
|
||||
if sys.stdin in select.select([sys.stdin], [], [], 0)[0]:
|
||||
sys.stdin.readline()
|
||||
@@ -848,6 +896,29 @@ class JerryDebugger(object):
|
||||
|
||||
elif buffer_type == JERRY_DEBUGGER_WAIT_FOR_SOURCE:
|
||||
self.send_client_source()
|
||||
|
||||
elif buffer_type in [JERRY_DEBUGGER_SCOPE_CHAIN, JERRY_DEBUGGER_SCOPE_CHAIN_END]:
|
||||
self.scopes = data[3:]
|
||||
|
||||
if buffer_type == JERRY_DEBUGGER_SCOPE_CHAIN_END:
|
||||
result = self.process_scopes()
|
||||
self.scopes = ""
|
||||
|
||||
self.prompt = True
|
||||
|
||||
return DebuggerAction(DebuggerAction.TEXT, result)
|
||||
|
||||
elif buffer_type in [JERRY_DEBUGGER_SCOPE_VARIABLES, JERRY_DEBUGGER_SCOPE_VARIABLES_END]:
|
||||
self.scope_vars += "".join(data[3:])
|
||||
|
||||
if buffer_type == JERRY_DEBUGGER_SCOPE_VARIABLES_END:
|
||||
result = self.process_scope_variables()
|
||||
self.scope_vars = ""
|
||||
|
||||
self.prompt = True
|
||||
|
||||
return DebuggerAction(DebuggerAction.TEXT, result)
|
||||
|
||||
else:
|
||||
raise Exception("Unknown message")
|
||||
|
||||
@@ -1203,3 +1274,79 @@ class JerryDebugger(object):
|
||||
if subtype == JERRY_DEBUGGER_EVAL_ERROR:
|
||||
return "Uncaught exception: %s" % (message)
|
||||
return message
|
||||
|
||||
def process_scope_variables(self):
|
||||
buff_size = len(self.scope_vars)
|
||||
buff_pos = 0
|
||||
|
||||
table = [['name', 'type', 'value']]
|
||||
|
||||
while buff_pos != buff_size:
|
||||
# Process name
|
||||
name_length = ord(self.scope_vars[buff_pos:buff_pos + 1])
|
||||
buff_pos += 1
|
||||
name = self.scope_vars[buff_pos:buff_pos + name_length]
|
||||
buff_pos += name_length
|
||||
|
||||
# Process type
|
||||
value_type = ord(self.scope_vars[buff_pos:buff_pos + 1])
|
||||
|
||||
buff_pos += 1
|
||||
|
||||
value_length = ord(self.scope_vars[buff_pos:buff_pos + 1])
|
||||
buff_pos += 1
|
||||
value = self.scope_vars[buff_pos: buff_pos + value_length]
|
||||
buff_pos += value_length
|
||||
|
||||
if value_type == JERRY_DEBUGGER_VALUE_UNDEFINED:
|
||||
table.append([name, 'undefined', value])
|
||||
elif value_type == JERRY_DEBUGGER_VALUE_NULL:
|
||||
table.append([name, 'Null', value])
|
||||
elif value_type == JERRY_DEBUGGER_VALUE_BOOLEAN:
|
||||
table.append([name, 'Boolean', value])
|
||||
elif value_type == JERRY_DEBUGGER_VALUE_NUMBER:
|
||||
table.append([name, 'Number', value])
|
||||
elif value_type == JERRY_DEBUGGER_VALUE_STRING:
|
||||
table.append([name, 'String', value])
|
||||
elif value_type == JERRY_DEBUGGER_VALUE_FUNCTION:
|
||||
table.append([name, 'Function', value])
|
||||
elif value_type == JERRY_DEBUGGER_VALUE_ARRAY:
|
||||
table.append([name, 'Array', '[' + value + ']'])
|
||||
elif value_type == JERRY_DEBUGGER_VALUE_OBJECT:
|
||||
table.append([name, 'Object', value])
|
||||
|
||||
result = self.form_table(table)
|
||||
|
||||
return result
|
||||
|
||||
def process_scopes(self):
|
||||
result = ""
|
||||
table = [['level', 'type']]
|
||||
|
||||
for i, level in enumerate(self.scopes):
|
||||
if ord(level) == JERRY_DEBUGGER_SCOPE_WITH:
|
||||
table.append([str(i), 'with'])
|
||||
elif ord(level) == JERRY_DEBUGGER_SCOPE_GLOBAL:
|
||||
table.append([str(i), 'global'])
|
||||
elif ord(level) == JERRY_DEBUGGER_SCOPE_NON_CLOSURE:
|
||||
# Currently it is only marks the catch closure.
|
||||
table.append([str(i), 'catch'])
|
||||
elif ord(level) == JERRY_DEBUGGER_SCOPE_LOCAL:
|
||||
table.append([str(i), 'local'])
|
||||
elif ord(level) == JERRY_DEBUGGER_SCOPE_CLOSURE:
|
||||
table.append([str(i), 'closure'])
|
||||
else:
|
||||
raise Exception("Unexpected scope chain element")
|
||||
|
||||
result = self.form_table(table)
|
||||
|
||||
return result
|
||||
|
||||
def form_table(self, table):
|
||||
result = ""
|
||||
col_width = [max(len(x) for x in col) for col in zip(*table)]
|
||||
for line in table:
|
||||
result += " | ".join("{:{}}".format(x, col_width[i])
|
||||
for i, x in enumerate(line)) + " \n"
|
||||
|
||||
return result
|
||||
|
||||
@@ -4,9 +4,9 @@ Stopped at tests/debugger/do_help.js:15
|
||||
|
||||
Documented commands (type help <topic>):
|
||||
========================================
|
||||
abort bt display exception list next s step
|
||||
b c dump f memstats quit scroll throw
|
||||
backtrace continue e finish ms res source
|
||||
break delete eval help n restart src
|
||||
abort bt display exception list next s src
|
||||
b c dump f memstats quit scopes step
|
||||
backtrace continue e finish ms res scroll throw
|
||||
break delete eval help n restart source variables
|
||||
|
||||
(jerry-debugger) quit
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
scopes
|
||||
b do_scopes.js:22
|
||||
c
|
||||
scopes
|
||||
c
|
||||
scopes
|
||||
b do_scopes.js:28
|
||||
c
|
||||
scopes
|
||||
b do_scopes.js:31
|
||||
c
|
||||
scopes
|
||||
b do_scopes.js:33
|
||||
c
|
||||
scopes
|
||||
b do_scopes.js:35
|
||||
c
|
||||
scopes
|
||||
c
|
||||
@@ -0,0 +1,63 @@
|
||||
Connecting to: localhost:5001
|
||||
Stopped at tests/debugger/do_scopes.js:15
|
||||
(jerry-debugger) scopes
|
||||
level | type
|
||||
0 | global
|
||||
(jerry-debugger) b do_scopes.js:22
|
||||
Breakpoint 1 at tests/debugger/do_scopes.js:22 (in f() at line:17, col:1)
|
||||
(jerry-debugger) c
|
||||
Exception throw detected (to disable automatic stop type exception 0)
|
||||
Exception hint: error
|
||||
Stopped at tests/debugger/do_scopes.js:19 (in f() at line:17, col:1)
|
||||
(jerry-debugger) scopes
|
||||
level | type
|
||||
0 | local
|
||||
1 | global
|
||||
(jerry-debugger) c
|
||||
Stopped at breakpoint:1 tests/debugger/do_scopes.js:22 (in f() at line:17, col:1)
|
||||
(jerry-debugger) scopes
|
||||
level | type
|
||||
0 | catch
|
||||
1 | local
|
||||
2 | global
|
||||
(jerry-debugger) b do_scopes.js:28
|
||||
Breakpoint 2 at tests/debugger/do_scopes.js:28 (in function() at line:27, col:4)
|
||||
(jerry-debugger) c
|
||||
Stopped at breakpoint:2 tests/debugger/do_scopes.js:28 (in function() at line:27, col:4)
|
||||
(jerry-debugger) scopes
|
||||
level | type
|
||||
0 | local
|
||||
1 | closure
|
||||
2 | global
|
||||
(jerry-debugger) b do_scopes.js:31
|
||||
Breakpoint 3 at tests/debugger/do_scopes.js:31 (in function() at line:27, col:4)
|
||||
(jerry-debugger) c
|
||||
Stopped at breakpoint:3 tests/debugger/do_scopes.js:31 (in function() at line:27, col:4)
|
||||
(jerry-debugger) scopes
|
||||
level | type
|
||||
0 | with
|
||||
1 | local
|
||||
2 | closure
|
||||
3 | global
|
||||
(jerry-debugger) b do_scopes.js:33
|
||||
Breakpoint 4 at tests/debugger/do_scopes.js:33 (in function() at line:27, col:4)
|
||||
(jerry-debugger) c
|
||||
Stopped at breakpoint:4 tests/debugger/do_scopes.js:33 (in function() at line:27, col:4)
|
||||
(jerry-debugger) scopes
|
||||
level | type
|
||||
0 | with
|
||||
1 | with
|
||||
2 | local
|
||||
3 | closure
|
||||
4 | global
|
||||
(jerry-debugger) b do_scopes.js:35
|
||||
Breakpoint 5 at tests/debugger/do_scopes.js:35 (in function() at line:27, col:4)
|
||||
(jerry-debugger) c
|
||||
Stopped at breakpoint:5 tests/debugger/do_scopes.js:35 (in function() at line:27, col:4)
|
||||
(jerry-debugger) scopes
|
||||
level | type
|
||||
0 | with
|
||||
1 | local
|
||||
2 | closure
|
||||
3 | global
|
||||
(jerry-debugger) c
|
||||
@@ -0,0 +1,41 @@
|
||||
// Copyright JS Foundation and other contributors, http://js.foundation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
var c = 4;
|
||||
|
||||
function f() {
|
||||
try {
|
||||
throw "error";
|
||||
}
|
||||
catch (err) {
|
||||
var c = 10;
|
||||
}
|
||||
|
||||
var z = true;
|
||||
var g = 0;
|
||||
(function() {
|
||||
var a = [1,2,3]
|
||||
a.y = "abc";
|
||||
with (a) {
|
||||
var h = [4,5,6]
|
||||
with (h) {
|
||||
h.d = "dfg"
|
||||
}
|
||||
a.d = g + c;
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
f();
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
scopes
|
||||
variables
|
||||
variables 1
|
||||
variables 0
|
||||
b tests/debugger/do_variables.js:20
|
||||
c
|
||||
scopes
|
||||
variables 0
|
||||
variables 1
|
||||
variables 2
|
||||
b tests/debugger/do_variables.js:30
|
||||
c
|
||||
scopes
|
||||
variables 1
|
||||
variables 0
|
||||
b tests/debugger/do_variables.js:33
|
||||
c
|
||||
c
|
||||
scopes
|
||||
variables 0
|
||||
variables 1
|
||||
b tests/debugger/do_variables.js:50
|
||||
c
|
||||
scopes
|
||||
variables 0
|
||||
variables 1
|
||||
variables 2
|
||||
c
|
||||
@@ -0,0 +1,128 @@
|
||||
Connecting to: localhost:5001
|
||||
Stopped at tests/debugger/do_variables.js:15
|
||||
(jerry-debugger) scopes
|
||||
level | type
|
||||
0 | global
|
||||
(jerry-debugger) variables
|
||||
name | type | value
|
||||
f | Function |
|
||||
addX | Function |
|
||||
z | undefined | undefined
|
||||
c | undefined | undefined
|
||||
print | Function |
|
||||
gc | Function |
|
||||
assert | Function |
|
||||
(jerry-debugger) variables 1
|
||||
name | type | value
|
||||
(jerry-debugger) variables 0
|
||||
name | type | value
|
||||
f | Function |
|
||||
addX | Function |
|
||||
z | undefined | undefined
|
||||
c | undefined | undefined
|
||||
print | Function |
|
||||
gc | Function |
|
||||
assert | Function |
|
||||
(jerry-debugger) b tests/debugger/do_variables.js:20
|
||||
Breakpoint 1 at tests/debugger/do_variables.js:20 (in function() at line:19, col:10)
|
||||
(jerry-debugger) c
|
||||
Stopped at breakpoint:1 tests/debugger/do_variables.js:20 (in function() at line:19, col:10)
|
||||
(jerry-debugger) scopes
|
||||
level | type
|
||||
0 | local
|
||||
1 | closure
|
||||
2 | global
|
||||
(jerry-debugger) variables 0
|
||||
name | type | value
|
||||
n | Number | 9
|
||||
b | undefined | undefined
|
||||
(jerry-debugger) variables 1
|
||||
name | type | value
|
||||
x | Number | 3
|
||||
(jerry-debugger) variables 2
|
||||
name | type | value
|
||||
addThree | Function |
|
||||
f | Function |
|
||||
addX | Function |
|
||||
z | Number | 5
|
||||
c | Number | 4
|
||||
print | Function |
|
||||
gc | Function |
|
||||
assert | Function |
|
||||
(jerry-debugger) b tests/debugger/do_variables.js:30
|
||||
Breakpoint 2 at tests/debugger/do_variables.js:30 (in f() at line:28, col:1)
|
||||
(jerry-debugger) c
|
||||
Stopped at breakpoint:2 tests/debugger/do_variables.js:30 (in f() at line:28, col:1)
|
||||
(jerry-debugger) scopes
|
||||
level | type
|
||||
0 | local
|
||||
1 | global
|
||||
(jerry-debugger) variables 1
|
||||
name | type | value
|
||||
d | Number | 12
|
||||
addThree | Function |
|
||||
f | Function |
|
||||
addX | Function |
|
||||
z | Number | 5
|
||||
c | Number | 4
|
||||
print | Function |
|
||||
gc | Function |
|
||||
assert | Function |
|
||||
(jerry-debugger) variables 0
|
||||
name | type | value
|
||||
b | undefined | undefined
|
||||
x | undefined | undefined
|
||||
user | undefined | undefined
|
||||
m | undefined | undefined
|
||||
c | undefined | undefined
|
||||
(jerry-debugger) b tests/debugger/do_variables.js:33
|
||||
Breakpoint 3 at tests/debugger/do_variables.js:33 (in f() at line:28, col:1)
|
||||
(jerry-debugger) c
|
||||
Exception throw detected (to disable automatic stop type exception 0)
|
||||
Exception hint: error
|
||||
Stopped at breakpoint:2 tests/debugger/do_variables.js:30 (in f() at line:28, col:1)
|
||||
(jerry-debugger) c
|
||||
Stopped at breakpoint:3 tests/debugger/do_variables.js:33 (in f() at line:28, col:1)
|
||||
(jerry-debugger) scopes
|
||||
level | type
|
||||
0 | catch
|
||||
1 | local
|
||||
2 | global
|
||||
(jerry-debugger) variables 0
|
||||
name | type | value
|
||||
err | String | error
|
||||
(jerry-debugger) variables 1
|
||||
name | type | value
|
||||
b | undefined | undefined
|
||||
x | undefined | undefined
|
||||
user | undefined | undefined
|
||||
m | undefined | undefined
|
||||
c | undefined | undefined
|
||||
(jerry-debugger) b tests/debugger/do_variables.js:50
|
||||
Breakpoint 4 at tests/debugger/do_variables.js:50 (in function() at line:46, col:4)
|
||||
(jerry-debugger) c
|
||||
Stopped at breakpoint:4 tests/debugger/do_variables.js:50 (in function() at line:46, col:4)
|
||||
(jerry-debugger) scopes
|
||||
level | type
|
||||
0 | with
|
||||
1 | local
|
||||
2 | closure
|
||||
3 | global
|
||||
(jerry-debugger) variables 0
|
||||
name | type | value
|
||||
y | String | abc
|
||||
2 | Number | 3
|
||||
1 | Number | 2
|
||||
0 | Number | 1
|
||||
(jerry-debugger) variables 1
|
||||
name | type | value
|
||||
h | undefined | undefined
|
||||
a | Array | [1,2,3]
|
||||
(jerry-debugger) variables 2
|
||||
name | type | value
|
||||
b | Number | 10
|
||||
x | Boolean | true
|
||||
user | Object | {"name":"John","age":30}
|
||||
m | Null | null
|
||||
c | Number | 10
|
||||
(jerry-debugger) c
|
||||
@@ -0,0 +1,60 @@
|
||||
// Copyright JS Foundation and other contributors, http://js.foundation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
var c = 4;
|
||||
var z = 5;
|
||||
|
||||
function addX(x) {
|
||||
return function(n) {
|
||||
var b = 2;
|
||||
return n + x;
|
||||
}
|
||||
}
|
||||
|
||||
addThree = addX(3);
|
||||
d = addThree(c+z);
|
||||
|
||||
function f() {
|
||||
try {
|
||||
throw "error";
|
||||
}
|
||||
catch (err) {
|
||||
var c = 10;
|
||||
}
|
||||
|
||||
var m = null;
|
||||
|
||||
var user = {
|
||||
name: "John",
|
||||
age: 30
|
||||
};
|
||||
|
||||
var x = true;
|
||||
var b = 10;
|
||||
|
||||
(function() {
|
||||
var a = [1,2,3]
|
||||
a.y = "abc";
|
||||
with (a) {
|
||||
var h = [4,5,6]
|
||||
with (h) {
|
||||
h.d = "dfg"
|
||||
}
|
||||
a.d = x;
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
f();
|
||||
|
||||
Reference in New Issue
Block a user