All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jparsec.examples.java.parser.ExpressionParser Maven / Gradle / Ivy

The newest version!
/*****************************************************************************
 * Copyright (C) jparsec.org                                                *
 * ------------------------------------------------------------------------- *
 * Licensed under the Apache License, Version 2.0 (the "License");           *
 * you may not use this file except in compliance with the License.          *
 * You may obtain a copy of the License at                                   *
 *                                                                           *
 * http://www.apache.org/licenses/LICENSE-2.0                                *
 *                                                                           *
 * Unless required by applicable law or agreed to in writing, software       *
 * distributed under the License is distributed on an "AS IS" BASIS,         *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  *
 * See the License for the specific language governing permissions and       *
 * limitations under the License.                                            *
 *****************************************************************************/
package org.jparsec.examples.java.parser;

import static org.jparsec.examples.java.parser.TerminalParser.phrase;
import static org.jparsec.examples.java.parser.TerminalParser.term;

import java.util.Collections;
import java.util.List;
import java.util.function.BinaryOperator;
import java.util.function.UnaryOperator;

import org.jparsec.OperatorTable;
import org.jparsec.Parser;
import org.jparsec.Parsers;
import org.jparsec.Terminals;
import org.jparsec.examples.java.ast.declaration.DefBody;
import org.jparsec.examples.java.ast.expression.ArrayInitializer;
import org.jparsec.examples.java.ast.expression.ArraySubscriptExpression;
import org.jparsec.examples.java.ast.expression.BinaryExpression;
import org.jparsec.examples.java.ast.expression.BooleanLiteral;
import org.jparsec.examples.java.ast.expression.CastExpression;
import org.jparsec.examples.java.ast.expression.CharLiteral;
import org.jparsec.examples.java.ast.expression.ClassLiteral;
import org.jparsec.examples.java.ast.expression.ConditionalExpression;
import org.jparsec.examples.java.ast.expression.ConstructorReference;
import org.jparsec.examples.java.ast.expression.DecimalPointNumberLiteral;
import org.jparsec.examples.java.ast.expression.Expression;
import org.jparsec.examples.java.ast.expression.Identifier;
import org.jparsec.examples.java.ast.expression.InstanceOfExpression;
import org.jparsec.examples.java.ast.expression.IntegerLiteral;
import org.jparsec.examples.java.ast.expression.LambdaExpression;
import org.jparsec.examples.java.ast.expression.MethodCallExpression;
import org.jparsec.examples.java.ast.expression.MethodReference;
import org.jparsec.examples.java.ast.expression.NewArrayExpression;
import org.jparsec.examples.java.ast.expression.NewExpression;
import org.jparsec.examples.java.ast.expression.NullExpression;
import org.jparsec.examples.java.ast.expression.Operator;
import org.jparsec.examples.java.ast.expression.PostfixUnaryExpression;
import org.jparsec.examples.java.ast.expression.PrefixUnaryExpression;
import org.jparsec.examples.java.ast.expression.QualifiedExpression;
import org.jparsec.examples.java.ast.expression.ScientificNumberLiteral;
import org.jparsec.examples.java.ast.expression.StringLiteral;
import org.jparsec.examples.java.ast.expression.SuperExpression;
import org.jparsec.examples.java.ast.expression.ThisExpression;
import org.jparsec.examples.java.ast.statement.ExpressionStatement;
import org.jparsec.examples.java.ast.statement.Statement;

/**
 * Parses java expression.
 * 
 * @author Ben Yu
 */
public final class ExpressionParser {

  static Parser> conditional(Parser consequence) {
    // "? consequence :" can be think of as a right associative infix operator.
    // consequence can be the lazy expression, which is everything
    return consequence.between(term("?"), term(":"))
        .map(cons -> (cond, alt) -> new ConditionalExpression(cond, cons, alt));
  }
  
  static final Parser NULL = term("null").retn(NullExpression.instance);
  
  /**
   * {@code (foo)} can be a parenthesized expression, or the prefix of a cast expression,
   * depending on whether there's an expression following.
   */
  static final Parser castOrExpression(Parser expr) {
    Parser explicitCast =
        Parsers.sequence(paren(TypeLiteralParser.TYPE_LITERAL), expr, CastExpression::new);
    return explicitCast.or(paren(expr));
  }
  
  static final Parser> INSTANCE_OF =
      term("instanceof").next(TypeLiteralParser.TYPE_LITERAL)
          .map(t -> e -> new InstanceOfExpression(e, t));
  
  static final Parser> QUALIFIED_EXPR =
      term(".").next(Terminals.Identifier.PARSER).map(n -> e -> new QualifiedExpression(e, n));

  static Parser> subscript(Parser expr) {
    return expr.between(term("["), term("]")).map(i -> a -> new ArraySubscriptExpression(a, i));
  }

  static final Parser> METHOD_REFERENCE = Parsers.sequence(
      term("::"),
      TypeLiteralParser.optionalTypeArgs(TypeLiteralParser.TYPE_LITERAL),
      Terminals.Identifier.PARSER,
      (__, typeParams, name) -> qualifier -> new MethodReference(qualifier, typeParams, name));

  static final Parser> CONSTRUCTOR_REFERENCE =
      phrase(":: new").retn(ConstructorReference::new);
  
  static Parser> qualifiedMethodCall(Parser arg) {
    return Parsers.sequence(
        term(".").next(TypeLiteralParser.optionalTypeArgs(TypeLiteralParser.TYPE_LITERAL)),
        Terminals.Identifier.PARSER,
        argumentList(arg),
        (t, m, a) -> q -> new MethodCallExpression(q, t, m, a));
  }
  
  static Parser> qualifiedNew(Parser arg, Parser body) {
    return Parsers.sequence(
        phrase(". new").next(TypeLiteralParser.ELEMENT_TYPE_LITERAL),
        argumentList(arg),
        body.optional(),
        (t, a, b) -> q -> new NewExpression(q, t, a, b));
  }
  
  static Parser simpleMethodCall(Parser arg) {
    return Parsers.sequence(
        Terminals.Identifier.PARSER, argumentList(arg),
        (name, args) ->
            new MethodCallExpression(null, TypeLiteralParser.EMPTY_TYPE_ARGUMENT_LIST, name, args));
  }
  
  // new a class instance
  static Parser simpleNewExpression(Parser arg, Parser body) {
    return Parsers.sequence(
        term("new").next(TypeLiteralParser.ELEMENT_TYPE_LITERAL),
        argumentList(arg),
        body.optional(),
        (type, args, defBody) -> new NewExpression(null, type, args, defBody));
  }
  
  // new int[5]
  static Parser newArrayWithExplicitLength(Parser expr) {
    return Parsers.sequence(term("new").next(TypeLiteralParser.TYPE_LITERAL),
        expr.between(term("["), term("]")),
        Parsers.between(term("{"), expr.sepBy(term(",")), term("}")).optional(),
        NewArrayExpression::new);
  }
  
  // new int[] {...}
  static Parser newArrayWithoutExplicitLength(Parser expr) {
    return Parsers.sequence(
        term("new").next(TypeLiteralParser.ARRAY_TYPE_LITERAL),
        Parsers.between(term("{"), expr.sepBy(term(",")), term("}")),
        (type, values) -> new NewArrayExpression(type.elementType, null, values));
  }
  
  static  Parser paren(Parser parser) {
    return parser.between(term("("), term(")"));
  }

  private static Parser> argumentList(Parser arg) {
    return paren(arg.sepBy(term(",")));
  }
  
  static final Parser THIS = Terminals.Identifier.PARSER.followedBy(term(".")).many()
      .followedBy(term("this"))
      .map(ThisExpression::new);
  
  static final Parser SUPER = term("super").retn(new SuperExpression());
  
  static final Parser IDENTIFIER = Terminals.Identifier.PARSER.map(Identifier::new);
  
  static final Parser CLASS_LITERAL = TypeLiteralParser.TYPE_LITERAL
      .followedBy(phrase(". class"))
      .map(ClassLiteral::new);
  
  static final Parser INTEGER_LITERAL =
      Parsers.tokenType(IntegerLiteral.class, "integer literal");
  
  static final Parser DECIMAL_LITERAL =
      Parsers.tokenType(DecimalPointNumberLiteral.class, "decimal number literal");
  
  static final Parser STRING_LITERAL = Terminals.StringLiteral.PARSER.map(StringLiteral::new);
  
  static final Parser CHAR_LITERAL = Terminals.CharLiteral.PARSER.map(CharLiteral::new);
  
  static final Parser BOOLEAN_LITERAL = Parsers.or(
      term("true").retn(new BooleanLiteral(true)),
      term("false").retn(new BooleanLiteral(false)));
  
  static final Parser SCIENTIFIC_LITERAL =
      Parsers.tokenType(ScientificNumberLiteral.class, "scientific number literal");

  @SuppressWarnings("unchecked")
  static final Parser ATOM = Parsers.or(
        NULL, THIS, SUPER, CLASS_LITERAL, BOOLEAN_LITERAL, CHAR_LITERAL, STRING_LITERAL,
        SCIENTIFIC_LITERAL, INTEGER_LITERAL, DECIMAL_LITERAL, IDENTIFIER);

  static Parser lambdaExpression(
      Parser expression, Parser stmt) {
    Parser typedParam = Parsers.sequence(
        TypeLiteralParser.TYPE_LITERAL, Terminals.Identifier.PARSER,
        LambdaExpression.Parameter::new);
    Parser simpleParam = Terminals.Identifier.PARSER.map(LambdaExpression.Parameter::new);
    Parser lambdaParam = typedParam.or(simpleParam);
    Parser> params =
        paren(lambdaParam.sepBy(term(","))).or(lambdaParam.map(Collections::singletonList));
    Parser body = StatementParser.blockStatement(stmt).cast()
        .or(expression.map(ExpressionStatement::new));
    return Parsers.sequence(params, term("->").next(body), LambdaExpression::new);
  }
 
  static Parser expression(
      Parser atom, Parser classBody, Parser statement) {
    // atom is literal, name, "a.b.c.this", "super".
    Parser.Reference ref = Parser.newReference();
    Parser lazy = ref.lazy();
    atom = Parsers.or(castOrExpression(lazy), simpleNewExpression(lazy, classBody),
                newArrayWithExplicitLength(lazy), newArrayWithoutExplicitLength(lazy),
                simpleMethodCall(lazy), lambdaExpression(lazy, statement),
                atom);
    Parser parser = new OperatorTable()
        .postfix(subscript(lazy), 200)
        .postfix(qualifiedMethodCall(lazy), 200)
        .postfix(qualifiedNew(lazy, classBody), 200)
        .postfix(METHOD_REFERENCE,  200)
        .postfix(CONSTRUCTOR_REFERENCE, 20)
        .postfix(QUALIFIED_EXPR, 200)
        .postfix(postfix(Operator.POST_INC), 200)
        .postfix(postfix(Operator.POST_DEC), 200)
        .prefix(prefix(Operator.INC), 190)
        .prefix(prefix(Operator.DEC), 190)
        .prefix(prefix(Operator.POSITIVE), 190)
        .prefix(prefix(Operator.NEGATIVE), 190)
        .prefix(prefix(Operator.INC), 190)
        .prefix(prefix(Operator.DEC), 190)
        .prefix(prefix(Operator.NOT), 190)
        .prefix(prefix(Operator.BITWISE_NOT), 190)
        .infixl(binary(Operator.MUL), 100)
        .infixl(binary(Operator.DIV), 100)
        .infixl(binary(Operator.MOD), 100)
        .infixl(binary(Operator.DIV), 100)
        .infixl(binary(Operator.PLUS), 90)
        .infixl(binary(Operator.MINUS), 90)
        .infixl(binary(Operator.LSHIFT), 80)
        .infixl(binary(Operator.RSHIFT), 80)
        .infixl(binary(Operator.UNSIGNED_RSHIFT), 80)
        .infixl(binary(Operator.LE), 70)
        .infixl(binary(Operator.GE), 70)
        .infixl(binary(Operator.LT), 70)
        .infixl(binary(Operator.GT), 70)
        .postfix(INSTANCE_OF, 65)
        .infixl(binary(Operator.EQ), 60)
        .infixl(binary(Operator.NE), 60)
        .infixl(binary(Operator.BITWISE_AND), 50)
        .infixl(binary(Operator.BITWISE_XOR), 40)
        .infixl(binary(Operator.BITWISE_OR), 30)
        .infixl(binary(Operator.AND), 20)
        .infixl(binary(Operator.OR), 10)
        .infixr(conditional(lazy), 5)
        .infixr(binary(Operator.ASSIGNMENT), 0)
        .infixr(binary(Operator.APLUS), 0)
        .infixr(binary(Operator.AMINUS), 0)
        .infixr(binary(Operator.AMUL), 0)
        .infixr(binary(Operator.ADIV), 0)
        .infixr(binary(Operator.AMOD), 0)
        .infixr(binary(Operator.AAND), 0)
        .infixr(binary(Operator.AOR), 0)
        .infixr(binary(Operator.AXOR), 0)
        .infixr(binary(Operator.ALSHIFT), 0)
        .infixr(binary(Operator.ARSHIFT), 0)
        .infixr(binary(Operator.UNSIGNED_ARSHIFT), 0)
        .build(atom);
    ref.set(parser);
    return parser;
  }
  
  public static Parser expression(
      Parser classBody, Parser statement) {
    return expression(ATOM, classBody, statement);
  }
  
  public static Parser arrayInitializer(Parser expr) {
    return expr.sepEndBy(term(",")).between(term("{"), term("}")).map(ArrayInitializer::new);
  }

  static Parser arrayInitializerOrRegularExpression(Parser expr) {
    return arrayInitializer(expr).or(expr);
  }
  
  private static Parser> binary(Operator op) {
    return term(op.toString()).retn((l, r) -> new BinaryExpression(l, op, r));
  }
  
  private static Parser> prefix(Operator op) {
    return term(op.toString()).retn(e -> new PrefixUnaryExpression(op, e));
  }
  
  private static Parser> postfix(Operator op) {
    return term(op.toString()).retn(e -> new PostfixUnaryExpression(e, op));
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy