8075207: Nashorn parser API returns StatementTree objects in out of order
authorsundar
Mon, 16 Mar 2015 17:01:47 +0530
changeset 29536 805894cd3c6b
parent 29535 436194135f7d
child 29537 e6615d669728
8075207: Nashorn parser API returns StatementTree objects in out of order Reviewed-by: lagergren, forax, hannesw
nashorn/samples/findwith.js
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/DoWhileLoopTree.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ForInLoopTree.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/IRTranslator.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ParserImpl.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/WhileLoopTree.java
nashorn/test/script/basic/JDK-8075207.js
nashorn/test/script/nosecurity/parserapi.js.EXPECTED
--- a/nashorn/samples/findwith.js	Mon Mar 16 11:00:07 2015 +0100
+++ b/nashorn/samples/findwith.js	Mon Mar 16 17:01:47 2015 +0530
@@ -52,7 +52,6 @@
 var SimpleTreeVisitor = Java.type("jdk.nashorn.api.tree.SimpleTreeVisitorES5_1");
 
 var parser = Parser.create("-scripting", "--const-as-var");
-var protoFound = false;
 
 function checkFile(file) {
     // print("checking " + file);
@@ -92,7 +91,3 @@
 } else {
     checkFile(file);
 }
-
-if (protoFound) {
-    print("__proto__ is non-standard. Use Object.get/setPrototypeOf instead");
-}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/DoWhileLoopTree.java	Mon Mar 16 11:00:07 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/DoWhileLoopTree.java	Mon Mar 16 17:01:47 2015 +0530
@@ -44,6 +44,7 @@
      *
      * @return the condition expression
      */
+    @Override
     ExpressionTree getCondition();
 
     /**
@@ -51,5 +52,6 @@
      *
      * @return the statement
      */
+    @Override
     StatementTree getStatement();
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ForInLoopTree.java	Mon Mar 16 11:00:07 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ForInLoopTree.java	Mon Mar 16 17:01:47 2015 +0530
@@ -57,6 +57,7 @@
      *
      * @return the statement
      */
+    @Override
     StatementTree getStatement();
 
     /**
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/IRTranslator.java	Mon Mar 16 11:00:07 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/IRTranslator.java	Mon Mar 16 17:01:47 2015 +0530
@@ -25,6 +25,7 @@
 package jdk.nashorn.api.tree;
 
 import java.util.ArrayList;
+import java.util.Comparator;
 import java.util.List;
 import jdk.nashorn.internal.ir.AccessNode;
 import jdk.nashorn.internal.ir.BinaryNode;
@@ -92,7 +93,7 @@
 
         final Block body = node.getBody();
         return new CompilationUnitTreeImpl(node,
-                translateStats(body != null? body.getStatements() : null));
+                translateStats(body != null? getOrderedStatements(body.getStatements()) : null));
     }
 
     @Override
@@ -103,25 +104,7 @@
 
     @Override
     public boolean enterBlock(final Block block) {
-        // FIXME: revisit this!
-        if (block.isSynthetic()) {
-            final int statCount = block.getStatementCount();
-            switch (statCount) {
-                case 0: {
-                    final EmptyNode emptyNode = new EmptyNode(-1, block.getToken(), block.getFinish());
-                    curStat = new EmptyStatementTreeImpl(emptyNode);
-                    return false;
-                }
-                case 1: {
-                    curStat = translateStat(block.getStatements().get(0));
-                    return false;
-                }
-            }
-        }
-
-        curStat = new BlockTreeImpl(block,
-            translateStats(block.getStatements()));
-        return false;
+        return handleBlock(block, false);
     }
 
     @Override
@@ -245,7 +228,7 @@
 
         final List<? extends ExpressionTree> paramTrees
                     = translateExprs(functionNode.getParameters());
-        final BlockTree blockTree = (BlockTree) translateBlock(functionNode.getBody());
+        final BlockTree blockTree = (BlockTree) translateBlock(functionNode.getBody(), true);
         curExpr = new FunctionExpressionTreeImpl(functionNode, paramTrees, blockTree);
 
         return false;
@@ -420,7 +403,7 @@
 
             final List<? extends ExpressionTree> paramTrees
                     = translateExprs(funcNode.getParameters());
-            final BlockTree blockTree = (BlockTree) translateBlock(funcNode.getBody());
+            final BlockTree blockTree = (BlockTree) translateBlock(funcNode.getBody(), true);
             curStat = new FunctionDeclarationTreeImpl(varNode, paramTrees, blockTree);
         } else {
             curStat = new VariableTreeImpl(varNode, translateExpr(initNode));
@@ -453,14 +436,51 @@
     }
 
     private StatementTree translateBlock(final Block blockNode) {
+        return translateBlock(blockNode, false);
+    }
+
+    private StatementTree translateBlock(final Block blockNode, final boolean sortStats) {
         if (blockNode == null) {
             return null;
         }
         curStat = null;
-        blockNode.accept(this);
+        handleBlock(blockNode, sortStats);
         return curStat;
     }
 
+    private boolean handleBlock(final Block block, final boolean sortStats) {
+        // FIXME: revisit this!
+        if (block.isSynthetic()) {
+            final int statCount = block.getStatementCount();
+            switch (statCount) {
+                case 0: {
+                    final EmptyNode emptyNode = new EmptyNode(-1, block.getToken(), block.getFinish());
+                    curStat = new EmptyStatementTreeImpl(emptyNode);
+                    return false;
+                }
+                case 1: {
+                    curStat = translateStat(block.getStatements().get(0));
+                    return false;
+                }
+                default: {
+                    // fall through
+                    break;
+                }
+            }
+        }
+
+        final List<? extends Statement> stats = block.getStatements();
+        curStat = new BlockTreeImpl(block,
+            translateStats(sortStats? getOrderedStatements(stats) : stats));
+        return false;
+    }
+
+    private List<? extends Statement> getOrderedStatements(final List<? extends Statement> stats) {
+        final List<? extends Statement> statList = new ArrayList<>(stats);
+        statList.sort(Comparator.comparingInt(Node::getStart));
+        return statList;
+    }
+
     private List<? extends StatementTree> translateStats(final List<? extends Statement> stats) {
         if (stats == null) {
             return null;
@@ -511,7 +531,7 @@
         return curStat;
     }
 
-    private IdentifierTree translateIdent(final IdentNode ident) {
+    private static IdentifierTree translateIdent(final IdentNode ident) {
         return new IdentifierTreeImpl(ident);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ParserImpl.java	Mon Mar 16 11:00:07 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ParserImpl.java	Mon Mar 16 17:01:47 2015 +0530
@@ -139,7 +139,7 @@
         }
     }
 
-    private CompilationUnitTree translate(final FunctionNode node) {
+    private static CompilationUnitTree translate(final FunctionNode node) {
         return new IRTranslator().translate(node);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/WhileLoopTree.java	Mon Mar 16 11:00:07 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/WhileLoopTree.java	Mon Mar 16 17:01:47 2015 +0530
@@ -43,6 +43,7 @@
      *
      * @return the condition expression
      */
+    @Override
     ExpressionTree getCondition();
 
     /**
@@ -50,5 +51,6 @@
      *
      * @return the statement contained
      */
+    @Override
     StatementTree getStatement();
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8075207.js	Mon Mar 16 17:01:47 2015 +0530
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8075207: Nashorn parser API returns StatementTree objects in out of order
+ *
+ * @test
+ * @option -scripting
+ * @run
+ */
+
+var Parser = Java.type("jdk.nashorn.api.tree.Parser");
+var ExpressionStatementTree = Java.type("jdk.nashorn.api.tree.ExpressionStatementTree");
+var FunctionDeclarationTree = Java.type("jdk.nashorn.api.tree.FunctionDeclarationTree");
+var VariableTree = Java.type("jdk.nashorn.api.tree.VariableTree");
+
+var parser = Parser.create();
+
+var ast = parser.parse("hello.js", <<CODE
+
+var hello = 'hello';
+
+function print_hello() {
+    var x = 2;
+    print(hello);
+    function inner_func() {}
+    var y = function() {
+        var PI = Math.PI;
+        function inner2() {}
+        var E = Math.E;
+    }
+}
+
+var hello = "hello 2";
+
+CODE, print);
+
+var stats = ast.sourceElements;
+Assert.assertTrue(stats.get(0) instanceof VariableTree);
+Assert.assertTrue(stats.get(1) instanceof FunctionDeclarationTree);
+Assert.assertTrue(stats.get(2) instanceof VariableTree);
+
+var print_hello = stats.get(1);
+Assert.assertEquals(print_hello.name, "print_hello");
+var print_hello_stats = print_hello.body.statements;
+Assert.assertTrue(print_hello_stats.get(0) instanceof VariableTree);
+Assert.assertTrue(print_hello_stats.get(1) instanceof ExpressionStatementTree);
+Assert.assertTrue(print_hello_stats.get(2) instanceof FunctionDeclarationTree);
+Assert.assertTrue(print_hello_stats.get(3) instanceof VariableTree);
+
+var anonFunc = print_hello_stats.get(3).initializer;
+var anonFunc_stats = anonFunc.body.statements;
+Assert.assertTrue(anonFunc_stats.get(0) instanceof VariableTree);
+Assert.assertTrue(anonFunc_stats.get(1) instanceof FunctionDeclarationTree);
+Assert.assertTrue(anonFunc_stats.get(2) instanceof VariableTree);
+
--- a/nashorn/test/script/nosecurity/parserapi.js.EXPECTED	Mon Mar 16 11:00:07 2015 +0100
+++ b/nashorn/test/script/nosecurity/parserapi.js.EXPECTED	Mon Mar 16 17:01:47 2015 +0530
@@ -1364,32 +1364,6 @@
       ]
     },
     {
-      "endPosition": "1380",
-      "kind": "FUNCTION",
-      "name": "test",
-      "body": {
-        "endPosition": "1377",
-        "kind": "BLOCK",
-        "statements": [
-          {
-            "expression": {
-              "endPosition": "1377",
-              "kind": "STRING_LITERAL",
-              "value": "use strict",
-              "startPosition": "1367"
-            },
-            "endPosition": "1377",
-            "kind": "EXPRESSION_STATEMENT",
-            "startPosition": "1367"
-          }
-        ],
-        "startPosition": "1364"
-      },
-      "strict": "true",
-      "startPosition": "1348",
-      "parameters": []
-    },
-    {
       "endPosition": "1282",
       "kind": "VARIABLE",
       "name": "hello",
@@ -1495,6 +1469,32 @@
       "endPosition": "1347",
       "kind": "EXPRESSION_STATEMENT",
       "startPosition": "1333"
+    },
+    {
+      "endPosition": "1380",
+      "kind": "FUNCTION",
+      "name": "test",
+      "body": {
+        "endPosition": "1377",
+        "kind": "BLOCK",
+        "statements": [
+          {
+            "expression": {
+              "endPosition": "1377",
+              "kind": "STRING_LITERAL",
+              "value": "use strict",
+              "startPosition": "1367"
+            },
+            "endPosition": "1377",
+            "kind": "EXPRESSION_STATEMENT",
+            "startPosition": "1367"
+          }
+        ],
+        "startPosition": "1364"
+      },
+      "strict": "true",
+      "startPosition": "1348",
+      "parameters": []
     }
   ],
   "sourceName": "parsertests/functions.js",
@@ -3976,6 +3976,17 @@
   "kind": "COMPILATION_UNIT",
   "sourceElements": [
     {
+      "expression": {
+        "endPosition": "1133",
+        "kind": "STRING_LITERAL",
+        "value": "use strict",
+        "startPosition": "1123"
+      },
+      "endPosition": "1133",
+      "kind": "EXPRESSION_STATEMENT",
+      "startPosition": "1123"
+    },
+    {
       "endPosition": "1165",
       "kind": "FUNCTION",
       "name": "f",
@@ -4000,17 +4011,6 @@
       "strict": "true",
       "startPosition": "1136",
       "parameters": []
-    },
-    {
-      "expression": {
-        "endPosition": "1133",
-        "kind": "STRING_LITERAL",
-        "value": "use strict",
-        "startPosition": "1123"
-      },
-      "endPosition": "1133",
-      "kind": "EXPRESSION_STATEMENT",
-      "startPosition": "1123"
     }
   ],
   "sourceName": "parsertests/useStrict.js",
@@ -4919,808 +4919,6 @@
       "parameters": []
     },
     {
-      "endPosition": "3598",
-      "kind": "FUNCTION",
-      "name": "processFiles",
-      "body": {
-        "endPosition": "3555",
-        "kind": "BLOCK",
-        "statements": [
-          {
-            "endPosition": "2938",
-            "kind": "VARIABLE",
-            "name": "File",
-            "startPosition": "2906",
-            "initializer": {
-              "endPosition": "2938",
-              "kind": "FUNCTION_INVOCATION",
-              "functionSelect": {
-                "identifier": "type",
-                "expression": {
-                  "endPosition": "2917",
-                  "kind": "IDENTIFIER",
-                  "name": "Java",
-                  "startPosition": "2913"
-                },
-                "endPosition": "2922",
-                "kind": "MEMBER_SELECT",
-                "startPosition": "2913"
-              },
-              "arguments": [
-                {
-                  "endPosition": "2936",
-                  "kind": "STRING_LITERAL",
-                  "value": "java.io.File",
-                  "startPosition": "2924"
-                }
-              ],
-              "startPosition": "2913"
-            }
-          },
-          {
-            "endPosition": "2993",
-            "kind": "VARIABLE",
-            "name": "files",
-            "startPosition": "2947",
-            "initializer": {
-              "endPosition": "2993",
-              "kind": "FUNCTION_INVOCATION",
-              "functionSelect": {
-                "identifier": "listFiles",
-                "expression": {
-                  "constructorExpression": {
-                    "endPosition": "2981",
-                    "kind": "FUNCTION_INVOCATION",
-                    "functionSelect": {
-                      "endPosition": "2963",
-                      "kind": "IDENTIFIER",
-                      "name": "File",
-                      "startPosition": "2959"
-                    },
-                    "arguments": [
-                      {
-                        "leftOperand": {
-                          "endPosition": "2971",
-                          "kind": "IDENTIFIER",
-                          "name": "__DIR__",
-                          "startPosition": "2964"
-                        },
-                        "endPosition": "2980",
-                        "kind": "PLUS",
-                        "rightOperand": {
-                          "endPosition": "2980",
-                          "kind": "IDENTIFIER",
-                          "name": "subdir",
-                          "startPosition": "2974"
-                        },
-                        "startPosition": "2964"
-                      }
-                    ],
-                    "startPosition": "2959"
-                  },
-                  "endPosition": "2981",
-                  "kind": "NEW",
-                  "startPosition": "2955"
-                },
-                "endPosition": "2991",
-                "kind": "MEMBER_SELECT",
-                "startPosition": "2955"
-              },
-              "arguments": [],
-              "startPosition": "2955"
-            }
-          },
-          {
-            "expression": {
-              "endPosition": "3026",
-              "kind": "FUNCTION_INVOCATION",
-              "functionSelect": {
-                "identifier": "sort",
-                "expression": {
-                  "identifier": "Arrays",
-                  "expression": {
-                    "identifier": "util",
-                    "expression": {
-                      "endPosition": "3002",
-                      "kind": "IDENTIFIER",
-                      "name": "java",
-                      "startPosition": "2998"
-                    },
-                    "endPosition": "3007",
-                    "kind": "MEMBER_SELECT",
-                    "startPosition": "2998"
-                  },
-                  "endPosition": "3014",
-                  "kind": "MEMBER_SELECT",
-                  "startPosition": "2998"
-                },
-                "endPosition": "3019",
-                "kind": "MEMBER_SELECT",
-                "startPosition": "2998"
-              },
-              "arguments": [
-                {
-                  "endPosition": "3025",
-                  "kind": "IDENTIFIER",
-                  "name": "files",
-                  "startPosition": "3020"
-                }
-              ],
-              "startPosition": "2998"
-            },
-            "endPosition": "3026",
-            "kind": "EXPRESSION_STATEMENT",
-            "startPosition": "2998"
-          },
-          {
-            "endPosition": "3049",
-            "kind": "VARIABLE",
-            "name": "file",
-            "startPosition": "3045"
-          },
-          {
-            "expression": {
-              "endPosition": "3058",
-              "kind": "IDENTIFIER",
-              "name": "files",
-              "startPosition": "3053"
-            },
-            "endPosition": "3555",
-            "kind": "FOR_IN_LOOP",
-            "forEach": "true",
-            "variable": {
-              "endPosition": "3049",
-              "kind": "IDENTIFIER",
-              "name": "file",
-              "startPosition": "3045"
-            },
-            "statement": {
-              "endPosition": "3555",
-              "kind": "BLOCK",
-              "statements": [
-                {
-                  "condition": {
-                    "endPosition": "3098",
-                    "kind": "FUNCTION_INVOCATION",
-                    "functionSelect": {
-                      "identifier": "endsWith",
-                      "expression": {
-                        "identifier": "name",
-                        "expression": {
-                          "endPosition": "3077",
-                          "kind": "IDENTIFIER",
-                          "name": "file",
-                          "startPosition": "3073"
-                        },
-                        "endPosition": "3082",
-                        "kind": "MEMBER_SELECT",
-                        "startPosition": "3073"
-                      },
-                      "endPosition": "3091",
-                      "kind": "MEMBER_SELECT",
-                      "startPosition": "3073"
-                    },
-                    "arguments": [
-                      {
-                        "endPosition": "3096",
-                        "kind": "STRING_LITERAL",
-                        "value": ".js",
-                        "startPosition": "3093"
-                      }
-                    ],
-                    "startPosition": "3073"
-                  },
-                  "endPosition": "3550",
-                  "kind": "IF",
-                  "startPosition": "3069",
-                  "thenStatement": {
-                    "endPosition": "3550",
-                    "kind": "BLOCK",
-                    "statements": [
-                      {
-                        "endPosition": "3141",
-                        "kind": "VARIABLE",
-                        "name": "script",
-                        "startPosition": "3117",
-                        "initializer": {
-                          "endPosition": "3141",
-                          "kind": "FUNCTION_INVOCATION",
-                          "functionSelect": {
-                            "endPosition": "3135",
-                            "kind": "IDENTIFIER",
-                            "name": "readFully",
-                            "startPosition": "3126"
-                          },
-                          "arguments": [
-                            {
-                              "endPosition": "3140",
-                              "kind": "IDENTIFIER",
-                              "name": "file",
-                              "startPosition": "3136"
-                            }
-                          ],
-                          "startPosition": "3126"
-                        }
-                      },
-                      {
-                        "endPosition": "3179",
-                        "kind": "VARIABLE",
-                        "name": "parser",
-                        "startPosition": "3158",
-                        "initializer": {
-                          "constructorExpression": {
-                            "endPosition": "3179",
-                            "kind": "FUNCTION_INVOCATION",
-                            "functionSelect": {
-                              "endPosition": "3177",
-                              "kind": "IDENTIFIER",
-                              "name": "Parser",
-                              "startPosition": "3171"
-                            },
-                            "arguments": [],
-                            "startPosition": "3171"
-                          },
-                          "endPosition": "3179",
-                          "kind": "NEW",
-                          "startPosition": "3167"
-                        }
-                      },
-                      {
-                        "endPosition": "3415",
-                        "kind": "VARIABLE",
-                        "name": "tree",
-                        "startPosition": "3196",
-                        "initializer": {
-                          "endPosition": "3415",
-                          "kind": "FUNCTION_INVOCATION",
-                          "functionSelect": {
-                            "identifier": "parse",
-                            "expression": {
-                              "endPosition": "3209",
-                              "kind": "IDENTIFIER",
-                              "name": "parser",
-                              "startPosition": "3203"
-                            },
-                            "endPosition": "3215",
-                            "kind": "MEMBER_SELECT",
-                            "startPosition": "3203"
-                          },
-                          "arguments": [
-                            {
-                              "leftOperand": {
-                                "leftOperand": {
-                                  "endPosition": "3222",
-                                  "kind": "IDENTIFIER",
-                                  "name": "subdir",
-                                  "startPosition": "3216"
-                                },
-                                "endPosition": "3227",
-                                "kind": "PLUS",
-                                "rightOperand": {
-                                  "endPosition": "3227",
-                                  "kind": "STRING_LITERAL",
-                                  "value": "/",
-                                  "startPosition": "3226"
-                                },
-                                "startPosition": "3216"
-                              },
-                              "endPosition": "3240",
-                              "kind": "PLUS",
-                              "rightOperand": {
-                                "identifier": "name",
-                                "expression": {
-                                  "endPosition": "3235",
-                                  "kind": "IDENTIFIER",
-                                  "name": "file",
-                                  "startPosition": "3231"
-                                },
-                                "endPosition": "3240",
-                                "kind": "MEMBER_SELECT",
-                                "startPosition": "3231"
-                              },
-                              "startPosition": "3216"
-                            },
-                            {
-                              "endPosition": "3248",
-                              "kind": "IDENTIFIER",
-                              "name": "script",
-                              "startPosition": "3242"
-                            },
-                            {
-                              "endPosition": "3286",
-                              "kind": "FUNCTION_EXPRESSION",
-                              "body": {
-                                "endPosition": "3397",
-                                "kind": "BLOCK",
-                                "statements": [
-                                  {
-                                    "expression": {
-                                      "endPosition": "3365",
-                                      "kind": "FUNCTION_INVOCATION",
-                                      "functionSelect": {
-                                        "endPosition": "3312",
-                                        "kind": "IDENTIFIER",
-                                        "name": "print",
-                                        "startPosition": "3307"
-                                      },
-                                      "arguments": [
-                                        {
-                                          "endPosition": "3364",
-                                          "kind": "FUNCTION_INVOCATION",
-                                          "functionSelect": {
-                                            "identifier": "stringify",
-                                            "expression": {
-                                              "endPosition": "3317",
-                                              "kind": "IDENTIFIER",
-                                              "name": "JSON",
-                                              "startPosition": "3313"
-                                            },
-                                            "endPosition": "3327",
-                                            "kind": "MEMBER_SELECT",
-                                            "startPosition": "3313"
-                                          },
-                                          "arguments": [
-                                            {
-                                              "endPosition": "3354",
-                                              "kind": "FUNCTION_INVOCATION",
-                                              "functionSelect": {
-                                                "identifier": "convert",
-                                                "expression": {
-                                                  "endPosition": "3334",
-                                                  "kind": "IDENTIFIER",
-                                                  "name": "parser",
-                                                  "startPosition": "3328"
-                                                },
-                                                "endPosition": "3342",
-                                                "kind": "MEMBER_SELECT",
-                                                "startPosition": "3328"
-                                              },
-                                              "arguments": [
-                                                {
-                                                  "endPosition": "3353",
-                                                  "kind": "IDENTIFIER",
-                                                  "name": "diagnostic",
-                                                  "startPosition": "3343"
-                                                }
-                                              ],
-                                              "startPosition": "3328"
-                                            },
-                                            {
-                                              "endPosition": "3360",
-                                              "kind": "NULL_LITERAL",
-                                              "startPosition": "3356"
-                                            },
-                                            {
-                                              "endPosition": "3363",
-                                              "kind": "NUMBER_LITERAL",
-                                              "value": "2",
-                                              "startPosition": "3362"
-                                            }
-                                          ],
-                                          "startPosition": "3313"
-                                        }
-                                      ],
-                                      "startPosition": "3307"
-                                    },
-                                    "endPosition": "3365",
-                                    "kind": "EXPRESSION_STATEMENT",
-                                    "startPosition": "3307"
-                                  },
-                                  {
-                                    "expression": {
-                                      "endPosition": "3396",
-                                      "kind": "FUNCTION_INVOCATION",
-                                      "functionSelect": {
-                                        "endPosition": "3391",
-                                        "kind": "IDENTIFIER",
-                                        "name": "print",
-                                        "startPosition": "3386"
-                                      },
-                                      "arguments": [
-                                        {
-                                          "endPosition": "3394",
-                                          "kind": "STRING_LITERAL",
-                                          "value": ",",
-                                          "startPosition": "3393"
-                                        }
-                                      ],
-                                      "startPosition": "3386"
-                                    },
-                                    "endPosition": "3396",
-                                    "kind": "EXPRESSION_STATEMENT",
-                                    "startPosition": "3386"
-                                  }
-                                ],
-                                "startPosition": "3286"
-                              },
-                              "strict": "false",
-                              "startPosition": "3286",
-                              "parameters": [
-                                {
-                                  "endPosition": "3284",
-                                  "kind": "IDENTIFIER",
-                                  "name": "diagnostic",
-                                  "startPosition": "3274"
-                                }
-                              ]
-                            }
-                          ],
-                          "startPosition": "3203"
-                        }
-                      },
-                      {
-                        "condition": {
-                          "leftOperand": {
-                            "endPosition": "3437",
-                            "kind": "IDENTIFIER",
-                            "name": "tree",
-                            "startPosition": "3433"
-                          },
-                          "endPosition": "3445",
-                          "kind": "NOT_EQUAL_TO",
-                          "rightOperand": {
-                            "endPosition": "3445",
-                            "kind": "NULL_LITERAL",
-                            "startPosition": "3441"
-                          },
-                          "startPosition": "3433"
-                        },
-                        "endPosition": "3541",
-                        "kind": "IF",
-                        "startPosition": "3429",
-                        "thenStatement": {
-                          "endPosition": "3541",
-                          "kind": "BLOCK",
-                          "statements": [
-                            {
-                              "expression": {
-                                "endPosition": "3500",
-                                "kind": "FUNCTION_INVOCATION",
-                                "functionSelect": {
-                                  "endPosition": "3469",
-                                  "kind": "IDENTIFIER",
-                                  "name": "print",
-                                  "startPosition": "3464"
-                                },
-                                "arguments": [
-                                  {
-                                    "endPosition": "3499",
-                                    "kind": "FUNCTION_INVOCATION",
-                                    "functionSelect": {
-                                      "identifier": "stringify",
-                                      "expression": {
-                                        "endPosition": "3474",
-                                        "kind": "IDENTIFIER",
-                                        "name": "JSON",
-                                        "startPosition": "3470"
-                                      },
-                                      "endPosition": "3484",
-                                      "kind": "MEMBER_SELECT",
-                                      "startPosition": "3470"
-                                    },
-                                    "arguments": [
-                                      {
-                                        "endPosition": "3489",
-                                        "kind": "IDENTIFIER",
-                                        "name": "tree",
-                                        "startPosition": "3485"
-                                      },
-                                      {
-                                        "endPosition": "3495",
-                                        "kind": "NULL_LITERAL",
-                                        "startPosition": "3491"
-                                      },
-                                      {
-                                        "endPosition": "3498",
-                                        "kind": "NUMBER_LITERAL",
-                                        "value": "2",
-                                        "startPosition": "3497"
-                                      }
-                                    ],
-                                    "startPosition": "3470"
-                                  }
-                                ],
-                                "startPosition": "3464"
-                              },
-                              "endPosition": "3500",
-                              "kind": "EXPRESSION_STATEMENT",
-                              "startPosition": "3464"
-                            },
-                            {
-                              "expression": {
-                                "endPosition": "3527",
-                                "kind": "FUNCTION_INVOCATION",
-                                "functionSelect": {
-                                  "endPosition": "3522",
-                                  "kind": "IDENTIFIER",
-                                  "name": "print",
-                                  "startPosition": "3517"
-                                },
-                                "arguments": [
-                                  {
-                                    "endPosition": "3525",
-                                    "kind": "STRING_LITERAL",
-                                    "value": ",",
-                                    "startPosition": "3524"
-                                  }
-                                ],
-                                "startPosition": "3517"
-                              },
-                              "endPosition": "3527",
-                              "kind": "EXPRESSION_STATEMENT",
-                              "startPosition": "3517"
-                            }
-                          ],
-                          "startPosition": "3447"
-                        }
-                      }
-                    ],
-                    "startPosition": "3100"
-                  }
-                }
-              ],
-              "startPosition": "3060"
-            },
-            "startPosition": "3031"
-          }
-        ],
-        "startPosition": "2897"
-      },
-      "strict": "false",
-      "startPosition": "2867",
-      "parameters": [
-        {
-          "endPosition": "2895",
-          "kind": "IDENTIFIER",
-          "name": "subdir",
-          "startPosition": "2889"
-        }
-      ]
-    },
-    {
-      "endPosition": "3901",
-      "kind": "FUNCTION",
-      "name": "main",
-      "body": {
-        "endPosition": "3899",
-        "kind": "BLOCK",
-        "statements": [
-          {
-            "expression": {
-              "endPosition": "3631",
-              "kind": "FUNCTION_INVOCATION",
-              "functionSelect": {
-                "endPosition": "3626",
-                "kind": "IDENTIFIER",
-                "name": "print",
-                "startPosition": "3621"
-              },
-              "arguments": [
-                {
-                  "endPosition": "3629",
-                  "kind": "STRING_LITERAL",
-                  "value": "[",
-                  "startPosition": "3628"
-                }
-              ],
-              "startPosition": "3621"
-            },
-            "endPosition": "3631",
-            "kind": "EXPRESSION_STATEMENT",
-            "startPosition": "3621"
-          },
-          {
-            "expression": {
-              "endPosition": "3665",
-              "kind": "FUNCTION_INVOCATION",
-              "functionSelect": {
-                "endPosition": "3650",
-                "kind": "IDENTIFIER",
-                "name": "processFiles",
-                "startPosition": "3638"
-              },
-              "arguments": [
-                {
-                  "endPosition": "3663",
-                  "kind": "STRING_LITERAL",
-                  "value": "parsertests",
-                  "startPosition": "3652"
-                }
-              ],
-              "startPosition": "3638"
-            },
-            "endPosition": "3665",
-            "kind": "EXPRESSION_STATEMENT",
-            "startPosition": "3638"
-          },
-          {
-            "expression": {
-              "endPosition": "3706",
-              "kind": "FUNCTION_INVOCATION",
-              "functionSelect": {
-                "endPosition": "3683",
-                "kind": "IDENTIFIER",
-                "name": "processFiles",
-                "startPosition": "3671"
-              },
-              "arguments": [
-                {
-                  "endPosition": "3704",
-                  "kind": "STRING_LITERAL",
-                  "value": "parsernegativetests",
-                  "startPosition": "3685"
-                }
-              ],
-              "startPosition": "3671"
-            },
-            "endPosition": "3706",
-            "kind": "EXPRESSION_STATEMENT",
-            "startPosition": "3671"
-          },
-          {
-            "endPosition": "3775",
-            "kind": "VARIABLE",
-            "name": "script",
-            "startPosition": "3747",
-            "initializer": {
-              "endPosition": "3775",
-              "kind": "FUNCTION_INVOCATION",
-              "functionSelect": {
-                "endPosition": "3765",
-                "kind": "IDENTIFIER",
-                "name": "readFully",
-                "startPosition": "3756"
-              },
-              "arguments": [
-                {
-                  "endPosition": "3774",
-                  "kind": "IDENTIFIER",
-                  "name": "__FILE__",
-                  "startPosition": "3766"
-                }
-              ],
-              "startPosition": "3756"
-            }
-          },
-          {
-            "endPosition": "3840",
-            "kind": "VARIABLE",
-            "name": "tree",
-            "startPosition": "3785",
-            "initializer": {
-              "endPosition": "3840",
-              "kind": "FUNCTION_INVOCATION",
-              "functionSelect": {
-                "identifier": "parse",
-                "expression": {
-                  "constructorExpression": {
-                    "endPosition": "3804",
-                    "kind": "FUNCTION_INVOCATION",
-                    "functionSelect": {
-                      "endPosition": "3802",
-                      "kind": "IDENTIFIER",
-                      "name": "Parser",
-                      "startPosition": "3796"
-                    },
-                    "arguments": [],
-                    "startPosition": "3796"
-                  },
-                  "endPosition": "3804",
-                  "kind": "NEW",
-                  "startPosition": "3792"
-                },
-                "endPosition": "3810",
-                "kind": "MEMBER_SELECT",
-                "startPosition": "3792"
-              },
-              "arguments": [
-                {
-                  "endPosition": "3824",
-                  "kind": "STRING_LITERAL",
-                  "value": "parserapi.js",
-                  "startPosition": "3812"
-                },
-                {
-                  "endPosition": "3833",
-                  "kind": "IDENTIFIER",
-                  "name": "script",
-                  "startPosition": "3827"
-                },
-                {
-                  "endPosition": "3839",
-                  "kind": "NULL_LITERAL",
-                  "startPosition": "3835"
-                }
-              ],
-              "startPosition": "3792"
-            }
-          },
-          {
-            "expression": {
-              "endPosition": "3882",
-              "kind": "FUNCTION_INVOCATION",
-              "functionSelect": {
-                "endPosition": "3851",
-                "kind": "IDENTIFIER",
-                "name": "print",
-                "startPosition": "3846"
-              },
-              "arguments": [
-                {
-                  "endPosition": "3881",
-                  "kind": "FUNCTION_INVOCATION",
-                  "functionSelect": {
-                    "identifier": "stringify",
-                    "expression": {
-                      "endPosition": "3856",
-                      "kind": "IDENTIFIER",
-                      "name": "JSON",
-                      "startPosition": "3852"
-                    },
-                    "endPosition": "3866",
-                    "kind": "MEMBER_SELECT",
-                    "startPosition": "3852"
-                  },
-                  "arguments": [
-                    {
-                      "endPosition": "3871",
-                      "kind": "IDENTIFIER",
-                      "name": "tree",
-                      "startPosition": "3867"
-                    },
-                    {
-                      "endPosition": "3877",
-                      "kind": "NULL_LITERAL",
-                      "startPosition": "3873"
-                    },
-                    {
-                      "endPosition": "3880",
-                      "kind": "NUMBER_LITERAL",
-                      "value": "2",
-                      "startPosition": "3879"
-                    }
-                  ],
-                  "startPosition": "3852"
-                }
-              ],
-              "startPosition": "3846"
-            },
-            "endPosition": "3882",
-            "kind": "EXPRESSION_STATEMENT",
-            "startPosition": "3846"
-          },
-          {
-            "expression": {
-              "endPosition": "3898",
-              "kind": "FUNCTION_INVOCATION",
-              "functionSelect": {
-                "endPosition": "3893",
-                "kind": "IDENTIFIER",
-                "name": "print",
-                "startPosition": "3888"
-              },
-              "arguments": [
-                {
-                  "endPosition": "3896",
-                  "kind": "STRING_LITERAL",
-                  "value": "]",
-                  "startPosition": "3895"
-                }
-              ],
-              "startPosition": "3888"
-            },
-            "endPosition": "3898",
-            "kind": "EXPRESSION_STATEMENT",
-            "startPosition": "3888"
-          }
-        ],
-        "startPosition": "3615"
-      },
-      "strict": "false",
-      "startPosition": "3599",
-      "parameters": []
-    },
-    {
       "expression": {
         "expression": {
           "endPosition": "1305",
@@ -6345,12 +5543,6 @@
                 }
               },
               {
-                "endPosition": "2170",
-                "kind": "VARIABLE",
-                "name": "i",
-                "startPosition": "2169"
-              },
-              {
                 "expression": {
                   "endPosition": "2177",
                   "kind": "IDENTIFIER",
@@ -6940,6 +6132,12 @@
                 "startPosition": "2160"
               },
               {
+                "endPosition": "2170",
+                "kind": "VARIABLE",
+                "name": "i",
+                "startPosition": "2169"
+              },
+              {
                 "expression": {
                   "endPosition": "2862",
                   "kind": "IDENTIFIER",
@@ -6991,6 +6189,808 @@
       "startPosition": "1972"
     },
     {
+      "endPosition": "3598",
+      "kind": "FUNCTION",
+      "name": "processFiles",
+      "body": {
+        "endPosition": "3555",
+        "kind": "BLOCK",
+        "statements": [
+          {
+            "endPosition": "2938",
+            "kind": "VARIABLE",
+            "name": "File",
+            "startPosition": "2906",
+            "initializer": {
+              "endPosition": "2938",
+              "kind": "FUNCTION_INVOCATION",
+              "functionSelect": {
+                "identifier": "type",
+                "expression": {
+                  "endPosition": "2917",
+                  "kind": "IDENTIFIER",
+                  "name": "Java",
+                  "startPosition": "2913"
+                },
+                "endPosition": "2922",
+                "kind": "MEMBER_SELECT",
+                "startPosition": "2913"
+              },
+              "arguments": [
+                {
+                  "endPosition": "2936",
+                  "kind": "STRING_LITERAL",
+                  "value": "java.io.File",
+                  "startPosition": "2924"
+                }
+              ],
+              "startPosition": "2913"
+            }
+          },
+          {
+            "endPosition": "2993",
+            "kind": "VARIABLE",
+            "name": "files",
+            "startPosition": "2947",
+            "initializer": {
+              "endPosition": "2993",
+              "kind": "FUNCTION_INVOCATION",
+              "functionSelect": {
+                "identifier": "listFiles",
+                "expression": {
+                  "constructorExpression": {
+                    "endPosition": "2981",
+                    "kind": "FUNCTION_INVOCATION",
+                    "functionSelect": {
+                      "endPosition": "2963",
+                      "kind": "IDENTIFIER",
+                      "name": "File",
+                      "startPosition": "2959"
+                    },
+                    "arguments": [
+                      {
+                        "leftOperand": {
+                          "endPosition": "2971",
+                          "kind": "IDENTIFIER",
+                          "name": "__DIR__",
+                          "startPosition": "2964"
+                        },
+                        "endPosition": "2980",
+                        "kind": "PLUS",
+                        "rightOperand": {
+                          "endPosition": "2980",
+                          "kind": "IDENTIFIER",
+                          "name": "subdir",
+                          "startPosition": "2974"
+                        },
+                        "startPosition": "2964"
+                      }
+                    ],
+                    "startPosition": "2959"
+                  },
+                  "endPosition": "2981",
+                  "kind": "NEW",
+                  "startPosition": "2955"
+                },
+                "endPosition": "2991",
+                "kind": "MEMBER_SELECT",
+                "startPosition": "2955"
+              },
+              "arguments": [],
+              "startPosition": "2955"
+            }
+          },
+          {
+            "expression": {
+              "endPosition": "3026",
+              "kind": "FUNCTION_INVOCATION",
+              "functionSelect": {
+                "identifier": "sort",
+                "expression": {
+                  "identifier": "Arrays",
+                  "expression": {
+                    "identifier": "util",
+                    "expression": {
+                      "endPosition": "3002",
+                      "kind": "IDENTIFIER",
+                      "name": "java",
+                      "startPosition": "2998"
+                    },
+                    "endPosition": "3007",
+                    "kind": "MEMBER_SELECT",
+                    "startPosition": "2998"
+                  },
+                  "endPosition": "3014",
+                  "kind": "MEMBER_SELECT",
+                  "startPosition": "2998"
+                },
+                "endPosition": "3019",
+                "kind": "MEMBER_SELECT",
+                "startPosition": "2998"
+              },
+              "arguments": [
+                {
+                  "endPosition": "3025",
+                  "kind": "IDENTIFIER",
+                  "name": "files",
+                  "startPosition": "3020"
+                }
+              ],
+              "startPosition": "2998"
+            },
+            "endPosition": "3026",
+            "kind": "EXPRESSION_STATEMENT",
+            "startPosition": "2998"
+          },
+          {
+            "expression": {
+              "endPosition": "3058",
+              "kind": "IDENTIFIER",
+              "name": "files",
+              "startPosition": "3053"
+            },
+            "endPosition": "3555",
+            "kind": "FOR_IN_LOOP",
+            "forEach": "true",
+            "variable": {
+              "endPosition": "3049",
+              "kind": "IDENTIFIER",
+              "name": "file",
+              "startPosition": "3045"
+            },
+            "statement": {
+              "endPosition": "3555",
+              "kind": "BLOCK",
+              "statements": [
+                {
+                  "condition": {
+                    "endPosition": "3098",
+                    "kind": "FUNCTION_INVOCATION",
+                    "functionSelect": {
+                      "identifier": "endsWith",
+                      "expression": {
+                        "identifier": "name",
+                        "expression": {
+                          "endPosition": "3077",
+                          "kind": "IDENTIFIER",
+                          "name": "file",
+                          "startPosition": "3073"
+                        },
+                        "endPosition": "3082",
+                        "kind": "MEMBER_SELECT",
+                        "startPosition": "3073"
+                      },
+                      "endPosition": "3091",
+                      "kind": "MEMBER_SELECT",
+                      "startPosition": "3073"
+                    },
+                    "arguments": [
+                      {
+                        "endPosition": "3096",
+                        "kind": "STRING_LITERAL",
+                        "value": ".js",
+                        "startPosition": "3093"
+                      }
+                    ],
+                    "startPosition": "3073"
+                  },
+                  "endPosition": "3550",
+                  "kind": "IF",
+                  "startPosition": "3069",
+                  "thenStatement": {
+                    "endPosition": "3550",
+                    "kind": "BLOCK",
+                    "statements": [
+                      {
+                        "endPosition": "3141",
+                        "kind": "VARIABLE",
+                        "name": "script",
+                        "startPosition": "3117",
+                        "initializer": {
+                          "endPosition": "3141",
+                          "kind": "FUNCTION_INVOCATION",
+                          "functionSelect": {
+                            "endPosition": "3135",
+                            "kind": "IDENTIFIER",
+                            "name": "readFully",
+                            "startPosition": "3126"
+                          },
+                          "arguments": [
+                            {
+                              "endPosition": "3140",
+                              "kind": "IDENTIFIER",
+                              "name": "file",
+                              "startPosition": "3136"
+                            }
+                          ],
+                          "startPosition": "3126"
+                        }
+                      },
+                      {
+                        "endPosition": "3179",
+                        "kind": "VARIABLE",
+                        "name": "parser",
+                        "startPosition": "3158",
+                        "initializer": {
+                          "constructorExpression": {
+                            "endPosition": "3179",
+                            "kind": "FUNCTION_INVOCATION",
+                            "functionSelect": {
+                              "endPosition": "3177",
+                              "kind": "IDENTIFIER",
+                              "name": "Parser",
+                              "startPosition": "3171"
+                            },
+                            "arguments": [],
+                            "startPosition": "3171"
+                          },
+                          "endPosition": "3179",
+                          "kind": "NEW",
+                          "startPosition": "3167"
+                        }
+                      },
+                      {
+                        "endPosition": "3415",
+                        "kind": "VARIABLE",
+                        "name": "tree",
+                        "startPosition": "3196",
+                        "initializer": {
+                          "endPosition": "3415",
+                          "kind": "FUNCTION_INVOCATION",
+                          "functionSelect": {
+                            "identifier": "parse",
+                            "expression": {
+                              "endPosition": "3209",
+                              "kind": "IDENTIFIER",
+                              "name": "parser",
+                              "startPosition": "3203"
+                            },
+                            "endPosition": "3215",
+                            "kind": "MEMBER_SELECT",
+                            "startPosition": "3203"
+                          },
+                          "arguments": [
+                            {
+                              "leftOperand": {
+                                "leftOperand": {
+                                  "endPosition": "3222",
+                                  "kind": "IDENTIFIER",
+                                  "name": "subdir",
+                                  "startPosition": "3216"
+                                },
+                                "endPosition": "3227",
+                                "kind": "PLUS",
+                                "rightOperand": {
+                                  "endPosition": "3227",
+                                  "kind": "STRING_LITERAL",
+                                  "value": "/",
+                                  "startPosition": "3226"
+                                },
+                                "startPosition": "3216"
+                              },
+                              "endPosition": "3240",
+                              "kind": "PLUS",
+                              "rightOperand": {
+                                "identifier": "name",
+                                "expression": {
+                                  "endPosition": "3235",
+                                  "kind": "IDENTIFIER",
+                                  "name": "file",
+                                  "startPosition": "3231"
+                                },
+                                "endPosition": "3240",
+                                "kind": "MEMBER_SELECT",
+                                "startPosition": "3231"
+                              },
+                              "startPosition": "3216"
+                            },
+                            {
+                              "endPosition": "3248",
+                              "kind": "IDENTIFIER",
+                              "name": "script",
+                              "startPosition": "3242"
+                            },
+                            {
+                              "endPosition": "3286",
+                              "kind": "FUNCTION_EXPRESSION",
+                              "body": {
+                                "endPosition": "3397",
+                                "kind": "BLOCK",
+                                "statements": [
+                                  {
+                                    "expression": {
+                                      "endPosition": "3365",
+                                      "kind": "FUNCTION_INVOCATION",
+                                      "functionSelect": {
+                                        "endPosition": "3312",
+                                        "kind": "IDENTIFIER",
+                                        "name": "print",
+                                        "startPosition": "3307"
+                                      },
+                                      "arguments": [
+                                        {
+                                          "endPosition": "3364",
+                                          "kind": "FUNCTION_INVOCATION",
+                                          "functionSelect": {
+                                            "identifier": "stringify",
+                                            "expression": {
+                                              "endPosition": "3317",
+                                              "kind": "IDENTIFIER",
+                                              "name": "JSON",
+                                              "startPosition": "3313"
+                                            },
+                                            "endPosition": "3327",
+                                            "kind": "MEMBER_SELECT",
+                                            "startPosition": "3313"
+                                          },
+                                          "arguments": [
+                                            {
+                                              "endPosition": "3354",
+                                              "kind": "FUNCTION_INVOCATION",
+                                              "functionSelect": {
+                                                "identifier": "convert",
+                                                "expression": {
+                                                  "endPosition": "3334",
+                                                  "kind": "IDENTIFIER",
+                                                  "name": "parser",
+                                                  "startPosition": "3328"
+                                                },
+                                                "endPosition": "3342",
+                                                "kind": "MEMBER_SELECT",
+                                                "startPosition": "3328"
+                                              },
+                                              "arguments": [
+                                                {
+                                                  "endPosition": "3353",
+                                                  "kind": "IDENTIFIER",
+                                                  "name": "diagnostic",
+                                                  "startPosition": "3343"
+                                                }
+                                              ],
+                                              "startPosition": "3328"
+                                            },
+                                            {
+                                              "endPosition": "3360",
+                                              "kind": "NULL_LITERAL",
+                                              "startPosition": "3356"
+                                            },
+                                            {
+                                              "endPosition": "3363",
+                                              "kind": "NUMBER_LITERAL",
+                                              "value": "2",
+                                              "startPosition": "3362"
+                                            }
+                                          ],
+                                          "startPosition": "3313"
+                                        }
+                                      ],
+                                      "startPosition": "3307"
+                                    },
+                                    "endPosition": "3365",
+                                    "kind": "EXPRESSION_STATEMENT",
+                                    "startPosition": "3307"
+                                  },
+                                  {
+                                    "expression": {
+                                      "endPosition": "3396",
+                                      "kind": "FUNCTION_INVOCATION",
+                                      "functionSelect": {
+                                        "endPosition": "3391",
+                                        "kind": "IDENTIFIER",
+                                        "name": "print",
+                                        "startPosition": "3386"
+                                      },
+                                      "arguments": [
+                                        {
+                                          "endPosition": "3394",
+                                          "kind": "STRING_LITERAL",
+                                          "value": ",",
+                                          "startPosition": "3393"
+                                        }
+                                      ],
+                                      "startPosition": "3386"
+                                    },
+                                    "endPosition": "3396",
+                                    "kind": "EXPRESSION_STATEMENT",
+                                    "startPosition": "3386"
+                                  }
+                                ],
+                                "startPosition": "3286"
+                              },
+                              "strict": "false",
+                              "startPosition": "3286",
+                              "parameters": [
+                                {
+                                  "endPosition": "3284",
+                                  "kind": "IDENTIFIER",
+                                  "name": "diagnostic",
+                                  "startPosition": "3274"
+                                }
+                              ]
+                            }
+                          ],
+                          "startPosition": "3203"
+                        }
+                      },
+                      {
+                        "condition": {
+                          "leftOperand": {
+                            "endPosition": "3437",
+                            "kind": "IDENTIFIER",
+                            "name": "tree",
+                            "startPosition": "3433"
+                          },
+                          "endPosition": "3445",
+                          "kind": "NOT_EQUAL_TO",
+                          "rightOperand": {
+                            "endPosition": "3445",
+                            "kind": "NULL_LITERAL",
+                            "startPosition": "3441"
+                          },
+                          "startPosition": "3433"
+                        },
+                        "endPosition": "3541",
+                        "kind": "IF",
+                        "startPosition": "3429",
+                        "thenStatement": {
+                          "endPosition": "3541",
+                          "kind": "BLOCK",
+                          "statements": [
+                            {
+                              "expression": {
+                                "endPosition": "3500",
+                                "kind": "FUNCTION_INVOCATION",
+                                "functionSelect": {
+                                  "endPosition": "3469",
+                                  "kind": "IDENTIFIER",
+                                  "name": "print",
+                                  "startPosition": "3464"
+                                },
+                                "arguments": [
+                                  {
+                                    "endPosition": "3499",
+                                    "kind": "FUNCTION_INVOCATION",
+                                    "functionSelect": {
+                                      "identifier": "stringify",
+                                      "expression": {
+                                        "endPosition": "3474",
+                                        "kind": "IDENTIFIER",
+                                        "name": "JSON",
+                                        "startPosition": "3470"
+                                      },
+                                      "endPosition": "3484",
+                                      "kind": "MEMBER_SELECT",
+                                      "startPosition": "3470"
+                                    },
+                                    "arguments": [
+                                      {
+                                        "endPosition": "3489",
+                                        "kind": "IDENTIFIER",
+                                        "name": "tree",
+                                        "startPosition": "3485"
+                                      },
+                                      {
+                                        "endPosition": "3495",
+                                        "kind": "NULL_LITERAL",
+                                        "startPosition": "3491"
+                                      },
+                                      {
+                                        "endPosition": "3498",
+                                        "kind": "NUMBER_LITERAL",
+                                        "value": "2",
+                                        "startPosition": "3497"
+                                      }
+                                    ],
+                                    "startPosition": "3470"
+                                  }
+                                ],
+                                "startPosition": "3464"
+                              },
+                              "endPosition": "3500",
+                              "kind": "EXPRESSION_STATEMENT",
+                              "startPosition": "3464"
+                            },
+                            {
+                              "expression": {
+                                "endPosition": "3527",
+                                "kind": "FUNCTION_INVOCATION",
+                                "functionSelect": {
+                                  "endPosition": "3522",
+                                  "kind": "IDENTIFIER",
+                                  "name": "print",
+                                  "startPosition": "3517"
+                                },
+                                "arguments": [
+                                  {
+                                    "endPosition": "3525",
+                                    "kind": "STRING_LITERAL",
+                                    "value": ",",
+                                    "startPosition": "3524"
+                                  }
+                                ],
+                                "startPosition": "3517"
+                              },
+                              "endPosition": "3527",
+                              "kind": "EXPRESSION_STATEMENT",
+                              "startPosition": "3517"
+                            }
+                          ],
+                          "startPosition": "3447"
+                        }
+                      }
+                    ],
+                    "startPosition": "3100"
+                  }
+                }
+              ],
+              "startPosition": "3060"
+            },
+            "startPosition": "3031"
+          },
+          {
+            "endPosition": "3049",
+            "kind": "VARIABLE",
+            "name": "file",
+            "startPosition": "3045"
+          }
+        ],
+        "startPosition": "2897"
+      },
+      "strict": "false",
+      "startPosition": "2867",
+      "parameters": [
+        {
+          "endPosition": "2895",
+          "kind": "IDENTIFIER",
+          "name": "subdir",
+          "startPosition": "2889"
+        }
+      ]
+    },
+    {
+      "endPosition": "3901",
+      "kind": "FUNCTION",
+      "name": "main",
+      "body": {
+        "endPosition": "3899",
+        "kind": "BLOCK",
+        "statements": [
+          {
+            "expression": {
+              "endPosition": "3631",
+              "kind": "FUNCTION_INVOCATION",
+              "functionSelect": {
+                "endPosition": "3626",
+                "kind": "IDENTIFIER",
+                "name": "print",
+                "startPosition": "3621"
+              },
+              "arguments": [
+                {
+                  "endPosition": "3629",
+                  "kind": "STRING_LITERAL",
+                  "value": "[",
+                  "startPosition": "3628"
+                }
+              ],
+              "startPosition": "3621"
+            },
+            "endPosition": "3631",
+            "kind": "EXPRESSION_STATEMENT",
+            "startPosition": "3621"
+          },
+          {
+            "expression": {
+              "endPosition": "3665",
+              "kind": "FUNCTION_INVOCATION",
+              "functionSelect": {
+                "endPosition": "3650",
+                "kind": "IDENTIFIER",
+                "name": "processFiles",
+                "startPosition": "3638"
+              },
+              "arguments": [
+                {
+                  "endPosition": "3663",
+                  "kind": "STRING_LITERAL",
+                  "value": "parsertests",
+                  "startPosition": "3652"
+                }
+              ],
+              "startPosition": "3638"
+            },
+            "endPosition": "3665",
+            "kind": "EXPRESSION_STATEMENT",
+            "startPosition": "3638"
+          },
+          {
+            "expression": {
+              "endPosition": "3706",
+              "kind": "FUNCTION_INVOCATION",
+              "functionSelect": {
+                "endPosition": "3683",
+                "kind": "IDENTIFIER",
+                "name": "processFiles",
+                "startPosition": "3671"
+              },
+              "arguments": [
+                {
+                  "endPosition": "3704",
+                  "kind": "STRING_LITERAL",
+                  "value": "parsernegativetests",
+                  "startPosition": "3685"
+                }
+              ],
+              "startPosition": "3671"
+            },
+            "endPosition": "3706",
+            "kind": "EXPRESSION_STATEMENT",
+            "startPosition": "3671"
+          },
+          {
+            "endPosition": "3775",
+            "kind": "VARIABLE",
+            "name": "script",
+            "startPosition": "3747",
+            "initializer": {
+              "endPosition": "3775",
+              "kind": "FUNCTION_INVOCATION",
+              "functionSelect": {
+                "endPosition": "3765",
+                "kind": "IDENTIFIER",
+                "name": "readFully",
+                "startPosition": "3756"
+              },
+              "arguments": [
+                {
+                  "endPosition": "3774",
+                  "kind": "IDENTIFIER",
+                  "name": "__FILE__",
+                  "startPosition": "3766"
+                }
+              ],
+              "startPosition": "3756"
+            }
+          },
+          {
+            "endPosition": "3840",
+            "kind": "VARIABLE",
+            "name": "tree",
+            "startPosition": "3785",
+            "initializer": {
+              "endPosition": "3840",
+              "kind": "FUNCTION_INVOCATION",
+              "functionSelect": {
+                "identifier": "parse",
+                "expression": {
+                  "constructorExpression": {
+                    "endPosition": "3804",
+                    "kind": "FUNCTION_INVOCATION",
+                    "functionSelect": {
+                      "endPosition": "3802",
+                      "kind": "IDENTIFIER",
+                      "name": "Parser",
+                      "startPosition": "3796"
+                    },
+                    "arguments": [],
+                    "startPosition": "3796"
+                  },
+                  "endPosition": "3804",
+                  "kind": "NEW",
+                  "startPosition": "3792"
+                },
+                "endPosition": "3810",
+                "kind": "MEMBER_SELECT",
+                "startPosition": "3792"
+              },
+              "arguments": [
+                {
+                  "endPosition": "3824",
+                  "kind": "STRING_LITERAL",
+                  "value": "parserapi.js",
+                  "startPosition": "3812"
+                },
+                {
+                  "endPosition": "3833",
+                  "kind": "IDENTIFIER",
+                  "name": "script",
+                  "startPosition": "3827"
+                },
+                {
+                  "endPosition": "3839",
+                  "kind": "NULL_LITERAL",
+                  "startPosition": "3835"
+                }
+              ],
+              "startPosition": "3792"
+            }
+          },
+          {
+            "expression": {
+              "endPosition": "3882",
+              "kind": "FUNCTION_INVOCATION",
+              "functionSelect": {
+                "endPosition": "3851",
+                "kind": "IDENTIFIER",
+                "name": "print",
+                "startPosition": "3846"
+              },
+              "arguments": [
+                {
+                  "endPosition": "3881",
+                  "kind": "FUNCTION_INVOCATION",
+                  "functionSelect": {
+                    "identifier": "stringify",
+                    "expression": {
+                      "endPosition": "3856",
+                      "kind": "IDENTIFIER",
+                      "name": "JSON",
+                      "startPosition": "3852"
+                    },
+                    "endPosition": "3866",
+                    "kind": "MEMBER_SELECT",
+                    "startPosition": "3852"
+                  },
+                  "arguments": [
+                    {
+                      "endPosition": "3871",
+                      "kind": "IDENTIFIER",
+                      "name": "tree",
+                      "startPosition": "3867"
+                    },
+                    {
+                      "endPosition": "3877",
+                      "kind": "NULL_LITERAL",
+                      "startPosition": "3873"
+                    },
+                    {
+                      "endPosition": "3880",
+                      "kind": "NUMBER_LITERAL",
+                      "value": "2",
+                      "startPosition": "3879"
+                    }
+                  ],
+                  "startPosition": "3852"
+                }
+              ],
+              "startPosition": "3846"
+            },
+            "endPosition": "3882",
+            "kind": "EXPRESSION_STATEMENT",
+            "startPosition": "3846"
+          },
+          {
+            "expression": {
+              "endPosition": "3898",
+              "kind": "FUNCTION_INVOCATION",
+              "functionSelect": {
+                "endPosition": "3893",
+                "kind": "IDENTIFIER",
+                "name": "print",
+                "startPosition": "3888"
+              },
+              "arguments": [
+                {
+                  "endPosition": "3896",
+                  "kind": "STRING_LITERAL",
+                  "value": "]",
+                  "startPosition": "3895"
+                }
+              ],
+              "startPosition": "3888"
+            },
+            "endPosition": "3898",
+            "kind": "EXPRESSION_STATEMENT",
+            "startPosition": "3888"
+          }
+        ],
+        "startPosition": "3615"
+      },
+      "strict": "false",
+      "startPosition": "3599",
+      "parameters": []
+    },
+    {
       "expression": {
         "endPosition": "3909",
         "kind": "FUNCTION_INVOCATION",