def get_message(self, blocking):
        """ Receive message. """

        # Connection was closed
        if self.data_buffer is None:
            return None

        while True:
            if len(self.data_buffer) >= 2:
                if jerry_ord(self.data_buffer[0]
                             ) != WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT:
                    raise Exception("Unexpected data frame")

                size = jerry_ord(self.data_buffer[1])
                if size == 0 or size >= 126:
                    raise Exception("Unexpected data frame")

                if len(self.data_buffer) >= size + 2:
                    result = self.data_buffer[2:size + 2]
                    self.data_buffer = self.data_buffer[size + 2:]
                    return result

            if not blocking and not self.protocol.ready():
                return b''

            data = self.protocol.receive_data(MAX_BUFFER_SIZE)

            if not data:
                self.data_buffer = None
                return None
            self.data_buffer += data
    def get_message(self, blocking):
        """ Receive message. """

        # Connection was closed
        if self.data_buffer is None:
            return None

        while True:
            if len(self.data_buffer) >= 1:
                size = jerry_ord(self.data_buffer[0])
                if size == 0:
                    raise Exception("Unexpected data frame")

                if len(self.data_buffer) >= size + 1:
                    result = self.data_buffer[1:size + 1]
                    self.data_buffer = self.data_buffer[size + 1:]
                    return result

            if not blocking and not self.protocol.ready():
                return b''

            received_data = self.protocol.receive_data(MAX_BUFFER_SIZE)

            if not received_data:
                return None

            self.data_buffer += received_data
    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 = jerry_ord(self.scope_vars[buff_pos])
            buff_pos += 1
            name = jerry_decode(self.scope_vars[buff_pos:buff_pos +
                                                name_length])
            buff_pos += name_length

            # Process type
            value_type = jerry_ord(self.scope_vars[buff_pos])

            buff_pos += 1

            value_length = jerry_ord(self.scope_vars[buff_pos])
            buff_pos += 1
            value = jerry_decode(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_scope(self):
        table = [['level', 'type']]

        for i_byte, level_byte in enumerate(self.scope_data):
            i = jerry_ord(i_byte)
            level = jerry_ord(level_byte)
            if level == JERRY_DEBUGGER_SCOPE_WITH:
                table.append([str(i), 'with'])
            elif level == JERRY_DEBUGGER_SCOPE_GLOBAL:
                table.append([str(i), 'global'])
            elif level == JERRY_DEBUGGER_SCOPE_NON_CLOSURE:
                # Currently it is only marks the catch closure.
                table.append([str(i), 'catch'])
            elif level == JERRY_DEBUGGER_SCOPE_LOCAL:
                table.append([str(i), 'local'])
            elif 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 _parse_source(self, data):
        source_code = b""
        source_code_name = b""
        function_name = b""
        stack = [{
            "line": 1,
            "column": 1,
            "name": b"",
            "lines": [],
            "offsets": []
        }]
        new_function_list = {}
        result = b""

        while True:
            if data is None:
                return b"Error: connection lost during source code receiving"

            buffer_type = jerry_ord(data[0])
            buffer_size = len(data) - 1

            logging.debug("Parser buffer type: %d, message size: %d",
                          buffer_type, buffer_size)

            if buffer_type == JERRY_DEBUGGER_PARSE_ERROR:
                logging.error("Syntax error found")
                return b""

            elif buffer_type in [
                    JERRY_DEBUGGER_SOURCE_CODE, JERRY_DEBUGGER_SOURCE_CODE_END
            ]:
                source_code += data[1:]

            elif buffer_type in [
                    JERRY_DEBUGGER_SOURCE_CODE_NAME,
                    JERRY_DEBUGGER_SOURCE_CODE_NAME_END
            ]:
                source_code_name += data[1:]

            elif buffer_type in [
                    JERRY_DEBUGGER_FUNCTION_NAME,
                    JERRY_DEBUGGER_FUNCTION_NAME_END
            ]:
                function_name += data[1:]

            elif buffer_type == JERRY_DEBUGGER_PARSE_FUNCTION:
                logging.debug("Source name: %s, function name: %s",
                              source_code_name, function_name)

                position = struct.unpack(
                    self.byte_order + self.idx_format + self.idx_format,
                    data[1:1 + 4 + 4])

                stack.append({
                    "source": source_code,
                    "source_name": source_code_name,
                    "line": position[0],
                    "column": position[1],
                    "name": function_name,
                    "lines": [],
                    "offsets": []
                })
                function_name = b""

            elif buffer_type in [
                    JERRY_DEBUGGER_BREAKPOINT_LIST,
                    JERRY_DEBUGGER_BREAKPOINT_OFFSET_LIST
            ]:
                name = "lines"
                if buffer_type == JERRY_DEBUGGER_BREAKPOINT_OFFSET_LIST:
                    name = "offsets"

                logging.debug("Breakpoint %s received", name)

                buffer_pos = 1
                while buffer_size > 0:
                    line = struct.unpack(self.byte_order + self.idx_format,
                                         data[buffer_pos:buffer_pos + 4])
                    stack[-1][name].append(line[0])
                    buffer_pos += 4
                    buffer_size -= 4

            elif buffer_type == JERRY_DEBUGGER_BYTE_CODE_CP:
                byte_code_cp = struct.unpack(self.byte_order + self.cp_format,
                                             data[1:1 + self.cp_size])[0]

                logging.debug("Byte code cptr received: {0x%x}", byte_code_cp)

                func_desc = stack.pop()

                # We know the last item in the list is the general byte code.
                if not stack:
                    func_desc["source"] = source_code
                    func_desc["source_name"] = source_code_name

                function = JerryFunction(
                    stack, byte_code_cp, func_desc["source"],
                    func_desc["source_name"], func_desc["line"],
                    func_desc["column"], func_desc["name"], func_desc["lines"],
                    func_desc["offsets"])

                new_function_list[byte_code_cp] = function

                if not stack:
                    logging.debug("Parse completed.")
                    break

            elif buffer_type == JERRY_DEBUGGER_RELEASE_BYTE_CODE_CP:
                # Redefined functions are dropped during parsing.
                byte_code_cp = struct.unpack(self.byte_order + self.cp_format,
                                             data[1:1 + self.cp_size])[0]

                if byte_code_cp in new_function_list:
                    del new_function_list[byte_code_cp]
                    self._send_bytecode_cp(byte_code_cp)
                else:
                    self._release_function(data)

            elif buffer_type in [
                    JERRY_DEBUGGER_OUTPUT_RESULT,
                    JERRY_DEBUGGER_OUTPUT_RESULT_END
            ]:
                result += self._process_incoming_text(buffer_type, data)

            else:
                logging.error("Parser error!")
                raise Exception("Unexpected message")

            data = self.channel.get_message(True)

        # Copy the ready list to the global storage.
        self.function_list.update(new_function_list)

        for function in new_function_list.values():
            for line, breakpoint in function.lines.items():
                self.line_list.insert(line, breakpoint)

        # Try to set the pending breakpoints
        if self.pending_breakpoint_list:
            logging.debug("Pending breakpoints available")
            bp_list = self.pending_breakpoint_list

            for breakpoint_index, breakpoint in list(bp_list.items()):
                source_lines = 0
                for src in new_function_list.values():
                    if (src.source_name == breakpoint.source_name
                            or src.source_name.endswith(b"/" +
                                                        breakpoint.source_name)
                            or
                            src.source_name.endswith(b"\\" +
                                                     breakpoint.source_name)):
                        source_lines = len(src.source)
                        break

                if breakpoint.line:
                    if breakpoint.line <= source_lines:
                        command = breakpoint.source_name + b":%d" % (
                            breakpoint.line)
                        set_result = self._set_breakpoint(command, True)

                        if set_result:
                            result += set_result
                            del bp_list[breakpoint_index]
                elif breakpoint.function:
                    command = breakpoint.function
                    set_result = self._set_breakpoint(command, True)

                    if set_result:
                        result += set_result
                        del bp_list[breakpoint_index]

            if not bp_list:
                self._send_parser_config(0)
            return result

        logging.debug("No pending breakpoints")
        return result
    def process_messages(self):
        result = b""
        while True:
            data = self.channel.get_message(False)
            if not self.non_interactive:
                if sys.stdin in select.select([sys.stdin], [], [], 0)[0]:
                    sys.stdin.readline()
                    self.stop()

            if data == b'':
                action_type = DebuggerAction.PROMPT if self.prompt else DebuggerAction.WAIT
                return DebuggerAction(action_type, b"")

            if not data:  # Break the while loop if there is no more data.
                return DebuggerAction(DebuggerAction.END, b"")

            buffer_type = jerry_ord(data[0])
            buffer_size = len(data) - 1

            logging.debug("Main buffer type: %d, message size: %d",
                          buffer_type, buffer_size)

            if buffer_type in [
                    JERRY_DEBUGGER_PARSE_ERROR, JERRY_DEBUGGER_BYTE_CODE_CP,
                    JERRY_DEBUGGER_PARSE_FUNCTION,
                    JERRY_DEBUGGER_BREAKPOINT_LIST, JERRY_DEBUGGER_SOURCE_CODE,
                    JERRY_DEBUGGER_SOURCE_CODE_END,
                    JERRY_DEBUGGER_SOURCE_CODE_NAME,
                    JERRY_DEBUGGER_SOURCE_CODE_NAME_END,
                    JERRY_DEBUGGER_FUNCTION_NAME,
                    JERRY_DEBUGGER_FUNCTION_NAME_END
            ]:
                result = self._parse_source(data)
                if result:
                    return DebuggerAction(DebuggerAction.TEXT, result)

            elif buffer_type == JERRY_DEBUGGER_WAITING_AFTER_PARSE:
                self._exec_command(JERRY_DEBUGGER_PARSER_RESUME)

            elif buffer_type == JERRY_DEBUGGER_RELEASE_BYTE_CODE_CP:
                self._release_function(data)

            elif buffer_type in [
                    JERRY_DEBUGGER_BREAKPOINT_HIT, JERRY_DEBUGGER_EXCEPTION_HIT
            ]:
                breakpoint_data = struct.unpack(
                    self.byte_order + self.cp_format + self.idx_format,
                    data[1:])

                breakpoint = self._get_breakpoint(breakpoint_data)
                self.last_breakpoint_hit = breakpoint[0]

                if buffer_type == JERRY_DEBUGGER_EXCEPTION_HIT:
                    result += b"Exception throw detected (to disable automatic stop type exception 0)\n"
                    if self.exception_string:
                        result += b"Exception hint: %s\n" % (
                            self.exception_string)
                        self.exception_string = b""

                if breakpoint[1]:
                    breakpoint_info = b"at"
                else:
                    breakpoint_info = b"around"

                if breakpoint[0].active_index >= 0:
                    breakpoint_info += b" breakpoint:%s%d%s" % (
                        self.red, breakpoint[0].active_index, self.nocolor)

                result += b"Stopped %s %s\n" % (breakpoint_info, breakpoint[0])

                if self.display > 0:
                    result += self.print_source(self.display, self.src_offset)

                self.prompt = True
                return DebuggerAction(DebuggerAction.TEXT, result)

            elif buffer_type == JERRY_DEBUGGER_EXCEPTION_STR:
                self.exception_string += data[1:]

            elif buffer_type == JERRY_DEBUGGER_EXCEPTION_STR_END:
                self.exception_string += data[1:]

            elif buffer_type == JERRY_DEBUGGER_BACKTRACE_TOTAL:
                total = struct.unpack(self.byte_order + self.idx_format,
                                      data[1:])[0]
                result += b"Total number of frames: %d\n" % (total)
                return DebuggerAction(DebuggerAction.TEXT, result)

            elif buffer_type in [
                    JERRY_DEBUGGER_BACKTRACE, JERRY_DEBUGGER_BACKTRACE_END
            ]:
                frame_index = self.frame_index

                buffer_pos = 1
                while buffer_size > 0:
                    breakpoint_data = struct.unpack(
                        self.byte_order + self.cp_format + self.idx_format,
                        data[buffer_pos:buffer_pos + self.cp_size + 4])

                    breakpoint = self._get_breakpoint(breakpoint_data)

                    result += b"Frame %d: %s\n" % (frame_index, breakpoint[0])

                    frame_index += 1
                    buffer_pos += self.cp_size + 4
                    buffer_size -= self.cp_size + 4

                if buffer_type == JERRY_DEBUGGER_BACKTRACE_END:
                    self.prompt = True
                else:
                    self.frame_index = frame_index

                return DebuggerAction(DebuggerAction.TEXT, result)

            elif buffer_type in [
                    JERRY_DEBUGGER_EVAL_RESULT, JERRY_DEBUGGER_EVAL_RESULT_END,
                    JERRY_DEBUGGER_OUTPUT_RESULT,
                    JERRY_DEBUGGER_OUTPUT_RESULT_END
            ]:

                result = self._process_incoming_text(buffer_type, data)
                return DebuggerAction(DebuggerAction.TEXT, result)

            elif buffer_type == JERRY_DEBUGGER_MEMSTATS_RECEIVE:

                memory_stats = struct.unpack(
                    self.byte_order + self.idx_format * 5, data[1:1 + 4 * 5])

                result += b"Allocated bytes: %s\n" % memory_stats[0]
                result += b"Byte code bytes: %s\n" % memory_stats[1]
                result += b"String bytes: %s\n" % memory_stats[2]
                result += b"Object bytes: %s\n" % memory_stats[3]
                result += b"Property bytes: %s\n" % memory_stats[4]

                self.prompt = True
                return DebuggerAction(DebuggerAction.TEXT, result)

            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.scope_data = data[1:]

                if buffer_type == JERRY_DEBUGGER_SCOPE_CHAIN_END:
                    result = self._process_scope()
                    self.scope_data = b""

                    self.prompt = True

                return DebuggerAction(DebuggerAction.TEXT, result)

            elif buffer_type in [
                    JERRY_DEBUGGER_SCOPE_VARIABLES,
                    JERRY_DEBUGGER_SCOPE_VARIABLES_END
            ]:
                self.scope_vars += data[1:]

                if buffer_type == JERRY_DEBUGGER_SCOPE_VARIABLES_END:
                    result = self._process_scope_variables()
                    self.scope_vars = b""

                    self.prompt = True

                return DebuggerAction(DebuggerAction.TEXT, result)

            elif JERRY_DEBUGGER_CLOSE_CONNECTION:
                return DebuggerAction(DebuggerAction.END, b"")

            else:
                raise Exception("Unknown message")
    def __init__(self, channel):
        self.prompt = False
        self.function_list = {}
        self.source = b''
        self.source_name = b''
        self.exception_string = b''
        self.frame_index = 0
        self.scope_vars = b""
        self.scope_data = b""
        self.client_sources = []
        self.last_breakpoint_hit = None
        self.next_breakpoint_index = 0
        self.active_breakpoint_list = {}
        self.pending_breakpoint_list = {}
        self.line_list = Multimap()
        self.display = 0
        self.green = b''
        self.red = b''
        self.yellow = b''
        self.green_bg = b''
        self.yellow_bg = b''
        self.blue = b''
        self.nocolor = b''
        self.src_offset = 0
        self.src_offset_diff = 0
        self.non_interactive = False
        self.current_out = b""
        self.current_log = b""
        self.channel = channel

        config_size = 8
        # The server will send the configuration message after connection established
        # type [1]
        # configuration [1]
        # version [4]
        # max_message_size [1]
        # cpointer_size [1]
        result = self.channel.connect(config_size)

        if len(result) != config_size or jerry_ord(
                result[0]) != JERRY_DEBUGGER_CONFIGURATION:
            raise Exception("Unexpected configuration")

        self.little_endian = jerry_ord(
            result[1]) & JERRY_DEBUGGER_LITTLE_ENDIAN
        self.max_message_size = jerry_ord(result[6])
        self.cp_size = jerry_ord(result[7])

        if self.little_endian:
            self.byte_order = "<"
            logging.debug("Little-endian machine")
        else:
            self.byte_order = ">"
            logging.debug("Big-endian machine")

        if self.cp_size == 2:
            self.cp_format = "H"
        else:
            self.cp_format = "I"

        self.idx_format = "I"

        self.version = struct.unpack(self.byte_order + self.idx_format,
                                     result[2:6])[0]
        if self.version != JERRY_DEBUGGER_VERSION:
            raise Exception(
                "Incorrect debugger version from target: %d expected: %d" %
                (self.version, JERRY_DEBUGGER_VERSION))

        logging.debug("Compressed pointer size: %d", self.cp_size)
    def _process_incoming_text(self, buffer_type, data):
        message = b""
        msg_type = buffer_type
        while True:
            if buffer_type in [
                    JERRY_DEBUGGER_EVAL_RESULT_END,
                    JERRY_DEBUGGER_OUTPUT_RESULT_END
            ]:
                subtype = jerry_ord(data[-1])
                message += data[1:-1]
                break
            else:
                message += data[1:]

            data = self.channel.get_message(True)
            buffer_type = jerry_ord(data[0])
            # Checks if the next frame would be an invalid data frame.
            # If it is not the message type, or the end type of it, an exception is thrown.
            if buffer_type not in [msg_type, msg_type + 1]:
                raise Exception("Invalid data caught")

        # Subtypes of output
        if buffer_type == JERRY_DEBUGGER_OUTPUT_RESULT_END:
            if subtype == JERRY_DEBUGGER_OUTPUT_OK:
                log_type = b"%sout:%s " % (self.blue, self.nocolor)

                message = self.current_out + message
                lines = message.split(b"\n")
                self.current_out = lines.pop()

                return b"".join(
                    [b"%s%s\n" % (log_type, line) for line in lines])

            if subtype == JERRY_DEBUGGER_OUTPUT_DEBUG:
                log_type = b"%slog:%s " % (self.yellow, self.nocolor)

                message = self.current_log + message
                lines = message.split(b"\n")
                self.current_log = lines.pop()

                return b"".join(
                    [b"%s%s\n" % (log_type, line) for line in lines])

            if not message.endswith(b"\n"):
                message += b"\n"

            if subtype == JERRY_DEBUGGER_OUTPUT_WARNING:
                return b"%swarning: %s%s" % (self.yellow, self.nocolor,
                                             message)
            elif subtype == JERRY_DEBUGGER_OUTPUT_ERROR:
                return b"%serr: %s%s" % (self.red, self.nocolor, message)
            elif subtype == JERRY_DEBUGGER_OUTPUT_TRACE:
                return b"%strace: %s%s" % (self.blue, self.nocolor, message)

        # Subtypes of eval
        self.prompt = True

        if not message.endswith(b"\n"):
            message += b"\n"

        if subtype == JERRY_DEBUGGER_EVAL_ERROR:
            return b"Uncaught exception: %s" % (message)
        return message