List scope chain levels and their variables to the selected stack frame.

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
diff --git a/jerry-core/debugger/debugger.c b/jerry-core/debugger/debugger.c
index 3f9ed5b..ef52470 100644
--- a/jerry-core/debugger/debugger.c
+++ b/jerry-core/debugger/debugger.c
@@ -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 @@
  * 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 == 31
+                     && JERRY_DEBUGGER_MESSAGES_IN_MAX_COUNT == 21
+                     && JERRY_DEBUGGER_VERSION == 7,
                      debugger_version_correlates_to_message_type_count);
 
 /**
@@ -195,6 +196,258 @@
   jerry_debugger_send (sizeof (jerry_debugger_send_type_t) + message_size);
 } /* jerry_debugger_send_backtrace */
 
+
+/**
+ * Send the scope chain.
+ */
+static void
+jerry_debugger_send_scope_chain (void)
+{
+  vm_frame_ctx_t *iter_frame_ctx_p = JERRY_CONTEXT (vm_top_context_p);
+
+  size_t count = 0;
+  const size_t send_max = JERRY_DEBUGGER_SEND_MAX (uint8_t);
+  bool prev_is_object_bound = false;
+
+  uint8_t scope_types[send_max];
+
+  for (ecma_object_t *lex_env_p =  iter_frame_ctx_p->lex_env_p;
+       lex_env_p != NULL;
+       lex_env_p = ecma_get_lex_env_outer_reference(lex_env_p))
+  {
+    if (ecma_is_lexical_environment (lex_env_p))
+    {
+      if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
+      {
+        if (count == 0 || prev_is_object_bound)
+        {
+          scope_types[count++] = JERRY_DEBUGGER_SCOPE_LOCAL;
+        }
+        else {
+          scope_types[count++] = JERRY_DEBUGGER_SCOPE_CLOSURE;
+        }
+
+        prev_is_object_bound = false;
+      }
+      else
+      {
+        JERRY_ASSERT (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)
+        {
+          scope_types[count++] = JERRY_DEBUGGER_SCOPE_GLOBAL;
+        }
+        else {
+          scope_types[count++] = JERRY_DEBUGGER_SCOPE_WITH;
+          prev_is_object_bound = true;
+        }
+      }
+    }
+  }
+
+  JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_string_t, message_type_p);
+
+  message_type_p->type = JERRY_DEBUGGER_SCOPE_CHAIN;
+  memcpy (message_type_p->string, scope_types, count);
+
+  jerry_debugger_send (sizeof (jerry_debugger_send_type_t) + count);
+
+} /* jerry_debugger_send_scope_chain */
+
+static jerry_debugger_scope_variable_type_t
+ecma_get_typeof_scope_variable (ecma_value_t value) /**< input ecma value */
+{
+  jerry_debugger_scope_variable_type_t ret_value = JERRY_DEBUGGER_VARIABLE_NONE;
+
+  if (ecma_is_value_undefined (value))
+  {
+    ret_value = JERRY_DEBUGGER_VARIABLE_UNDEFINED;
+  }
+  else if (ecma_is_value_null (value))
+  {
+    ret_value = JERRY_DEBUGGER_VARIABLE_OBJECT;
+  }
+  else if (ecma_is_value_boolean (value))
+  {
+    ret_value = JERRY_DEBUGGER_VARIABLE_BOOLEAN;
+  }
+  else if (ecma_is_value_number (value))
+  {
+    ret_value = JERRY_DEBUGGER_VARIABLE_NUMBER;
+  }
+  else if (ecma_is_value_string (value))
+  {
+    ret_value = JERRY_DEBUGGER_VARIABLE_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_VARIABLE_ARRAY;
+    }
+    else
+    {
+      ret_value = ecma_op_is_callable (value) ? JERRY_DEBUGGER_VARIABLE_FUNCTION : JERRY_DEBUGGER_VARIABLE_OBJECT;
+    }
+  }
+
+  JERRY_ASSERT (ret_value != JERRY_DEBUGGER_VARIABLE_NONE);
+
+  return ret_value;
+} /* ecma_get_typeof_scope_variable */
+
+static bool
+copy_value_to_string_message (jerry_debugger_scope_variable_type_t variable_type,
+                              ecma_string_t *value_str,
+                              jerry_debugger_send_string_t *message_string_p,
+                              size_t *curr_msg_length)
+{
+  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);
+
+  if (*curr_msg_length == max_byte_count)
+  {
+    if (!jerry_debugger_send (max_message_size))
+    {
+      return false;
+    }
+  }
+
+  if (variable_type != JERRY_DEBUGGER_VARIABLE_NONE)
+  {
+    uint8_t type_value = (uint8_t) variable_type;
+    memcpy (message_string_p->string + *curr_msg_length, &type_value, 1);
+    *curr_msg_length += 1;
+  }
+
+  ECMA_STRING_TO_UTF8_STRING (value_str, str_buff, str_buff_size);
+
+  if (*curr_msg_length == max_byte_count)
+  {
+    if (!jerry_debugger_send (max_message_size))
+    {
+      return false;
+    }
+  }
+
+  uint8_t str_size = (uint8_t) str_buff_size;
+  memcpy (message_string_p->string + *curr_msg_length, &str_size, 1);
+  *curr_msg_length += 1;
+
+  size_t free_bytes = max_byte_count - *curr_msg_length;
+  const uint8_t* string_p = str_buff;
+  size_t remained_size = str_buff_size;
+
+  while (remained_size > free_bytes)
+  {
+    memcpy (message_string_p->string + *curr_msg_length, string_p, free_bytes);
+
+    if (!jerry_debugger_send (max_message_size))
+    {
+      ECMA_FINALIZE_UTF8_STRING (str_buff, str_buff_size);
+
+      return false;
+    }
+
+    string_p += free_bytes;
+    remained_size -= free_bytes;
+    free_bytes = max_byte_count;
+    *curr_msg_length = 0;
+  }
+
+  memcpy (message_string_p->string + *curr_msg_length, string_p, remained_size);
+  *curr_msg_length += remained_size;
+
+  ECMA_FINALIZE_UTF8_STRING (str_buff, str_buff_size);
+
+  return true;
+} /* copy_value_to_string_message */
+
+static void
+jerry_debugger_send_scope_variables (const uint8_t *recv_buffer_p)
+{
+  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 (lex_env_p == NULL)
+    {
+      jerry_debugger_send_type (JERRY_DEBUGGER_SCOPE_VARIABLES_END);
+      return;
+    }
+    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 string_length = 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]))
+      {
+        ecma_string_t* prop_name = ecma_string_from_property_name (prop_iter_p->types[i],
+                                                                   prop_pair_p->names_cp[i]);
+
+        if (!copy_value_to_string_message (JERRY_DEBUGGER_VARIABLE_NONE,
+                                           prop_name,
+                                           message_string_p,
+                                           &string_length))
+        {
+          return;
+        }
+
+        ecma_property_value_t prop_value_p = prop_pair_p->values[i];
+        ecma_value_t final_str = ecma_op_to_string (prop_value_p.value);
+
+        if (!copy_value_to_string_message (ecma_get_typeof_scope_variable (prop_value_p.value),
+                                           ecma_get_string_from_value (final_str),
+                                           message_string_p,
+                                           &string_length))
+        {
+          return;
+        }
+
+        ecma_free_value (final_str);
+      }
+    }
+
+    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) + string_length);
+} /* jerry_debugger_send_scope_variables */
+
 /**
  * Send result of evaluated expression or throw an error.
  *
@@ -525,6 +778,24 @@
       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);
diff --git a/jerry-core/debugger/debugger.h b/jerry-core/debugger/debugger.h
index 5b1db98..11caadc 100644
--- a/jerry-core/debugger/debugger.h
+++ b/jerry-core/debugger/debugger.h
@@ -26,7 +26,7 @@
 /**
  * JerryScript debugger protocol version.
  */
-#define JERRY_DEBUGGER_VERSION (6)
+#define JERRY_DEBUGGER_VERSION (7)
 
 /**
  * Frequency of calling jerry_debugger_receive() by the VM.
@@ -157,7 +157,9 @@
   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,
+  JERRY_DEBUGGER_SCOPE_VARIABLES = 29,
+  JERRY_DEBUGGER_SCOPE_VARIABLES_END = 30,
   JERRY_DEBUGGER_MESSAGES_OUT_MAX_COUNT, /**< number of different type of output messages by the debugger */
 
   /* Messages sent by the client to server. */
@@ -187,7 +189,8 @@
   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 the lex env names from the scope chain */
+  JERRY_DEBUGGER_GET_SCOPE_VARIABLES = 20,
   JERRY_DEBUGGER_MESSAGES_IN_MAX_COUNT, /**< number of different type of input messages */
 } jerry_debugger_header_type_t;
 
@@ -235,6 +238,33 @@
 } jerry_debugger_output_subtype_t;
 
 /**
+ * Types of scope chain.
+ *
+ */
+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_CATCH = 5
+} jerry_debugger_scope_chain_type_t;
+
+
+typedef enum
+{
+  JERRY_DEBUGGER_VARIABLE_NONE = 1,
+  JERRY_DEBUGGER_VARIABLE_UNDEFINED = 2,
+  JERRY_DEBUGGER_VARIABLE_NULL = 3,
+  JERRY_DEBUGGER_VARIABLE_BOOLEAN = 4,
+  JERRY_DEBUGGER_VARIABLE_NUMBER = 5,
+  JERRY_DEBUGGER_VARIABLE_STRING = 6,
+  JERRY_DEBUGGER_VARIABLE_FUNCTION = 7,
+  JERRY_DEBUGGER_VARIABLE_ARRAY = 8,
+  JERRY_DEBUGGER_VARIABLE_OBJECT = 9
+} jerry_debugger_scope_variable_type_t;
+
+/**
  * Byte data for evaluating expressions and receiving client source.
  */
 typedef struct
@@ -370,6 +400,15 @@
 } jerry_debugger_send_backtrace_t;
 
 /**
+ * Outgoing message: scope chain information.
+ */
+typedef struct
+{
+  uint8_t type; /**< type of the message */
+  uint8_t chain_types[]; /**< scope chain types */
+} jerry_debugger_send_scope_chain_t;
+
+/**
  * Outgoing message: number of total frames in backtrace.
  */
 typedef struct
@@ -417,6 +456,15 @@
 } 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.
  */
 typedef struct
diff --git a/jerry-debugger/jerry_client.py b/jerry-debugger/jerry_client.py
index 7e34b69..e63dc77 100755
--- a/jerry-debugger/jerry_client.py
+++ b/jerry-debugger/jerry_client.py
@@ -118,6 +118,12 @@
         self.stop = True
     do_bt = do_backtrace
 
+    def do_scope_variables(self, args):
+        """ Get scope variables from debugger """
+        write(self.debugger.scope_variables(args))
+        self.stop = True
+    do_sv = do_scope_variables
+
     def do_src(self, args):
         """ Get current source code """
         if args:
@@ -172,6 +178,12 @@
         self.stop = True
     do_ms = do_memstats
 
+    def do_scope_chain(self, _):
+        """ Memory statistics """
+        self.debugger.scope_chain()
+        self.stop = True
+    do_sc = do_scope_chain
+
     def do_abort(self, args):
         """ Throw an exception """
         self.debugger.abort(args)
diff --git a/jerry-debugger/jerry_client_ws.py b/jerry-debugger/jerry_client_ws.py
index 246e376..a26e6b9 100644
--- a/jerry-debugger/jerry_client_ws.py
+++ b/jerry-debugger/jerry_client_ws.py
@@ -22,9 +22,10 @@
 import socket
 import struct
 import sys
+from tabulate import tabulate
 
 # 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 +55,9 @@
 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_VARIABLES = 29
+JERRY_DEBUGGER_SCOPE_VARIABLES_END = 30
 
 # Debugger option flags
 JERRY_DEBUGGER_LITTLE_ENDIAN = 0x1
@@ -94,11 +98,27 @@
 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_VARIABLE_NONE = 1
+JERRY_DEBUGGER_VARIABLE_UNDEFINED = 2
+JERRY_DEBUGGER_VARIABLE_NULL = 3
+JERRY_DEBUGGER_VARIABLE_BOOLEAN = 4
+JERRY_DEBUGGER_VARIABLE_NUMBER = 5
+JERRY_DEBUGGER_VARIABLE_STRING = 6
+JERRY_DEBUGGER_VARIABLE_FUNCTION = 7
+JERRY_DEBUGGER_VARIABLE_ARRAY = 8
+JERRY_DEBUGGER_VARIABLE_OBJECT = 9
 
 def arguments_parse():
     parser = argparse.ArgumentParser(description="JerryScript debugger client")
@@ -264,6 +284,7 @@
         self.source_name = ''
         self.exception_string = ''
         self.frame_index = 0
+        self.scope_vars = ""
         self.client_sources = []
         self.last_breakpoint_hit = None
         self.next_breakpoint_index = 0
@@ -394,6 +415,10 @@
         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 +525,27 @@
         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" % (vall_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 +770,6 @@
 
         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,7 +893,49 @@
 
             elif buffer_type == JERRY_DEBUGGER_WAIT_FOR_SOURCE:
                 self.send_client_source()
+
+            elif buffer_type == JERRY_DEBUGGER_SCOPE_CHAIN:
+                scope_chain = []
+                for i in data[3:]:
+                    if ord(i) == JERRY_DEBUGGER_SCOPE_WITH:
+                        scope_chain.append("with")
+                    elif ord(i) == JERRY_DEBUGGER_SCOPE_GLOBAL:
+                        scope_chain.append("global")
+                    elif ord(i) == JERRY_DEBUGGER_SCOPE_CLOSURE:
+                        scope_chain.append("closure")
+                    elif ord(i) == JERRY_DEBUGGER_SCOPE_LOCAL:
+                        scope_chain.append("local")
+                    else:
+                        raise Exception("Unexpected scope chain element")
+
+                headers = ['index', 'type']
+                table = []
+                for index, scope_type in enumerate(scope_chain):
+                    table.append([index, scope_type])
+
+                result = tabulate(table, headers = headers)
+                if not result.endswith('\n'):
+                    result += '\n'
+
+                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:
+                print (buffer_type)
                 raise Exception("Unknown message")
 
     def print_source(self, line_num, offset):
@@ -1203,3 +1290,53 @@
         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
+
+        headers = ['name', 'type', 'value']
+        table = []
+
+        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_VARIABLE_UNDEFINED:
+                table.append([name,'undefined'])
+                #result += 'undefined\n'
+            elif value_type == JERRY_DEBUGGER_VARIABLE_NULL:
+                table.append([name, 'Null'])
+                #result += 'Null\n'
+            elif value_type == JERRY_DEBUGGER_VARIABLE_BOOLEAN:
+                table.append([name,'Boolean', bool(value)])
+            elif value_type == JERRY_DEBUGGER_VARIABLE_NUMBER:
+                table.append([name,'Number', value])
+            elif value_type == JERRY_DEBUGGER_VARIABLE_STRING:
+                table.append([name,'String', value])
+            elif value_type == JERRY_DEBUGGER_VARIABLE_FUNCTION:
+                table.append([name,'Function', value])
+            elif value_type == JERRY_DEBUGGER_VARIABLE_ARRAY:
+                table.append([name,'Array', '[' + value + ']'])
+            elif value_type == JERRY_DEBUGGER_VARIABLE_OBJECT:
+                table.append([name,'Object', '{' + value + '}'])
+
+        result = tabulate(table, headers=headers)
+
+        if not result.endswith('\n'):
+            result += '\n'
+
+        return result
diff --git a/tools/apt-get-install-deps.sh b/tools/apt-get-install-deps.sh
index a2eaf6e..8e79162 100755
--- a/tools/apt-get-install-deps.sh
+++ b/tools/apt-get-install-deps.sh
@@ -19,4 +19,4 @@
     make cmake \
     gcc gcc-multilib \
     doxygen \
-    cppcheck vera++ python
+    cppcheck vera++ python python-tabulate