blob: 54e17d7b8ab4e3d086600d8b5cf5b927449b7256 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 de.bokelberg.flex.parser;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.adobe.ac.pmd.files.impl.FileUtils;
import com.adobe.ac.pmd.parser.IAS3Parser;
import com.adobe.ac.pmd.parser.IParserNode;
import com.adobe.ac.pmd.parser.KeyWords;
import com.adobe.ac.pmd.parser.NodeKind;
import com.adobe.ac.pmd.parser.Operators;
import com.adobe.ac.pmd.parser.exceptions.NullTokenException;
import com.adobe.ac.pmd.parser.exceptions.TokenException;
import com.adobe.ac.pmd.parser.exceptions.UnExpectedTokenException;
import com.adobe.ac.pmd.parser.exceptions.UnExpectedTokenException.Position;
import de.bokelberg.flex.parser.AS3Scanner.Token;
public class AS3Parser implements IAS3Parser
{
/**
*
*/
public static final String ASDOC_COMMENT = "/**";
/**
*
*/
public static final String MULTIPLE_LINES_COMMENT = "/*";
/**
*
*/
public static final String NEW_LINE = "\n";
/**
*
*/
public static final String SINGLE_LINE_COMMENT = "//";
private static final String VECTOR = "Vector";
private Node currentAsDoc;
private Node currentFunctionNode;
private Node currentMultiLineComment;
private String fileName;
private boolean isInFor;
private AS3Scanner scn;
private Token tok;
/**
*
*/
public AS3Parser()
{
this.scn = new AS3Scanner();
isInFor = false;
}
/*
* (non-Javadoc)
* @see de.bokelberg.flex.parser.IAS3Parser#buildAst(java.lang.String)
*/
public final IParserNode buildAst( final String filePath ) throws IOException,
TokenException
{
return parseLines( filePath,
FileUtils.readLines( new File( filePath ) ) );
}
/*
* (non-Javadoc)
* @see com.adobe.ac.pmd.parser.IAS3Parser#buildAst(java.lang.String,
* java.lang.String[])
*/
public final IParserNode buildAst( final String filePath,
final String[] scriptBlockLines ) throws TokenException
{
return parseLines( filePath,
scriptBlockLines );
}
/**
* @return
*/
final AS3Scanner getScn()
{
return scn;
}
final void nextToken() throws TokenException
{
nextToken( false );
}
/**
* Get the next token Skip comments and newlines for now In the end we want
* to keep them though.
*
* @throws TokenException
*/
final void nextToken( final boolean ignoreDocumentation ) throws TokenException
{
do
{
if ( ignoreDocumentation )
{
nextTokenIgnoringDocumentation();
}
else
{
nextTokenAllowNewLine();
}
}
while ( tok.getText().equals( NEW_LINE ) );
}
/**
* tok is first content token
*
* @throws TokenException
*/
final Node parseClassContent() throws TokenException
{
final Node result = Node.create( NodeKind.CONTENT,
tok.getLine(),
tok.getColumn() );
final List< Token > modifiers = new ArrayList< Token >();
final List< Node > meta = new ArrayList< Node >();
while ( !tokIs( Operators.RIGHT_CURLY_BRACKET ) )
{
if ( tokIs( Operators.LEFT_CURLY_BRACKET ) )
{
result.addChild( parseBlock() );
}
if ( tokIs( Operators.LEFT_SQUARE_BRACKET ) )
{
meta.add( parseMetaData() );
}
else if ( tokIs( KeyWords.VAR ) )
{
parseClassField( result,
modifiers,
meta );
}
else if ( tokIs( KeyWords.CONST ) )
{
parseClassConstant( result,
modifiers,
meta );
}
else if ( tokIs( KeyWords.IMPORT ) )
{
result.addChild( parseImport() );
}
else if ( tokIs( KeyWords.FUNCTION ) )
{
parseClassFunctions( result,
modifiers,
meta );
}
else
{
tryToParseCommentNode( result,
modifiers );
}
}
return result;
}
/**
* tok is empty, since nextToken has not been called before
*
* @throws UnExpectedTokenException
*/
final Node parseCompilationUnit() throws TokenException
{
final Node result = Node.create( NodeKind.COMPILATION_UNIT,
-1,
-1 );
nextTokenIgnoringDocumentation();
if ( tokIs( KeyWords.PACKAGE ) )
{
result.addChild( parsePackage() );
}
result.addChild( parsePackageContent() );
return result;
}
/**
* @return
* @throws TokenException
*/
final IParserNode parseExpression() throws TokenException
{
return parseAssignmentExpression();
}
/**
* tok is first content token
*
* @throws TokenException
*/
final Node parseInterfaceContent() throws TokenException
{
final Node result = Node.create( NodeKind.CONTENT,
tok.getLine(),
tok.getColumn() );
while ( !tokIs( Operators.RIGHT_CURLY_BRACKET ) )
{
if ( tokIs( KeyWords.IMPORT ) )
{
result.addChild( parseImport() );
}
else if ( tokIs( KeyWords.FUNCTION ) )
{
result.addChild( parseFunctionSignature() );
}
else if ( tokIs( KeyWords.INCLUDE )
|| tokIs( KeyWords.INCLUDE_AS2 ) )
{
result.addChild( parseIncludeExpression() );
}
else if ( tokIs( Operators.LEFT_SQUARE_BRACKET ) )
{
while ( !tokIs( Operators.RIGHT_SQUARE_BRACKET ) )
{
nextToken();
}
nextToken();
}
else
{
tryToParseCommentNode( result,
null );
}
}
return result;
}
/**
* tok is first token of content
*
* @throws UnExpectedTokenException
*/
final Node parsePackageContent() throws TokenException
{
final Node result = Node.create( NodeKind.CONTENT,
tok.getLine(),
tok.getColumn() );
final List< Token > modifiers = new ArrayList< Token >();
final List< Node > meta = new ArrayList< Node >();
while ( !tokIs( Operators.RIGHT_CURLY_BRACKET )
&& !tokIs( KeyWords.EOF ) )
{
if ( tokIs( KeyWords.IMPORT ) )
{
result.addChild( parseImport() );
}
else if ( tokIs( KeyWords.USE ) )
{
result.addChild( parseUse() );
}
else if ( tokIs( Operators.LEFT_SQUARE_BRACKET ) )
{
meta.add( parseMetaData() );
}
else if ( tokIs( KeyWords.CLASS ) )
{
result.addChild( parseClass( meta,
modifiers ) );
modifiers.clear();
meta.clear();
}
else if ( tokIs( KeyWords.INTERFACE ) )
{
result.addChild( parseInterface( meta,
modifiers ) );
modifiers.clear();
meta.clear();
}
else if ( tokIs( KeyWords.FUNCTION ) )
{
parseClassFunctions( result,
modifiers,
meta );
}
else if ( tok.getText().startsWith( ASDOC_COMMENT ) )
{
currentAsDoc = Node.create( NodeKind.AS_DOC,
tok.getLine(),
tok.getColumn(),
tok.getText() );
nextToken();
}
else if ( tok.getText().startsWith( MULTIPLE_LINES_COMMENT ) )
{
currentMultiLineComment = Node.create( NodeKind.MULTI_LINE_COMMENT,
tok.getLine(),
tok.getColumn(),
tok.getText() );
nextToken();
}
else
{
modifiers.add( tok );
nextTokenIgnoringDocumentation();
}
}
return result;
}
/**
* @return
* @throws TokenException
*/
final Node parsePrimaryExpression() throws TokenException
{
Node result = Node.create( NodeKind.PRIMARY,
tok.getLine(),
tok.getColumn(),
tok.getText() );
if ( tokIs( Operators.LEFT_SQUARE_BRACKET ) )
{
result.addChild( parseArrayLiteral() );
}
else if ( tokIs( Operators.LEFT_CURLY_BRACKET ) )
{
result.addChild( parseObjectLiteral() );
}
else if ( tokIs( KeyWords.FUNCTION ) )
{
result.addChild( parseLambdaExpression() );
}
else if ( tokIs( KeyWords.NEW ) )
{
result = parseNewExpression();
}
else if ( tokIs( Operators.LEFT_PARENTHESIS ) )
{
result.addChild( parseEncapsulatedExpression() );
}
else
{
nextToken( true );
}
return result;
}
/**
* tok is the first token of a statement
*
* @throws TokenException
*/
final IParserNode parseStatement() throws TokenException
{
IParserNode result;
if ( tokIs( KeyWords.FOR ) )
{
result = parseFor();
}
else if ( tokIs( KeyWords.IF ) )
{
result = parseIf();
}
else if ( tokIs( KeyWords.SWITCH ) )
{
result = parseSwitch();
}
else if ( tokIs( KeyWords.DO ) )
{
result = parseDo();
}
else if ( tokIs( KeyWords.WHILE ) )
{
result = parseWhile();
}
else if ( tokIs( KeyWords.TRY ) )
{
result = parseTry();
}
else if ( tokIs( KeyWords.CATCH ) )
{
result = parseCatch();
}
else if ( tokIs( KeyWords.FINALLY ) )
{
result = parseFinally();
}
else if ( tokIs( Operators.LEFT_CURLY_BRACKET ) )
{
result = parseBlock();
}
else if ( tokIs( KeyWords.VAR ) )
{
result = parseVar();
}
else if ( tokIs( KeyWords.CONST ) )
{
result = parseConst();
}
else if ( tokIs( KeyWords.RETURN ) )
{
result = parseReturnStatement();
}
else if ( tokIs( Operators.SEMI_COLUMN ) )
{
result = parseEmptyStatement();
}
else
{
result = parseExpressionList();
skip( Operators.SEMI_COLUMN );
}
return result;
}
/**
* @return
* @throws TokenException
*/
final Node parseUnaryExpression() throws TokenException
{
Node result;
if ( tokIs( Operators.INCREMENT ) )
{
nextToken();
result = Node.create( NodeKind.PRE_INC,
tok.getLine(),
tok.getColumn(),
parseUnaryExpression() );
}
else if ( tokIs( Operators.DECREMENT ) )
{
nextToken();
result = Node.create( NodeKind.PRE_DEC,
tok.getLine(),
tok.getColumn(),
parseUnaryExpression() );
}
else if ( tokIs( Operators.MINUS ) )
{
nextToken();
result = Node.create( NodeKind.MINUS,
tok.getLine(),
tok.getColumn(),
parseUnaryExpression() );
}
else if ( tokIs( Operators.PLUS )
|| tokIs( Operators.PLUS_AS2 ) )
{
nextToken();
result = Node.create( NodeKind.PLUS,
tok.getLine(),
tok.getColumn(),
parseUnaryExpression() );
}
else
{
result = parseUnaryExpressionNotPlusMinus();
}
return result;
}
private IParserNode collectVarListContent( final Node result ) throws TokenException
{
result.addChild( parseNameTypeInit() );
while ( tokIs( Operators.COMMA ) )
{
nextToken( true );
result.addChild( parseNameTypeInit() );
}
return result;
}
private void consume( final KeyWords keyword ) throws TokenException
{
consume( keyword.toString() );
}
private void consume( final Operators operator ) throws TokenException
{
consume( operator.toString() );
}
/**
* Compare the current token to the parameter. If it equals, get the next
* token. If not, throw a runtime exception.
*
* @param text
* @throws UnExpectedTokenException
*/
private void consume( final String text ) throws TokenException
{
while ( tok.getText().startsWith( "//" ) )
{
nextToken();
}
if ( !tokIs( text ) )
{
throw new UnExpectedTokenException( tok.getText(),
new Position( tok.getLine(), tok.getColumn() ),
fileName,
text );
}
nextToken();
}
private Node convertMeta( final List< Node > metadataList )
{
if ( metadataList == null
|| metadataList.isEmpty() )
{
return null;
}
final Node result = Node.create( NodeKind.META_LIST,
tok.getLine(),
tok.getColumn() );
for ( final Node metadataNode : metadataList )
{
result.addChild( metadataNode );
}
return result;
}
private Node convertModifiers( final List< Token > modifierList )
{
if ( modifierList == null )
{
return null;
}
final Node result = Node.create( NodeKind.MOD_LIST,
tok.getLine(),
tok.getColumn() );
for ( final Token modifierToken : modifierList )
{
result.addChild( NodeKind.MODIFIER,
tok.getLine(),
tok.getColumn(),
modifierToken.getText() );
}
return result;
}
private Node[] doParseSignature() throws TokenException
{
consume( KeyWords.FUNCTION );
Node type = Node.create( NodeKind.TYPE,
tok.getLine(),
tok.getColumn(),
KeyWords.FUNCTION.toString() );
if ( tokIs( KeyWords.SET )
|| tokIs( KeyWords.GET ) )
{
type = Node.create( NodeKind.TYPE,
tok.getLine(),
tok.getColumn(),
tok.getText() );
nextToken(); // set or get
}
final Node name = Node.create( NodeKind.NAME,
tok.getLine(),
tok.getColumn(),
tok.getText() );
nextToken(); // name
final Node params = parseParameterList();
final Node returnType = parseOptionalType();
return new Node[]
{ type,
name,
params,
returnType };
}
private NodeKind findFunctionTypeFromSignature( final Node[] signature )
{
for ( final Node node : signature )
{
if ( node.is( NodeKind.TYPE ) )
{
if ( node.getStringValue().equals( "set" ) )
{
return NodeKind.SET;
}
if ( node.getStringValue().equals( "get" ) )
{
return NodeKind.GET;
}
return NodeKind.FUNCTION;
}
}
return NodeKind.FUNCTION;
}
/**
* Get the next token Skip comments but keep newlines We need this method for
* beeing able to decide if a returnStatement has an expression
*
* @throws UnExpectedTokenException
*/
private void nextTokenAllowNewLine() throws TokenException
{
do
{
tok = scn.nextToken();
if ( tok == null )
{
throw new NullTokenException( fileName );
}
if ( tok.getText() == null )
{
throw new NullTokenException( fileName );
}
}
while ( tok.getText().startsWith( SINGLE_LINE_COMMENT ) );
}
private void nextTokenIgnoringDocumentation() throws TokenException
{
do
{
nextToken();
}
while ( tok.getText().startsWith( MULTIPLE_LINES_COMMENT ) );
}
private IParserNode parseAdditiveExpression() throws TokenException
{
final Node result = Node.create( NodeKind.ADD,
tok.getLine(),
tok.getColumn(),
parseMultiplicativeExpression() );
while ( tokIs( Operators.PLUS )
|| tokIs( Operators.PLUS_AS2 ) || tokIs( Operators.MINUS ) )
{
result.addChild( Node.create( NodeKind.OP,
tok.getLine(),
tok.getColumn(),
tok.getText() ) );
nextToken( true );
result.addChild( parseMultiplicativeExpression() );
}
return result.numChildren() > 1 ? result
: result.getChild( 0 );
}
// ------------------------------------------------------------------------
// language specific recursive descent parsing
// ------------------------------------------------------------------------
private IParserNode parseAndExpression() throws TokenException
{
final Node result = Node.create( NodeKind.AND,
tok.getLine(),
tok.getColumn(),
parseBitwiseOrExpression() );
while ( tokIs( Operators.AND )
|| tokIs( Operators.AND_AS2 ) )
{
result.addChild( Node.create( NodeKind.OP,
tok.getLine(),
tok.getColumn(),
tok.getText() ) );
nextToken( true );
result.addChild( parseBitwiseOrExpression() );
}
return result.numChildren() > 1 ? result
: result.getChild( 0 );
}
/**
* tok is ( exit tok is first token after )
*/
private Node parseArgumentList() throws TokenException
{
consume( Operators.LEFT_PARENTHESIS );
final Node result = Node.create( NodeKind.ARGUMENTS,
tok.getLine(),
tok.getColumn() );
while ( !tokIs( Operators.RIGHT_PARENTHESIS ) )
{
result.addChild( parseExpression() );
skip( Operators.COMMA );
}
consume( Operators.RIGHT_PARENTHESIS );
return result;
}
private Node parseArrayAccessor( final Node node ) throws TokenException
{
final Node result = Node.create( NodeKind.ARRAY_ACCESSOR,
tok.getLine(),
tok.getColumn() );
result.addChild( node );
while ( tokIs( Operators.LEFT_SQUARE_BRACKET ) )
{
nextToken( true );
result.addChild( parseExpression() );
consume( Operators.RIGHT_SQUARE_BRACKET );
}
return result;
}
/**
* tok is [
*/
private IParserNode parseArrayLiteral() throws TokenException
{
final Node result = Node.create( NodeKind.ARRAY,
tok.getLine(),
tok.getColumn() );
consume( Operators.LEFT_SQUARE_BRACKET );
while ( !tokIs( Operators.RIGHT_SQUARE_BRACKET ) )
{
result.addChild( parseExpression() );
skip( Operators.COMMA );
}
consume( Operators.RIGHT_SQUARE_BRACKET );
return result;
}
private IParserNode parseAssignmentExpression() throws TokenException
{
final Node result = Node.create( NodeKind.ASSIGN,
tok.getLine(),
tok.getColumn(),
parseConditionalExpression() );
while ( tokIs( Operators.EQUAL )
|| tokIs( Operators.PLUS_EQUAL ) || tokIs( Operators.MINUS_EQUAL )
|| tokIs( Operators.TIMES_EQUAL ) || tokIs( Operators.DIVIDED_EQUAL )
|| tokIs( Operators.MODULO_EQUAL ) || tokIs( Operators.AND_EQUAL ) || tokIs( Operators.OR_EQUAL )
|| tokIs( Operators.XOR_EQUAL ) )
{
result.addChild( Node.create( NodeKind.OP,
tok.getLine(),
tok.getColumn(),
tok.getText() ) );
nextToken( true );
result.addChild( parseExpression() );
}
return result.numChildren() > 1 ? result
: result.getChild( 0 );
}
private IParserNode parseBitwiseAndExpression() throws TokenException
{
final Node result = Node.create( NodeKind.B_AND,
tok.getLine(),
tok.getColumn(),
parseEqualityExpression() );
while ( tokIs( Operators.B_AND ) )
{
result.addChild( Node.create( NodeKind.OP,
tok.getLine(),
tok.getColumn(),
tok.getText() ) );
nextToken( true );
result.addChild( parseEqualityExpression() );
}
return result.numChildren() > 1 ? result
: result.getChild( 0 );
}
private IParserNode parseBitwiseOrExpression() throws TokenException
{
final Node result = Node.create( NodeKind.B_OR,
tok.getLine(),
tok.getColumn(),
parseBitwiseXorExpression() );
while ( tokIs( Operators.B_OR ) )
{
result.addChild( Node.create( NodeKind.OP,
tok.getLine(),
tok.getColumn(),
tok.getText() ) );
nextToken( true );
result.addChild( parseBitwiseXorExpression() );
}
return result.numChildren() > 1 ? result
: result.getChild( 0 );
}
private IParserNode parseBitwiseXorExpression() throws TokenException
{
final Node result = Node.create( NodeKind.B_XOR,
tok.getLine(),
tok.getColumn(),
parseBitwiseAndExpression() );
while ( tokIs( Operators.B_XOR ) )
{
result.addChild( Node.create( NodeKind.OP,
tok.getLine(),
tok.getColumn(),
tok.getText() ) );
nextToken( true );
result.addChild( parseBitwiseAndExpression() );
}
return result.numChildren() > 1 ? result
: result.getChild( 0 );
}
private Node parseBlock() throws TokenException
{
return parseBlock( Node.create( NodeKind.BLOCK,
tok.getLine(),
tok.getColumn() ) );
}
private Node parseBlock( final Node result ) throws TokenException
{
consume( Operators.LEFT_CURLY_BRACKET );
while ( !tokIs( Operators.RIGHT_CURLY_BRACKET ) )
{
if ( tok.getText().startsWith( MULTIPLE_LINES_COMMENT ) )
{
currentFunctionNode.addChild( Node.create( NodeKind.MULTI_LINE_COMMENT,
tok.getLine(),
tok.getColumn(),
tok.getText() ) );
nextToken();
}
else
{
result.addChild( parseStatement() );
}
}
consume( Operators.RIGHT_CURLY_BRACKET );
return result;
}
/**
* tok is catch
*
* @throws TokenException
*/
private Node parseCatch() throws TokenException
{
consume( KeyWords.CATCH );
consume( Operators.LEFT_PARENTHESIS );
final Node result = Node.create( NodeKind.CATCH,
tok.getLine(),
tok.getColumn(),
Node.create( NodeKind.NAME,
tok.getLine(),
tok.getColumn(),
tok.getText() ) );
nextToken( true ); // name
if ( tokIs( Operators.COLUMN ) )
{
nextToken( true ); // :
result.addChild( Node.create( NodeKind.TYPE,
tok.getLine(),
tok.getColumn(),
tok.getText() ) );
nextToken( true ); // type
}
consume( Operators.RIGHT_PARENTHESIS );
result.addChild( parseBlock() );
return result;
}
/**
* tok is class
*
* @param meta
* @param modifier
* @throws TokenException
*/
private Node parseClass( final List< Node > meta,
final List< Token > modifier ) throws TokenException
{
consume( KeyWords.CLASS );
final Node result = Node.create( NodeKind.CLASS,
tok.getLine(),
tok.getColumn() );
if ( currentAsDoc != null )
{
result.addChild( currentAsDoc );
currentAsDoc = null;
}
if ( currentMultiLineComment != null )
{
result.addChild( currentMultiLineComment );
currentMultiLineComment = null;
}
result.addChild( NodeKind.NAME,
tok.getLine(),
tok.getColumn(),
parseQualifiedName( true ) );
result.addChild( convertMeta( meta ) );
result.addChild( convertModifiers( modifier ) );
// nextToken( true ); // name
do
{
if ( tokIs( KeyWords.EXTENDS ) )
{
nextToken( true ); // extends
result.addChild( NodeKind.EXTENDS,
tok.getLine(),
tok.getColumn(),
parseQualifiedName( false ) );
}
else if ( tokIs( KeyWords.IMPLEMENTS ) )
{
result.addChild( parseImplementsList() );
}
}
while ( !tokIs( Operators.LEFT_CURLY_BRACKET ) );
consume( Operators.LEFT_CURLY_BRACKET );
result.addChild( parseClassContent() );
consume( Operators.RIGHT_CURLY_BRACKET );
return result;
}
private void parseClassConstant( final Node result,
final List< Token > modifiers,
final List< Node > meta ) throws TokenException
{
result.addChild( parseConstList( meta,
modifiers ) );
if ( tokIs( Operators.SEMI_COLUMN ) )
{
nextToken();
}
meta.clear();
modifiers.clear();
}
private void parseClassField( final Node result,
final List< Token > modifiers,
final List< Node > meta ) throws TokenException
{
final Node varList = parseVarList( meta,
modifiers );
result.addChild( varList );
if ( currentAsDoc != null )
{
varList.addChild( currentAsDoc );
currentAsDoc = null;
}
if ( currentMultiLineComment != null )
{
result.addChild( currentMultiLineComment );
currentMultiLineComment = null;
}
if ( tokIs( Operators.SEMI_COLUMN ) )
{
nextToken();
}
meta.clear();
modifiers.clear();
}
private void parseClassFunctions( final Node result,
final List< Token > modifiers,
final List< Node > meta ) throws TokenException
{
result.addChild( parseFunction( meta,
modifiers ) );
meta.clear();
modifiers.clear();
}
/**
* tok is (
*
* @throws TokenException
*/
private Node parseCondition() throws TokenException
{
consume( Operators.LEFT_PARENTHESIS );
final Node result = Node.create( NodeKind.CONDITION,
tok.getLine(),
tok.getColumn(),
parseExpression() );
consume( Operators.RIGHT_PARENTHESIS );
return result;
}
private IParserNode parseConditionalExpression() throws TokenException
{
final IParserNode result = parseOrExpression();
if ( tokIs( Operators.QUESTION_MARK ) )
{
final Node conditional = Node.create( NodeKind.CONDITIONAL,
tok.getLine(),
tok.getColumn(),
result );
nextToken( true ); // ?
conditional.addChild( parseExpression() );
nextToken( true ); // :
conditional.addChild( parseExpression() );
return conditional;
}
return result;
}
private Node parseConst() throws TokenException
{
Node result;
result = parseConstList( null,
null );
skip( Operators.SEMI_COLUMN );
return result;
}
/**
* tok is const
*
* @param modifiers
* @param meta
* @throws TokenException
*/
private Node parseConstList( final List< Node > meta,
final List< Token > modifiers ) throws TokenException
{
consume( KeyWords.CONST );
final Node result = Node.create( NodeKind.CONST_LIST,
tok.getLine(),
tok.getColumn() );
result.addChild( convertMeta( meta ) );
result.addChild( convertModifiers( modifiers ) );
collectVarListContent( result );
return result;
}
private Node parseDecrement( final Node node ) throws TokenException
{
nextToken( true );
final Node result = Node.create( NodeKind.POST_DEC,
tok.getLine(),
tok.getColumn() );
result.addChild( node );
return result;
}
/**
* tok is do
*
* @throws TokenException
*/
private Node parseDo() throws TokenException
{
consume( KeyWords.DO );
final Node result = Node.create( NodeKind.DO,
tok.getLine(),
tok.getColumn(),
parseStatement() );
consume( KeyWords.WHILE );
result.addChild( parseCondition() );
if ( tokIs( Operators.SEMI_COLUMN ) )
{
nextToken( true );
}
return result;
}
private Node parseDot( final Node node ) throws TokenException
{
nextToken();
if ( tokIs( Operators.LEFT_PARENTHESIS ) )
{
nextToken();
final Node result = Node.create( NodeKind.E4X_FILTER,
tok.getLine(),
tok.getColumn() );
result.addChild( node );
result.addChild( parseExpression() );
consume( Operators.RIGHT_PARENTHESIS );
return result;
}
else if ( tokIs( Operators.TIMES ) )
{
final Node result = Node.create( NodeKind.E4X_STAR,
tok.getLine(),
tok.getColumn() );
result.addChild( node );
return result;
}
final Node result = Node.create( NodeKind.DOT,
tok.getLine(),
tok.getColumn() );
result.addChild( node );
result.addChild( parseExpression() );
return result;
}
private Node parseEmptyStatement() throws TokenException
{
Node result;
result = Node.create( NodeKind.STMT_EMPTY,
tok.getLine(),
tok.getColumn(),
Operators.SEMI_COLUMN.toString() );
nextToken( true );
return result;
}
private Node parseEncapsulatedExpression() throws TokenException
{
consume( Operators.LEFT_PARENTHESIS );
final Node result = Node.create( NodeKind.ENCAPSULATED,
tok.getLine(),
tok.getColumn() );
result.addChild( parseExpressionList() );
consume( Operators.RIGHT_PARENTHESIS );
return result;
}
private IParserNode parseEqualityExpression() throws TokenException
{
final Node result = Node.create( NodeKind.EQUALITY,
tok.getLine(),
tok.getColumn(),
parseRelationalExpression() );
while ( tokIs( Operators.DOUBLE_EQUAL )
|| tokIs( Operators.DOUBLE_EQUAL_AS2 ) || tokIs( Operators.STRICTLY_EQUAL )
|| tokIs( Operators.NON_EQUAL ) || tokIs( Operators.NON_EQUAL_AS2_1 )
|| tokIs( Operators.NON_EQUAL_AS2_2 ) || tokIs( Operators.NON_STRICTLY_EQUAL ) )
{
result.addChild( Node.create( NodeKind.OP,
tok.getLine(),
tok.getColumn(),
tok.getText() ) );
nextToken( true );
result.addChild( parseRelationalExpression() );
}
return result.numChildren() > 1 ? result
: result.getChild( 0 );
}
private IParserNode parseExpressionList() throws TokenException
{
final Node result = Node.create( NodeKind.EXPR_LIST,
tok.getLine(),
tok.getColumn(),
parseAssignmentExpression() );
while ( tokIs( Operators.COMMA ) )
{
nextToken( true );
result.addChild( parseAssignmentExpression() );
}
return result.numChildren() > 1 ? result
: result.getChild( 0 );
}
private Node parseFinally() throws TokenException
{
Node result;
nextToken( true );
result = Node.create( NodeKind.FINALLY,
tok.getLine(),
tok.getColumn(),
parseBlock() );
return result;
}
/**
* tok is for
*
* @throws TokenException
*/
private Node parseFor() throws TokenException
{
consume( KeyWords.FOR );
if ( tokIs( KeyWords.EACH ) )
{
nextToken();
return parseForEach();
}
else
{
return parseTraditionalFor();
}
}
/**
* tok is ( for each( var obj : Type in List )
*
* @throws TokenException
*/
private Node parseForEach() throws TokenException
{
consume( Operators.LEFT_PARENTHESIS );
final Node result = Node.create( NodeKind.FOREACH,
tok.getLine(),
tok.getColumn() );
if ( tokIs( KeyWords.VAR ) )
{
final Node var = Node.create( NodeKind.VAR,
tok.getLine(),
tok.getColumn() );
nextToken();
var.addChild( parseNameTypeInit() );
result.addChild( var );
}
else
{
result.addChild( NodeKind.NAME,
tok.getLine(),
tok.getColumn(),
tok.getText() );
// names allowed?
nextToken();
}
nextToken(); // in
result.addChild( NodeKind.IN,
tok.getLine(),
tok.getColumn(),
parseExpression() );
consume( Operators.RIGHT_PARENTHESIS );
result.addChild( parseStatement() );
return result;
}
private Node parseForIn( final Node result ) throws TokenException
{
nextToken();
result.addChild( NodeKind.IN,
tok.getLine(),
tok.getColumn(),
parseExpression() );
result.setId( NodeKind.FORIN );
return result;
}
/**
* tok is function
*
* @param modifiers
* @param meta
* @throws TokenException
*/
private Node parseFunction( final List< Node > meta,
final List< Token > modifiers ) throws TokenException
{
final Node[] signature = doParseSignature();
final Node result = Node.create( findFunctionTypeFromSignature( signature ),
tok.getLine(),
tok.getColumn(),
signature[ 0 ].getStringValue() );
if ( currentAsDoc != null )
{
result.addChild( currentAsDoc );
currentAsDoc = null;
}
if ( currentMultiLineComment != null )
{
result.addChild( currentMultiLineComment );
currentMultiLineComment = null;
}
result.addChild( convertMeta( meta ) );
result.addChild( convertModifiers( modifiers ) );
result.addChild( signature[ 1 ] );
result.addChild( signature[ 2 ] );
result.addChild( signature[ 3 ] );
if ( tokIs( Operators.SEMI_COLUMN ) )
{
consume( Operators.SEMI_COLUMN );
}
else
{
result.addChild( parseFunctionBlock() );
}
currentFunctionNode = null;
return result;
}
/**
* tok is { exit tok is the first tok after }
*
* @throws TokenException
* @throws TokenException
*/
private Node parseFunctionBlock() throws TokenException
{
final Node block = Node.create( NodeKind.BLOCK,
tok.getLine(),
tok.getColumn() );
currentFunctionNode = block;
parseBlock( block );
return block;
}
private Node parseFunctionCall( final Node node ) throws TokenException
{
final Node result = Node.create( NodeKind.CALL,
tok.getLine(),
tok.getColumn() );
result.addChild( node );
while ( tokIs( Operators.LEFT_PARENTHESIS ) )
{
result.addChild( parseArgumentList() );
}
while ( tokIs( Operators.LEFT_SQUARE_BRACKET ) )
{
result.addChild( parseArrayLiteral() );
}
return result;
}
/**
* tok is function exit tok is the first token after the optional ;
*
* @throws TokenException
*/
private Node parseFunctionSignature() throws TokenException
{
final Node[] signature = doParseSignature();
skip( Operators.SEMI_COLUMN );
final Node result = Node.create( findFunctionTypeFromSignature( signature ),
tok.getLine(),
tok.getColumn(),
signature[ 0 ].getStringValue() );
result.addChild( signature[ 1 ] );
result.addChild( signature[ 2 ] );
result.addChild( signature[ 3 ] );
return result;
}
/**
* tok is if
*
* @throws TokenException
*/
private Node parseIf() throws TokenException
{
consume( KeyWords.IF );
final Node result = Node.create( NodeKind.IF,
tok.getLine(),
tok.getColumn(),
parseCondition() );
result.addChild( parseStatement() );
if ( tokIs( KeyWords.ELSE ) )
{
nextToken( true );
result.addChild( parseStatement() );
}
return result;
}
/**
* tok is implements implements a,b,c exit tok is the first token after the
* list of qualfied names
*
* @throws TokenException
*/
private Node parseImplementsList() throws TokenException
{
consume( KeyWords.IMPLEMENTS );
final Node result = Node.create( NodeKind.IMPLEMENTS_LIST,
tok.getLine(),
tok.getColumn() );
result.addChild( NodeKind.IMPLEMENTS,
tok.getLine(),
tok.getColumn(),
parseQualifiedName( true ) );
while ( tokIs( Operators.COMMA ) )
{
nextToken( true );
result.addChild( NodeKind.IMPLEMENTS,
tok.getLine(),
tok.getColumn(),
parseQualifiedName( false ) );
}
return result;
}
/**
* tok is import
*
* @throws TokenException
*/
private Node parseImport() throws TokenException
{
consume( KeyWords.IMPORT );
final Node result = Node.create( NodeKind.IMPORT,
tok.getLine(),
tok.getColumn(),
parseImportName() );
skip( Operators.SEMI_COLUMN );
return result;
}
/**
* tok is the first part of a name the last part can be a star exit tok is
* the first token, which doesn't belong to the name
*
* @throws TokenException
*/
private String parseImportName() throws TokenException
{
final StringBuffer result = new StringBuffer();
result.append( tok.getText() );
nextToken();
while ( tokIs( Operators.DOT ) )
{
result.append( Operators.DOT );
nextToken(); // .
result.append( tok.getText() );
nextToken(); // part of name
}
return result.toString();
}
private IParserNode parseIncludeExpression() throws TokenException
{
final Node result = Node.create( NodeKind.INCLUDE,
tok.getLine(),
tok.getColumn() );
if ( tokIs( KeyWords.INCLUDE ) )
{
consume( KeyWords.INCLUDE );
}
else if ( tokIs( KeyWords.INCLUDE_AS2 ) )
{
consume( KeyWords.INCLUDE_AS2 );
}
result.addChild( parseExpression() );
return result;
}
private Node parseIncrement( final Node node ) throws TokenException
{
nextToken( true );
final Node result = Node.create( NodeKind.POST_INC,
tok.getLine(),
tok.getColumn() );
result.addChild( node );
return result;
}
/**
* tok is interface
*
* @param meta
* @param modifier
* @throws TokenException
*/
private Node parseInterface( final List< Node > meta,
final List< Token > modifier ) throws TokenException
{
consume( KeyWords.INTERFACE );
final Node result = Node.create( NodeKind.INTERFACE,
tok.getLine(),
tok.getColumn() );
if ( currentAsDoc != null )
{
result.addChild( currentAsDoc );
currentAsDoc = null;
}
if ( currentMultiLineComment != null )
{
result.addChild( currentMultiLineComment );
currentMultiLineComment = null;
}
result.addChild( NodeKind.NAME,
tok.getLine(),
tok.getColumn(),
parseQualifiedName( true ) );
result.addChild( convertMeta( meta ) );
result.addChild( convertModifiers( modifier ) );
if ( tokIs( KeyWords.EXTENDS ) )
{
nextToken(); // extends
result.addChild( NodeKind.EXTENDS,
tok.getLine(),
tok.getColumn(),
parseQualifiedName( false ) );
}
while ( tokIs( Operators.COMMA ) )
{
nextToken(); // comma
result.addChild( NodeKind.EXTENDS,
tok.getLine(),
tok.getColumn(),
parseQualifiedName( false ) );
}
consume( Operators.LEFT_CURLY_BRACKET );
result.addChild( parseInterfaceContent() );
consume( Operators.RIGHT_CURLY_BRACKET );
return result;
}
/**
* tok is function
*
* @throws TokenException
*/
private Node parseLambdaExpression() throws TokenException
{
consume( KeyWords.FUNCTION );
Node result;
if ( tok.getText().compareTo( "(" ) == 0 )
{
result = Node.create( NodeKind.LAMBDA,
tok.getLine(),
tok.getColumn() );
}
else
{
result = Node.create( NodeKind.FUNCTION,
tok.getLine(),
tok.getColumn(),
tok.getText() );
nextToken( true );
}
result.addChild( parseParameterList() );
result.addChild( parseOptionalType() );
result.addChild( parseBlock() );
return result;
}
private IParserNode parseLines( final String filePath,
final String[] lines ) throws TokenException
{
setFileName( filePath );
scn = new AS3Scanner();
scn.setLines( lines );
return parseCompilationUnit();
}
/**
* tok is [ [id] [id ("test")] [id (name="test",type="a.b.c.Event")] exit
* token is the first token after ]
*
* @throws TokenException
*/
private Node parseMetaData() throws TokenException
{
final StringBuffer buffer = new StringBuffer();
final int line = tok.getLine();
final int column = tok.getColumn();
consume( Operators.LEFT_SQUARE_BRACKET );
while ( !tokIs( Operators.RIGHT_SQUARE_BRACKET ) )
{
if ( buffer.length() > 0 )
{
buffer.append( ' ' );
}
buffer.append( tok.getText() );
nextToken();
}
skip( Operators.RIGHT_SQUARE_BRACKET );
final Node metaDataNode = Node.create( NodeKind.META,
line,
column,
buffer.toString() );
return metaDataNode;
}
private IParserNode parseMultiplicativeExpression() throws TokenException
{
final Node result = Node.create( NodeKind.MULTIPLICATION,
tok.getLine(),
tok.getColumn(),
parseUnaryExpression() );
while ( tokIs( Operators.TIMES )
|| tokIs( Operators.SLASH ) || tokIs( Operators.MODULO ) )
{
result.addChild( Node.create( NodeKind.OP,
tok.getLine(),
tok.getColumn(),
tok.getText() ) );
nextToken( true );
result.addChild( parseUnaryExpression() );
}
return result.numChildren() > 1 ? result
: result.getChild( 0 );
}
private String parseNamespaceName() throws TokenException
{
final String name = tok.getText();
nextToken(); // simple name for now
return name;
}
private Node parseNameTypeInit() throws TokenException
{
final Node result = Node.create( NodeKind.NAME_TYPE_INIT,
tok.getLine(),
tok.getColumn() );
result.addChild( NodeKind.NAME,
tok.getLine(),
tok.getColumn(),
tok.getText() );
nextToken( true ); // name
result.addChild( parseOptionalType() );
result.addChild( parseOptionalInit() );
return result;
}
private Node parseNewExpression() throws TokenException
{
consume( KeyWords.NEW );
final Node result = Node.create( NodeKind.NEW,
tok.getLine(),
tok.getColumn() );
result.addChild( parseExpression() ); // name
if ( tokIs( Operators.VECTOR_START ) )
{
result.addChild( Node.create( NodeKind.VECTOR,
tok.getLine(),
tok.getColumn(),
parseVector() ) );
}
if ( tokIs( Operators.LEFT_PARENTHESIS ) )
{
result.addChild( parseArgumentList() );
}
return result;
}
/**
* tok is {
*/
private Node parseObjectLiteral() throws TokenException
{
final Node result = Node.create( NodeKind.OBJECT,
tok.getLine(),
tok.getColumn() );
consume( Operators.LEFT_CURLY_BRACKET );
while ( !tokIs( Operators.RIGHT_CURLY_BRACKET ) )
{
result.addChild( parseObjectLiteralPropertyDeclaration() );
skip( Operators.COMMA );
}
consume( Operators.RIGHT_CURLY_BRACKET );
return result;
}
/*
* tok is name
*/
private Node parseObjectLiteralPropertyDeclaration() throws TokenException
{
final Node result = Node.create( NodeKind.PROP,
tok.getLine(),
tok.getColumn() );
final Node name = Node.create( NodeKind.NAME,
tok.getLine(),
tok.getColumn(),
tok.getText() );
result.addChild( name );
nextToken(); // name
consume( Operators.COLUMN );
result.addChild( NodeKind.VALUE,
tok.getLine(),
tok.getColumn(),
parseExpression() );
return result;
}
/**
* if tok is "=" parse the expression otherwise do nothing
*
* @return
*/
private Node parseOptionalInit() throws TokenException
{
Node result = null;
if ( tokIs( Operators.EQUAL ) )
{
nextToken( true );
result = Node.create( NodeKind.INIT,
tok.getLine(),
tok.getColumn(),
parseExpression() );
}
return result;
}
/**
* if tok is ":" parse the type otherwise do nothing
*
* @return
* @throws TokenException
*/
private Node parseOptionalType() throws TokenException
{
Node result = Node.create( NodeKind.TYPE,
tok.getLine(),
tok.getColumn(),
"" );
if ( tokIs( Operators.COLUMN ) )
{
nextToken( true );
result = parseType();
}
return result;
}
private IParserNode parseOrExpression() throws TokenException
{
final Node result = Node.create( NodeKind.OR,
tok.getLine(),
tok.getColumn(),
parseAndExpression() );
while ( tokIs( Operators.LOGICAL_OR )
|| tokIs( Operators.LOGICAL_OR_AS2 ) )
{
result.addChild( Node.create( NodeKind.OP,
tok.getLine(),
tok.getColumn(),
tok.getText() ) );
nextToken( true );
result.addChild( parseAndExpression() );
}
return result.numChildren() > 1 ? result
: result.getChild( 0 );
}
/**
* tok is package
*
* @throws UnExpectedTokenException
*/
private Node parsePackage() throws TokenException
{
consume( KeyWords.PACKAGE );
final Node result = Node.create( NodeKind.PACKAGE,
tok.getLine(),
tok.getColumn() );
final StringBuffer nameBuffer = new StringBuffer();
while ( !tokIs( Operators.LEFT_CURLY_BRACKET ) )
{
nameBuffer.append( tok.getText() );
nextToken();
}
result.addChild( NodeKind.NAME,
tok.getLine(),
tok.getColumn(),
nameBuffer.toString() );
consume( Operators.LEFT_CURLY_BRACKET );
result.addChild( parsePackageContent() );
consume( Operators.RIGHT_CURLY_BRACKET );
return result;
}
/**
* tok is the name of a parameter or ...
*/
private Node parseParameter() throws TokenException
{
final Node result = Node.create( NodeKind.PARAMETER,
tok.getLine(),
tok.getColumn() );
if ( tokIs( Operators.REST_PARAMETERS ) )
{
nextToken( true ); // ...
final Node rest = Node.create( NodeKind.REST,
tok.getLine(),
tok.getColumn(),
tok.getText() );
nextToken( true ); // rest
result.addChild( rest );
}
else
{
result.addChild( parseNameTypeInit() );
}
return result;
}
/**
* tok is (
*
* @throws TokenException
*/
private Node parseParameterList() throws TokenException
{
consume( Operators.LEFT_PARENTHESIS );
final Node result = Node.create( NodeKind.PARAMETER_LIST,
tok.getLine(),
tok.getColumn() );
while ( !tokIs( Operators.RIGHT_PARENTHESIS ) )
{
result.addChild( parseParameter() );
if ( tokIs( Operators.COMMA ) )
{
nextToken( true );
}
else
{
break;
}
}
consume( Operators.RIGHT_PARENTHESIS );
return result;
}
/**
* tok is first part of the name exit tok is the first token after the name
*
* @throws TokenException
*/
private String parseQualifiedName( final boolean skipPackage ) throws TokenException
{
final StringBuffer buffer = new StringBuffer();
buffer.append( tok.getText() );
nextToken();
while ( tokIs( Operators.DOT )
|| tokIs( Operators.DOUBLE_COLUMN ) )
{
buffer.append( tok.getText() );
nextToken();
buffer.append( tok.getText() );
nextToken(); // name
}
if ( skipPackage )
{
return buffer.substring( buffer.lastIndexOf( Operators.DOT.toString() ) + 1 );
}
return buffer.toString();
}
private IParserNode parseRelationalExpression() throws TokenException
{
final Node result = Node.create( NodeKind.RELATION,
tok.getLine(),
tok.getColumn(),
parseShiftExpression() );
while ( tokIs( Operators.INFERIOR )
|| tokIs( Operators.INFERIOR_AS2 ) || tokIs( Operators.INFERIOR_OR_EQUAL )
|| tokIs( Operators.INFERIOR_OR_EQUAL_AS2 ) || tokIs( Operators.SUPERIOR )
|| tokIs( Operators.SUPERIOR_AS2 ) || tokIs( Operators.SUPERIOR_OR_EQUAL )
|| tokIs( Operators.SUPERIOR_OR_EQUAL_AS2 ) || tokIs( KeyWords.IS ) || tokIs( KeyWords.IN )
&& !isInFor || tokIs( KeyWords.AS ) || tokIs( KeyWords.INSTANCE_OF ) )
{
if ( !tokIs( KeyWords.AS ) )
{
result.addChild( Node.create( NodeKind.OP,
tok.getLine(),
tok.getColumn(),
tok.getText() ) );
}
else
{
result.addChild( Node.create( NodeKind.AS,
tok.getLine(),
tok.getColumn(),
tok.getText() ) );
}
nextToken( true );
result.addChild( parseShiftExpression() );
}
return result.numChildren() > 1 ? result
: result.getChild( 0 );
}
private IParserNode parseReturnStatement() throws TokenException
{
Node result;
nextTokenAllowNewLine();
if ( tokIs( NEW_LINE )
|| tokIs( Operators.SEMI_COLUMN ) )
{
nextToken( true );
result = Node.create( NodeKind.RETURN,
tok.getLine(),
tok.getColumn(),
"" );
}
else
{
result = Node.create( NodeKind.RETURN,
tok.getLine(),
tok.getColumn(),
parseExpression() );
skip( Operators.SEMI_COLUMN );
}
return result;
}
private IParserNode parseShiftExpression() throws TokenException
{
final Node result = Node.create( NodeKind.SHIFT,
tok.getLine(),
tok.getColumn(),
parseAdditiveExpression() );
while ( tokIs( Operators.DOUBLE_SHIFT_LEFT )
|| tokIs( Operators.TRIPLE_SHIFT_LEFT ) || tokIs( Operators.DOUBLE_SHIFT_RIGHT )
|| tokIs( Operators.TRIPLE_SHIFT_RIGHT ) )
{
result.addChild( Node.create( NodeKind.OP,
tok.getLine(),
tok.getColumn(),
tok.getText() ) );
nextToken( true );
result.addChild( parseAdditiveExpression() );
}
return result.numChildren() > 1 ? result
: result.getChild( 0 );
}
/**
* tok is switch
*
* @throws TokenException
*/
private Node parseSwitch() throws TokenException
{
consume( KeyWords.SWITCH );
final Node result = Node.create( NodeKind.SWITCH,
tok.getLine(),
tok.getColumn(),
parseCondition() );
if ( tokIs( Operators.LEFT_CURLY_BRACKET ) )
{
nextToken();
result.addChild( parseSwitchCases() );
consume( Operators.RIGHT_CURLY_BRACKET );
}
return result;
}
/**
* tok is case, default or the first token of the first statement
*
* @throws TokenException
*/
private Node parseSwitchBlock() throws TokenException
{
final Node result = Node.create( NodeKind.SWITCH_BLOCK,
tok.getLine(),
tok.getColumn() );
while ( !tokIs( KeyWords.CASE )
&& !tokIs( KeyWords.DEFAULT ) && !tokIs( Operators.RIGHT_CURLY_BRACKET ) )
{
result.addChild( parseStatement() );
}
return result;
}
/**
* tok is { exit tok is }
*
* @throws TokenException
*/
private Node parseSwitchCases() throws TokenException
{
final Node result = Node.create( NodeKind.CASES,
tok.getLine(),
tok.getColumn() );
for ( ;; )
{
if ( tokIs( Operators.RIGHT_CURLY_BRACKET ) )
{
break;
}
else if ( tokIs( KeyWords.CASE ) )
{
nextToken( true ); // case
final Node caseNode = Node.create( NodeKind.CASE,
tok.getLine(),
tok.getColumn(),
parseExpression() );
consume( Operators.COLUMN );
caseNode.addChild( parseSwitchBlock() );
result.addChild( caseNode );
}
else if ( tokIs( KeyWords.DEFAULT ) )
{
nextToken( true ); // default
consume( Operators.COLUMN );
final Node caseNode = Node.create( NodeKind.CASE,
tok.getLine(),
tok.getColumn(),
Node.create( NodeKind.DEFAULT,
tok.getLine(),
tok.getColumn(),
KeyWords.DEFAULT.toString() ) );
caseNode.addChild( parseSwitchBlock() );
result.addChild( caseNode );
}
}
return result;
}
/**
* tok is ( for( var x : int = 0; i < length; i++ ) for( var s : String in
* Object )
*
* @throws TokenException
*/
private Node parseTraditionalFor() throws TokenException
{
consume( Operators.LEFT_PARENTHESIS );
final Node result = Node.create( NodeKind.FOR,
tok.getLine(),
tok.getColumn() );
if ( !tokIs( Operators.SEMI_COLUMN ) )
{
if ( tokIs( KeyWords.VAR ) )
{
result.addChild( NodeKind.INIT,
tok.getLine(),
tok.getColumn(),
parseVarList( null,
null ) );
}
else
{
isInFor = true;
result.addChild( NodeKind.INIT,
tok.getLine(),
tok.getColumn(),
parseExpression() );
isInFor = false;
}
if ( tokIs( NodeKind.IN.toString() ) )
{
return parseForIn( result );
}
}
consume( Operators.SEMI_COLUMN );
if ( !tokIs( Operators.SEMI_COLUMN ) )
{
result.addChild( NodeKind.COND,
tok.getLine(),
tok.getColumn(),
parseExpression() );
}
consume( Operators.SEMI_COLUMN );
if ( !tokIs( Operators.RIGHT_PARENTHESIS ) )
{
result.addChild( NodeKind.ITER,
tok.getLine(),
tok.getColumn(),
parseExpressionList() );
}
consume( Operators.RIGHT_PARENTHESIS );
result.addChild( parseStatement() );
return result;
}
private Node parseTry() throws TokenException
{
Node result;
nextToken( true );
result = Node.create( NodeKind.TRY,
tok.getLine(),
tok.getColumn(),
parseBlock() );
return result;
}
private Node parseType() throws TokenException
{
Node result;
if ( tok.getText().equals( VECTOR ) )
{
result = parseVector();
}
else
{
result = Node.create( NodeKind.TYPE,
tok.getLine(),
tok.getColumn(),
parseQualifiedName( true ) );
// nextToken( true );
}
return result;
}
private Node parseUnaryExpressionNotPlusMinus() throws TokenException
{
Node result;
if ( tokIs( KeyWords.DELETE ) )
{
nextToken( true );
result = Node.create( NodeKind.DELETE,
tok.getLine(),
tok.getColumn(),
parseExpression() );
}
else if ( tokIs( KeyWords.VOID ) )
{
nextToken( true );
result = Node.create( NodeKind.VOID,
tok.getLine(),
tok.getColumn(),
parseExpression() );
}
else if ( tokIs( KeyWords.TYPEOF ) )
{
nextToken( true );
result = Node.create( NodeKind.TYPEOF,
tok.getLine(),
tok.getColumn(),
parseExpression() );
}
else if ( tokIs( "!" )
|| tokIs( "not" ) )
{
nextToken( true );
result = Node.create( NodeKind.NOT,
tok.getLine(),
tok.getColumn(),
parseExpression() );
}
else if ( tokIs( "~" ) )
{
nextToken( true );
result = Node.create( NodeKind.B_NOT,
tok.getLine(),
tok.getColumn(),
parseExpression() );
}
else
{
result = parseUnaryPostfixExpression();
}
return result;
}
private Node parseUnaryPostfixExpression() throws TokenException
{
Node node = parsePrimaryExpression();
if ( tokIs( Operators.LEFT_SQUARE_BRACKET ) )
{
node = parseArrayAccessor( node );
}
else if ( tokIs( Operators.LEFT_PARENTHESIS ) )
{
node = parseFunctionCall( node );
}
if ( tokIs( Operators.INCREMENT ) )
{
node = parseIncrement( node );
}
else if ( tokIs( Operators.DECREMENT ) )
{
node = parseDecrement( node );
}
else if ( tokIs( Operators.DOT )
|| tokIs( Operators.DOUBLE_COLUMN ) )
{
node = parseDot( node );
}
return node;
}
private Node parseUse() throws TokenException
{
consume( KeyWords.USE );
consume( KeyWords.NAMESPACE );
final Node result = Node.create( NodeKind.USE,
tok.getLine(),
tok.getColumn(),
parseNamespaceName() );
skip( Operators.SEMI_COLUMN );
return result;
}
private Node parseVar() throws TokenException
{
Node result;
result = parseVarList( null,
null );
skip( Operators.SEMI_COLUMN );
return result;
}
/**
* tok is var var x, y : String, z : int = 0;
*
* @param modifiers
* @param meta
* @throws TokenException
*/
private Node parseVarList( final List< Node > meta,
final List< Token > modifiers ) throws TokenException
{
consume( KeyWords.VAR );
final Node result = Node.create( NodeKind.VAR_LIST,
tok.getLine(),
tok.getColumn() );
result.addChild( convertMeta( meta ) );
result.addChild( convertModifiers( modifiers ) );
collectVarListContent( result );
return result;
}
private Node parseVector() throws TokenException
{
final Node result = Node.create( NodeKind.VECTOR,
tok.getLine(),
tok.getColumn(),
"" );
if ( tok.getText().compareTo( "Vector" ) == 0 )
{
nextToken();
}
consume( Operators.VECTOR_START );
result.addChild( parseType() );
consume( Operators.SUPERIOR );
return result;
}
/**
* tok is while
*
* @throws TokenException
*/
private Node parseWhile() throws TokenException
{
consume( KeyWords.WHILE );
final Node result = Node.create( NodeKind.WHILE,
tok.getLine(),
tok.getColumn() );
result.addChild( parseCondition() );
result.addChild( parseStatement() );
return result;
}
private void setFileName( final String fileNameToParse )
{
fileName = fileNameToParse;
}
private void skip( final Operators operator ) throws TokenException
{
skip( operator.toString() );
}
/**
* Skip the current token, if it equals to the parameter
*
* @param text
* @throws UnExpectedTokenException
*/
private void skip( final String text ) throws TokenException
{
if ( tokIs( text ) )
{
nextToken();
}
}
private boolean tokIs( final KeyWords keyword )
{
return tok.getText().compareTo( keyword.toString() ) == 0;
}
private boolean tokIs( final Operators operator )
{
return tok.getText().compareTo( operator.toString() ) == 0;
}
/**
* Compare the current token to the parameter
*
* @param text
* @return true, if tok's text property equals the parameter
*/
private boolean tokIs( final String text )
{
return tok.getText().equals( text );
}
private void tryToParseCommentNode( final Node result,
final List< Token > modifiers ) throws TokenException
{
if ( tok.getText().startsWith( ASDOC_COMMENT ) )
{
currentAsDoc = Node.create( NodeKind.AS_DOC,
tok.getLine(),
tok.getColumn(),
tok.getText() );
nextToken();
}
else if ( tok.getText().startsWith( MULTIPLE_LINES_COMMENT ) )
{
result.addChild( Node.create( NodeKind.MULTI_LINE_COMMENT,
tok.getLine(),
tok.getColumn(),
tok.getText() ) );
nextToken();
}
else
{
if ( modifiers != null )
{
modifiers.add( tok );
}
nextTokenIgnoringDocumentation();
}
}
}