| /* |
| * 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(); |
| } |
| } |
| } |