code: private CompositeExpression parseSemVerExpression() {
          CompositeExpression expr;
          if (tokens.positiveLookahead(NOT)) {
              tokens.consume();
              consumeNextToken(LEFT_PAREN);
              expr = not(parseSemVerExpression());
              consumeNextToken(RIGHT_PAREN);
          } else if (tokens.positiveLookahead(LEFT_PAREN)) {
              consumeNextToken(LEFT_PAREN);
              expr = parseSemVerExpression();
              consumeNextToken(RIGHT_PAREN);
          } else {
              expr = parseRange();
          }
          return parseMoreExpressions(expr);
      }
docs: Parses the {@literal <semver-expr>} non-terminal.
  
  <pre>
  {@literal
  <semver-expr> ::= "(" <semver-expr> ")"
  | "!" "(" <semver-expr> ")"
  | <semver-expr> <more-expr>
  | <range>
  }
  </pre>
  
  @return the expression AST