def parse(self, precedence=0, required=True):
        self.reader.skip_whitespace()
        left_start = self.reader.offset
        left = self.parse_left(required)
        if left == None:
            return None
        self.add_node(left, left_start)

        while True:
            if self.hooks != None:
                parsed = self.hooks.infix_prehook(left)
                if parsed != None:
                    left = parsed
                    self.add_node(left, left_start)
                    continue

            op = self.parse_operator()
            if op == None or op.precedence <= precedence:
                break
            self.reader.expect_token(op.text)
            op_text = self.config.aliases.get(
                op.text) if op.text in self.config.aliases else op.text

            if op.is_binary:
                right = self.parse(op.precedence -
                                   1 if op.is_right_assoc else op.precedence)
                left = exprs.BinaryExpression(left, op_text, right)
            elif op.is_postfix:
                left = exprs.UnaryExpression(exprs.UNARY_TYPE.POSTFIX, op_text,
                                             left)
            elif op.text == "?":
                when_true = self.parse()
                self.reader.expect_token(":")
                when_false = self.parse(op.precedence - 1)
                left = exprs.ConditionalExpression(left, when_true, when_false)
            elif op.text == "(":
                args = self.parse_call_arguments()
                left = exprs.UnresolvedCallExpression(left, [], args)
            elif op.text == "[":
                element_expr = self.parse()
                self.reader.expect_token("]")
                left = exprs.ElementAccessExpression(left, element_expr)
            elif op.text in self.config.property_access_ops:
                prop = self.reader.expect_identifier(
                    "expected identifier as property name")
                left = exprs.PropertyAccessExpression(left, prop)
            else:
                self.reader.fail(
                    f'''parsing \'{op.text}\' is not yet implemented''')

            self.add_node(left, left_start)

        if isinstance(left, exprs.ParenthesizedExpression) and isinstance(
                left.expression, exprs.Identifier):
            expr = self.parse(0, False)
            if expr != None:
                return exprs.CastExpression(
                    astTypes.UnresolvedType(left.expression.text, []), expr)

        return left
    def parse_left(self, required=True):
        result = self.hooks.unary_prehook() if self.hooks != None else None
        if result != None:
            return result

        unary = self.reader.read_any_of(self.config.unary)
        if unary != None:
            right = self.parse(self.prefix_precedence)
            return exprs.UnaryExpression(exprs.UNARY_TYPE.PREFIX, unary, right)

        id = self.reader.read_identifier()
        if id != None:
            return exprs.Identifier(id)

        num = self.reader.read_number()
        if num != None:
            return exprs.NumericLiteral(num)

        str = self.reader.read_string()
        if str != None:
            return exprs.StringLiteral(str)

        if self.reader.read_token("("):
            expr = self.parse()
            self.reader.expect_token(")")
            return exprs.ParenthesizedExpression(expr)

        if required:
            self.reader.fail(
                f'''unknown (literal / unary) token in expression''')

        return None