You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by cd...@apache.org on 2015/03/07 13:07:16 UTC

[23/24] git commit: [flex-utilities] [refs/heads/feature/pmd-5.2-language-module] - Initial commit of the PMD language module for Apache Flex

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/ff722d6f/FlexPMD/language-module/parser/parser-impl/src/main/java/org/apache/flex/pmd/parser/impl/AS3Parser.java
----------------------------------------------------------------------
diff --git a/FlexPMD/language-module/parser/parser-impl/src/main/java/org/apache/flex/pmd/parser/impl/AS3Parser.java b/FlexPMD/language-module/parser/parser-impl/src/main/java/org/apache/flex/pmd/parser/impl/AS3Parser.java
new file mode 100644
index 0000000..37d36b8
--- /dev/null
+++ b/FlexPMD/language-module/parser/parser-impl/src/main/java/org/apache/flex/pmd/parser/impl/AS3Parser.java
@@ -0,0 +1,2037 @@
+/*
+ * 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 org.apache.flex.pmd.parser.impl;
+
+import net.sourceforge.pmd.lang.Parser;
+import net.sourceforge.pmd.lang.ParserOptions;
+import net.sourceforge.pmd.lang.TokenManager;
+import net.sourceforge.pmd.lang.ast.ParseException;
+import org.apache.flex.pmd.parser.IParserNode;
+import org.apache.flex.pmd.parser.KeyWords;
+import org.apache.flex.pmd.parser.NodeKind;
+import org.apache.flex.pmd.parser.Operators;
+import org.apache.flex.pmd.parser.ast.Token;
+import org.apache.flex.pmd.parser.exceptions.NullTokenException;
+import org.apache.flex.pmd.parser.exceptions.TokenException;
+import org.apache.flex.pmd.parser.exceptions.UnExpectedTokenException;
+import org.apache.flex.pmd.parser.exceptions.UnExpectedTokenException.Position;
+import org.apache.flex.pmd.utils.FileUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author xagnetti
+ */
+public class AS3Parser implements Parser {
+
+    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(ParserOptions parserOptions) {
+        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 {
+        List<String> lines = FileUtils.readFile(new File(filePath));
+        return parseLines(filePath, lines.toArray(new String[lines.size()]));
+    }
+
+    /*
+    * (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);
+    }
+
+
+    @Override
+    public ParserOptions getParserOptions() {
+        return null;
+    }
+
+    @Override
+    public TokenManager getTokenManager(String fileName, Reader source) {
+        return null;
+    }
+
+    @Override
+    public boolean canParse() {
+        return false;
+    }
+
+    @Override
+    public net.sourceforge.pmd.lang.ast.Node parse(String fileName, Reader source) throws ParseException {
+        return null;
+    }
+
+    @Override
+    public Map<Integer, String> getSuppressMap() {
+        return null;
+    }
+
+
+    /**
+     * @return
+     */
+    /*private*/ AS3Scanner getScn() {
+        return scn;
+    }
+
+    /*private*/ 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
+     */
+    private 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
+     */
+    /*private*/ 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
+     */
+    /*private*/ 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
+     */
+    private IParserNode parseExpression() throws TokenException {
+        return parseAssignmentExpression();
+    }
+
+    /**
+     * tok is first content token
+     *
+     * @throws TokenException
+     */
+    /*private*/ 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
+     */
+    /*private*/ 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
+     */
+    /*private*/ 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
+     */
+    /*private*/ 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
+     */
+    private 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 StringBuilder result = new StringBuilder();
+
+        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 StringBuilder buffer = new StringBuilder();
+
+        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 StringBuilder nameBuffer = new StringBuilder();
+
+        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 StringBuilder buffer = new StringBuilder();
+
+        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();
+        }
+    }
+}