All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
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);
}
}