def __parse(token_stream, first_token):
    class KVP:
        def __init__(self, key):
            self.key = key
            self.value = None
            self.set = False

        def __str__(self):
            if self.set:
                return "{}: {}".format(self.key, self.value)
            else:
                return "{}: <NULL>".format(self.key)

    stack = []
    token_type, token = first_token
    if token_type == TOKEN_TYPE.OPERATOR:
        if token == "{":
            stack.append({})
        elif token == "[":
            stack.append([])
        else:
            raise ValueError("Expected object or array.  Got '{}'".format(token))
    else:
        raise ValueError("Expected object or array.  Got '{}'".format(token))

    last_type, last_token = token_type, token
    try:
        token_type, token = next(token_stream)
    except StopIteration as e:
        raise ValueError("Too many opening braces") from e
    try:
        while True:
            if isinstance(stack[-1], list):
                if last_type == TOKEN_TYPE.OPERATOR:
                    if last_token == "[":
                        if token_type == TOKEN_TYPE.OPERATOR:
                            if token == "{":
                                stack.append({})
                            elif token == "[":
                                stack.append([])
                            elif token != "]":
                                raise ValueError("Array must either be empty or contain a value.  Got '{}'".
                                                 format(token))
                        else:
                            stack.append(token)
                    elif last_token == ",":
                        if token_type == TOKEN_TYPE.OPERATOR:
                            if token == "{":
                                stack.append({})
                            elif token == "[":
                                stack.append([])
                            else:
                                raise ValueError("Array value expected.  Got '{}'".format(token))
                        else:
                            stack.append(token)
                    elif last_token == "]":
                        value = stack.pop()
                        if len(stack) == 0:
                            return value, token_type, token
                        if isinstance(stack[-1], list):
                            stack[-1].append(value)
                        elif isinstance(stack[-1], dict):
                            stack[-1][value.key] = value.value
                        elif isinstance(stack[-1], KVP):
                            stack[-1].value = value
                            stack[-1].set = True
                            value = stack.pop()
                            if len(stack) == 0:
                                return value, token_type, token
                            if isinstance(stack[-1], list):
                                stack[-1].append(value)
                            elif isinstance(stack[-1], dict):
                                stack[-1][value.key] = value.value
                            else:
                                raise ValueError("Array items must be followed by a comma or closing bracket.  "
                                                 "Got '{}'".format(value))
                        else:
                            raise ValueError("Array items must be followed by a comma or closing bracket.  "
                                             "Got '{}'".format(value))
                    elif last_token == "}":
                        raise ValueError("Array closed with a '}'")
                    else:
                        raise ValueError("Array should not contain ':'")
                else:
                    raise ValueError("Unknown Error")
            elif isinstance(stack[-1], dict):
                if last_type == TOKEN_TYPE.OPERATOR:
                    if last_token == "{":
                        if token_type == TOKEN_TYPE.OPERATOR:
                            if token == "{":
                                stack.append({})
                            elif token == "[":
                                stack.append([])
                            elif token != "}":
                                raise ValueError("Object must either be empty or contain key value pairs."
                                                 "  Got '{}'".format(token))
                        elif token_type == TOKEN_TYPE.STRING:
                            stack.append(KVP(token))
                        else:
                            raise ValueError("Object keys must be strings.  Got '{}'".format(token))
                    elif last_token == ",":
                        if token_type == TOKEN_TYPE.OPERATOR:
                            if token == "{":
                                stack.append({})
                            elif token == "[":
                                stack.append([])
                            else:
                                raise ValueError("Object key expected.  Got '{}'".format(token))
                        elif token_type == TOKEN_TYPE.STRING:
                            stack.append(KVP(token))
                        else:
                            raise ValueError("Object keys must be strings.  Got '{}'".format(token))
                    elif last_token == "}":
                        value = stack.pop()
                        if len(stack) == 0:
                            return value, token_type, token
                        if isinstance(stack[-1], list):
                            stack[-1].append(value)
                        elif isinstance(stack[-1], dict):
                            stack[-1][value.key] = value.value
                        elif isinstance(stack[-1], KVP):
                            stack[-1].value = value
                            stack[-1].set = True
                            value = stack.pop()
                            if len(stack) == 0:
                                return value, token_type, token
                            if isinstance(stack[-1], list):
                                stack[-1].append(value)
                            elif isinstance(stack[-1], dict):
                                stack[-1][value.key] = value.value
                            else:
                                raise ValueError("Object key value pairs must be followed by a comma or "
                                                 "closing bracket.  Got '{}'".format(value))
                    elif last_token == "]":
                        raise ValueError("Object closed with a ']'")
                    else:
                        raise ValueError("Object key value pairs should be separated by comma, not ':'")
            elif isinstance(stack[-1], KVP):
                if stack[-1].set:
                    if token_type == TOKEN_TYPE.OPERATOR:
                        if token != "}" and token != ",":
                            raise ValueError("Object key value pairs should be followed by ',' or '}'.  Got '"
                                             + token + "'")
                        value = stack.pop()
                        if len(stack) == 0:
                            return value, token_type, token
                        if isinstance(stack[-1], list):
                            stack[-1].append(value)
                        elif isinstance(stack[-1], dict):
                            stack[-1][value.key] = value.value
                        else:
                            raise ValueError("Object key value pairs must be followed by a comma or closing bracket.  "
                                             "Got '{}'".format(value))
                        if token == "}" and len(stack) == 1:
                            return stack[0], None, None
                    else:
                        raise ValueError("Object key value pairs should be followed by ',' or '}'.  Got '"
                                         + token + "'")
                else:
                    if token_type == TOKEN_TYPE.OPERATOR and token == ":" and last_type == TOKEN_TYPE.STRING:
                        pass
                    elif last_type == TOKEN_TYPE.OPERATOR and last_token == ":":
                        if token_type == TOKEN_TYPE.OPERATOR:
                            if token == "{":
                                stack.append({})
                            elif token == "[":
                                stack.append([])
                            else:
                                raise ValueError("Object property value expected.  Got '{}'".format(token))
                        else:
                            stack[-1].value = token
                            stack[-1].set = True
                    else:
                        raise ValueError("Object keys must be separated from values by a single ':'.  "
                                         "Got '{}'".format(token))
            else:
                value = stack.pop()
                if isinstance(stack[-1], list):
                    stack[-1].append(value)
                elif isinstance(stack[-1], dict):
                    stack[-1][value.key] = value.value
                else:
                    raise ValueError("Array items must be followed by a comma or closing bracket.  "
                                     "Got '{}'".format(value))

            last_type, last_token = token_type, token
            token_type, token = next(token_stream)
    except StopIteration as e:
        if len(stack) == 1:
            return stack[0], None, None
        else:
            raise ValueError("JSON Object not properly closed") from e