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

manifold.internal.javac.ManJavacParser_ Maven / Gradle / Ivy

/*
 * Copyright (c) 2019 - Manifold Systems LLC
 *
 * 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 com.sun.tools.javac.parser;

import com.sun.tools.javac.parser.Tokens.Token;
import com.sun.tools.javac.parser.Tokens.TokenKind;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCExpression;
import com.sun.tools.javac.tree.TreeInfo;
import com.sun.tools.javac.util.Assert;
import com.sun.tools.javac.util.Names;
import java.lang.reflect.Field;


import static com.sun.tools.javac.parser.Tokens.TokenKind.*;

/**
 * !!! IMPORTANT !!!
 * 

* If necessary, update this file if Java low-level expr grammar changes: * Create a directory path mirroring the package "com.sun.tools.javac.parser", copy this there and remove underscore. * Make necessary changes then compile the renamed file by itself, then copy/rename the ManJavaParser.class to *.clazz * (note the zz) in the resource directory at manifold/internal/javac (overwrite the existing file there). Finally, * rename the file back to *.java_ and copy it back to the manifold.internal.javac package, overwriting the existing * file. lol. *

*

* Subclass java parser to implement the "empty" operator to support "Binding" expressions. See {@code term2()}, * {@code term2Rest()}, and other overrides for details. */ public class ManJavacParser extends JavacParser { private static final int infixPrecedenceLevels = 10; private static Field field_mode = null; private static Field field_endPosTable = null; private static Field field_parseModuleInfo = null; static { try { field_mode = JavacParser.class.getDeclaredField( "mode" ); field_mode.setAccessible( true ); field_endPosTable = JavacParser.class.getDeclaredField( "endPosTable" ); field_endPosTable.setAccessible( true ); // Java 9+ //noinspection JavaReflectionMemberAccess field_parseModuleInfo = JavacParser.class.getDeclaredField( "parseModuleInfo" ); field_parseModuleInfo.setAccessible( true ); } catch( NoSuchFieldException ignore ) { } } private final Names _names; private final AbstractEndPosTable _endPosTable; public ManJavacParser( ParserFactory fac, Lexer S, boolean keepDocComments, boolean keepLineMap, boolean keepEndPositions, boolean parseModuleInfo ) { super( fac, S, keepDocComments, keepLineMap, keepEndPositions ); _names = fac.names; try { _endPosTable = (AbstractEndPosTable)field_endPosTable.get( this ); } catch( IllegalAccessException e ) { throw new RuntimeException( e ); } if( parseModuleInfo && field_parseModuleInfo != null ) { try { field_parseModuleInfo.set( this, true ); } catch( IllegalAccessException e ) { throw new RuntimeException( e ); } } } public void nextToken() { if( S == null ) return; S.nextToken(); token = S.token(); } /** Expression2 = Expression3 [Expression2Rest] * Type2 = Type3 * TypeNoParams2 = TypeNoParams3 * *

* Manifold: Allow for a binary expression to have an "empty" operator e.g., {@code foo bar}, where the types * the operands can declare a "reaction", such an expression is called a binding expression. The "empty" operator's * precedence is between '+' and '*', thus a binding expression can only have other binding expressions, * multiplication expressions, and a subset of unary expressions as children (see {@code isBinderRhs() and * {@code term2Rest()}. */ JCExpression term2() { JCExpression t = term3(); if ((get_mode() & EXPR) != 0 && prec(token.kind) >= TreeInfo.orPrec || get_mode() == EXPR && isBinderRhs()) { set_mode( EXPR ); return term2Rest(t, TreeInfo.orPrec); } else { return t; } } /* Expression2Rest = {infixop Expression3} * | Expression3 instanceof Type * infixop = "||" * | "&&" * | "|" * | "^" * | "&" * | "==" | "!=" * | "<" | ">" | "<=" | ">=" * | "<<" | ">>" | ">>>" * | "+" | "-" * | "*" | "/" | "%" *

* Manifold: Handle binder expressions e.g., {@code ident unit}, involving the "empty" operator. See * {@code term2()}. */ JCExpression term2Rest(JCExpression t, int minprec) { JCExpression[] odStack = newOdStack(); Token[] opStack = newOpStack(); // optimization, was odStack = new Tree[...]; opStack = new Tree[...]; int top = 0; odStack[0] = t; Token topOp = Tokens.DUMMY; boolean binder = isBinderRhs(); while (binder || prec(token.kind) >= minprec) { opStack[top] = topOp; top++; if( binder ) { topOp = null; } else { topOp = token; nextToken(); } odStack[top] = (topOp != null && topOp.kind == INSTANCEOF) ? parseType() : binder ? parseBinderOperand() : term3(); binder = isBinderRhs(); while (top > 0 && (isSameOrHigher(topOp == null ? null : topOp.kind, binder ? null : token.kind))) { odStack[top-1] = makeOp(topOp == null ? odStack[top].pos : topOp.pos, topOp == null ? null : topOp.kind, odStack[top-1], odStack[top]); top--; topOp = opStack[top]; } } Assert.check( top == 0); t = odStack[0]; if (t.hasTag(JCTree.Tag.PLUS)) { t = foldStrings(t); } odStackSupply.add(odStack); opStackSupply.add(opStack); return t; } private JCExpression parseBinderOperand() { if( token.kind == LPAREN ) { return term3(); } if( token.kind == INTLITERAL || token.kind == LONGLITERAL || token.kind == FLOATLITERAL || token.kind == DOUBLELITERAL || token.kind == CHARLITERAL || token.kind == STRINGLITERAL ) { set_mode( EXPR ); JCExpression t = literal( _names.empty ); return toP( t ); } if( token.kind == IDENTIFIER ) { JCExpression t = toP( F.at( token.pos ).Ident( ident() ) ); return toP( t ); } return illegal(); } private boolean isSameOrHigher( TokenKind kind, TokenKind other ) { if( kind == null ) { return other == null || prec(other) < TreeInfo.mulPrec; } else { return other == null ? prec(kind) >= TreeInfo.mulPrec : prec(kind) >= prec(other); } } /** Construct a binary or type test node. */ private JCExpression makeOp(int pos, TokenKind topOp, JCExpression od1, JCExpression od2) { if (topOp == INSTANCEOF) { return F.at(pos).TypeTest(od1, od2); } else { //Manifold: use APPLY for binding op. //It is later changed to MUL after ManAttr processing so the expr will pass safely through javac until it is //transformed to a pre/postBind() call. JCTree.Tag optag = topOp == null ? JCTree.Tag.APPLY : optag( topOp ); return F.at( pos ).Binary( optag, od1, od2 ); } } private boolean isBinderRhs() { return token.kind == IDENTIFIER || token.kind == INTLITERAL || token.kind == LONGLITERAL || token.kind == FLOATLITERAL || token.kind == DOUBLELITERAL || token.kind == STRINGLITERAL || token.kind == LPAREN; } /** * Manifold: * Override to account for case: {@code (ident unit)}. This otherwise conflicts with the parser's handling of parens * for lambda parsing eg. {@code (int index) -> ...}. Hence the lookahead here for the '->' to distinguish from a * binding expression. */ @Override ParensResult analyzeParens() { ParensResult parensResult = super.analyzeParens(); if( parensResult == ParensResult.EXPLICIT_LAMBDA || parensResult == ParensResult.IMPLICIT_LAMBDA ) { int lookahead = 0; while( !peekToken( lookahead, RPAREN ) ) { lookahead++; } if( !peekToken( ++lookahead, ARROW ) ) { parensResult = ParensResult.PARENS; } } return parensResult; } private int get_mode() { try { return (int)field_mode.get( this ); } catch( IllegalAccessException e ) { throw new RuntimeException( e ); } } private void set_mode( int mode ) { try { field_mode.set( this, mode ); } catch( IllegalAccessException e ) { throw new RuntimeException( e ); } } protected T toP( T t ) { return _endPosTable.toP(t); } private JCExpression[] newOdStack() { if (odStackSupply.isEmpty()) return new JCExpression[infixPrecedenceLevels + 1]; return odStackSupply.remove(odStackSupply.size() - 1); } private Token[] newOpStack() { if (opStackSupply.isEmpty()) return new Token[infixPrecedenceLevels + 1]; return opStackSupply.remove(opStackSupply.size() - 1); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy