@Override
    protected Expression unary() throws ParsingException {
        Expression result;
        if (tokens[position].equals(Lexeme.NOT.s)) {
            position++;
            result = new Not(unary());
            return result;
        }
        if (tokens[position].equals(Lexeme.FOR_ALL.s)) {
            position++;
            Term var = null;
            if (isLowercaseVariable(tokens[position])) {
                var = new Term(tokens[position]);
                position++;
            } else {
                throw new ParsingException("something wrong, you tried to parse " + tokens[position] + " as variable");
            }
            result = new ForAll(var, unary());
            return result;
        }
        if (tokens[position].equals(Lexeme.EXISTS.s)) {
            position++;
            Term var;
            if (isLowercaseVariable(tokens[position])) {
                var = term();
            } else {
                throw new ParsingException("something wrong, you tried to parse " + tokens[position] + " as variable");
            }
            result = new Exists(var, unary());
            return result;
        }
        if (tokens[position].equals(Lexeme.LEFT_P.s)) {
            int backupPos = position;
            try {
                position++;

                result = expr();
                if (!tokens[position].equals(Lexeme.RIGHT_P.s)) {
                    StringBuilder sb = new StringBuilder();
                    for (String s : tokens) {
                        sb.append(s);
                    }
                    throw new ParsingException("you have unclosed brackets in expression " + sb.toString());
                } else {
                    position++;
                }
                return result;
            } catch (ParsingException e) {
                position = backupPos;
                return predicate();
            }
        }
        return predicate();
    }