8134503: support ES6 parsing in Nashorn
authorhannesw
Wed, 27 Apr 2016 15:50:33 +0200
changeset 37732 3673fec68d16
parent 37646 84aba7335005
child 37733 54c8207aed23
8134503: support ES6 parsing in Nashorn Reviewed-by: jlaskey, sundar, mhaupt Contributed-by: andreas.woess@oracle.com
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompilationPhase.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/SplitIntoFunctions.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/WeighNodes.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/AccessNode.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BaseNode.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Block.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ClassNode.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ExpressionList.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ForNode.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IdentNode.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IndexNode.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Module.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/PropertyNode.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeVisitor.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContext.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextFunctionNode.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextModuleNode.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/TokenType.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/Shell.java
nashorn/test/script/basic/es6/parser-es6.js
nashorn/test/script/basic/yield.js
nashorn/test/script/error/NASHORN-154/function_mult_params_in_strict.js.EXPECTED
nashorn/test/script/nosecurity/parserapi.js.EXPECTED
nashorn/test/script/nosecurity/parserapi_strict.js.EXPECTED
nashorn/test/script/nosecurity/treeapi/array_literal.js.EXPECTED
nashorn/test/script/nosecurity/treeapi/objectLiteral.js.EXPECTED
nashorn/test/script/nosecurity/treeapi/property.js.EXPECTED
nashorn/test/script/nosecurity/treeapi/throw.js.EXPECTED
nashorn/test/script/nosecurity/treeapi/with.js.EXPECTED
nashorn/test/src/jdk/nashorn/internal/test/framework/ScriptRunnable.java
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java	Wed Jul 05 21:38:12 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java	Wed Apr 27 15:50:33 2016 +0200
@@ -4310,7 +4310,7 @@
      * @param ident identifier for block or function where applicable
      */
     private void printSymbols(final Block block, final FunctionNode function, final String ident) {
-        if (compiler.getScriptEnvironment()._print_symbols || function.getFlag(FunctionNode.IS_PRINT_SYMBOLS)) {
+        if (compiler.getScriptEnvironment()._print_symbols || function.getDebugFlag(FunctionNode.DEBUG_PRINT_SYMBOLS)) {
             final PrintWriter out = compiler.getScriptEnvironment().getErr();
             out.println("[BLOCK in '" + ident + "']");
             if (!block.printSymbols(out)) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompilationPhase.java	Wed Jul 05 21:38:12 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompilationPhase.java	Wed Apr 27 15:50:33 2016 +0200
@@ -278,12 +278,12 @@
             final PrintWriter       err  = senv.getErr();
 
             //TODO separate phase for the debug printouts for abstraction and clarity
-            if (senv._print_lower_ast || fn.getFlag(FunctionNode.IS_PRINT_LOWER_AST)) {
+            if (senv._print_lower_ast || fn.getDebugFlag(FunctionNode.DEBUG_PRINT_LOWER_AST)) {
                 err.println("Lower AST for: " + quote(newFunctionNode.getName()));
                 err.println(new ASTWriter(newFunctionNode));
             }
 
-            if (senv._print_lower_parse || fn.getFlag(FunctionNode.IS_PRINT_LOWER_PARSE)) {
+            if (senv._print_lower_parse || fn.getDebugFlag(FunctionNode.DEBUG_PRINT_LOWER_PARSE)) {
                 err.println("Lower AST for: " + quote(newFunctionNode.getName()));
                 err.println(new PrintVisitor(newFunctionNode));
             }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/SplitIntoFunctions.java	Wed Jul 05 21:38:12 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/SplitIntoFunctions.java	Wed Apr 27 15:50:33 2016 +0200
@@ -175,7 +175,9 @@
                 // we still use IS_SPLIT as the criteria in CompilationPhase.SERIALIZE_SPLIT_PHASE.
                 FunctionNode.IS_ANONYMOUS | FunctionNode.USES_ANCESTOR_SCOPE | FunctionNode.IS_SPLIT,
                 body,
-                null
+                null,
+                originalFn.getModule(),
+                originalFn.getDebugFlags()
         )
         .setCompileUnit(lc, splitNode.getCompileUnit());
 
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/WeighNodes.java	Wed Jul 05 21:38:12 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/WeighNodes.java	Wed Apr 27 15:50:33 2016 +0200
@@ -435,7 +435,7 @@
     }
 
     @Override
-    public Node leaveBIND(final BinaryNode binaryNode) {
+    public Node leaveARROW(final BinaryNode binaryNode) {
         return binaryNodeWeight(binaryNode);
     }
 
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/AccessNode.java	Wed Jul 05 21:38:12 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/AccessNode.java	Wed Apr 27 15:50:33 2016 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2016, 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
@@ -48,12 +48,13 @@
      * @param property  property
      */
     public AccessNode(final long token, final int finish, final Expression base, final String property) {
-        super(token, finish, base, false);
+        super(token, finish, base, false, false);
         this.property = property;
     }
 
-    private AccessNode(final AccessNode accessNode, final Expression base, final String property, final boolean isFunction, final Type type, final int id) {
-        super(accessNode, base, isFunction, type, id);
+    private AccessNode(final AccessNode accessNode, final Expression base, final String property, final boolean isFunction,
+                       final Type type, final int id, final boolean isSuper) {
+        super(accessNode, base, isFunction, type, id, isSuper);
         this.property = property;
     }
 
@@ -105,7 +106,7 @@
         if (this.base == base) {
             return this;
         }
-        return new AccessNode(this, base, property, isFunction(), type, programPoint);
+        return new AccessNode(this, base, property, isFunction(), type, programPoint, isSuper());
     }
 
     @Override
@@ -113,7 +114,7 @@
         if (this.type == type) {
             return this;
         }
-        return new AccessNode(this, base, property, isFunction(), type, programPoint);
+        return new AccessNode(this, base, property, isFunction(), type, programPoint, isSuper());
     }
 
     @Override
@@ -121,7 +122,7 @@
         if (this.programPoint == programPoint) {
             return this;
         }
-        return new AccessNode(this, base, property, isFunction(), type, programPoint);
+        return new AccessNode(this, base, property, isFunction(), type, programPoint, isSuper());
     }
 
     @Override
@@ -129,6 +130,14 @@
         if (isFunction()) {
             return this;
         }
-        return new AccessNode(this, base, property, true, type, programPoint);
+        return new AccessNode(this, base, property, true, type, programPoint, isSuper());
+    }
+
+    @Override
+    public AccessNode setIsSuper() {
+        if (isSuper()) {
+            return this;
+        }
+        return new AccessNode(this, base, property, isFunction(), type, programPoint, true);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BaseNode.java	Wed Jul 05 21:38:12 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BaseNode.java	Wed Apr 27 15:50:33 2016 +0200
@@ -52,6 +52,9 @@
     /** Program point id */
     protected final int programPoint;
 
+    /** Super property access. */
+    private final boolean isSuper;
+
     /**
      * Constructor
      *
@@ -59,13 +62,15 @@
      * @param finish finish
      * @param base   base node
      * @param isFunction is this a function
+     * @param isSuper is this a super property access
      */
-    public BaseNode(final long token, final int finish, final Expression base, final boolean isFunction) {
+    public BaseNode(final long token, final int finish, final Expression base, final boolean isFunction, final boolean isSuper) {
         super(token, base.getStart(), finish);
         this.base           = base;
         this.isFunction     = isFunction;
         this.type = null;
         this.programPoint   = INVALID_PROGRAM_POINT;
+        this.isSuper        = isSuper;
     }
 
     /**
@@ -75,13 +80,15 @@
      * @param isFunction is this a function
      * @param callSiteType  the callsite type for this base node, either optimistic or conservative
      * @param programPoint  program point id
+     * @param isSuper is this a super property access
      */
-    protected BaseNode(final BaseNode baseNode, final Expression base, final boolean isFunction, final Type callSiteType, final int programPoint) {
+    protected BaseNode(final BaseNode baseNode, final Expression base, final boolean isFunction, final Type callSiteType, final int programPoint, final boolean isSuper) {
         super(baseNode);
         this.base           = base;
         this.isFunction     = isFunction;
         this.type = callSiteType;
         this.programPoint   = programPoint;
+        this.isSuper        = isSuper;
     }
 
     /**
@@ -136,4 +143,17 @@
      */
     public abstract BaseNode setIsFunction();
 
+    /**
+     * @return {@code true} if a SuperProperty access.
+     */
+    public boolean isSuper() {
+        return isSuper;
+    }
+
+    /**
+     * Mark this node as being a SuperProperty access.
+     *
+     * @return  a base node identical to this one in all aspects except with its super flag set.
+     */
+    public abstract BaseNode setIsSuper();
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Block.java	Wed Jul 05 21:38:12 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Block.java	Wed Apr 27 15:50:33 2016 +0200
@@ -65,24 +65,39 @@
     private final LocalVariableConversion conversion;
 
     /** Flag indicating that this block needs scope */
-    public static final int NEEDS_SCOPE = 1 << 0;
+    public static final int NEEDS_SCOPE        = 1 << 0;
 
     /**
      * Is this block tagged as terminal based on its contents
      * (usually the last statement)
      */
-    public static final int IS_TERMINAL = 1 << 2;
+    public static final int IS_TERMINAL        = 1 << 2;
 
     /**
      * Is this block the eager global scope - i.e. the original program. This isn't true for the
      * outermost level of recompiles
      */
-    public static final int IS_GLOBAL_SCOPE = 1 << 3;
+    public static final int IS_GLOBAL_SCOPE    = 1 << 3;
 
     /**
      * Is this block a synthetic one introduced by Parser?
      */
-    public static final int IS_SYNTHETIC = 1 << 4;
+    public static final int IS_SYNTHETIC       = 1 << 4;
+
+    /**
+     * Is this the function body block? May not be the first, if parameter list contains expressions.
+     */
+    public static final int IS_BODY            = 1 << 5;
+
+    /**
+     * Is this the parameter initialization block? If present, must be the first block, immediately wrapping the function body block.
+     */
+    public static final int IS_PARAMETER_BLOCK = 1 << 6;
+
+    /**
+     * Marks the variable declaration block for case clauses of a switch statement.
+     */
+    public static final int IS_SWITCH_BLOCK    = 1 << 7;
 
     /**
      * Constructor
@@ -489,4 +504,31 @@
     public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
         return Acceptor.accept(this, visitor);
     }
+
+    /**
+     * Checks if this is a function body.
+     *
+     * @return true if the function body flag is set
+     */
+    public boolean isFunctionBody() {
+        return getFlag(IS_BODY);
+    }
+
+    /**
+     * Checks if this is a parameter block.
+     *
+     * @return true if the parameter block flag is set
+     */
+    public boolean isParameterBlock() {
+        return getFlag(IS_PARAMETER_BLOCK);
+    }
+
+    /**
+     * Checks whether this is a switch block.
+     *
+     * @return true if this is a switch block
+     */
+    public boolean isSwitchBlock() {
+        return getFlag(IS_SWITCH_BLOCK);
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ClassNode.java	Wed Apr 27 15:50:33 2016 +0200
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2015, 2016, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package jdk.nashorn.internal.ir;
+
+import java.util.Collections;
+import java.util.List;
+
+import jdk.nashorn.internal.codegen.types.Type;
+import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+
+/**
+ * IR representation for class definitions.
+ */
+public class ClassNode extends Expression {
+    private static final long serialVersionUID = 1L;
+
+    private final IdentNode ident;
+    private final Expression classHeritage;
+    private final PropertyNode constructor;
+    private final List<PropertyNode> classElements;
+    private final int line;
+
+    /**
+     * Constructor.
+     *
+     * @param line line number
+     * @param token token
+     * @param finish finish
+     * @param ident ident
+     * @param classHeritage class heritage
+     * @param constructor constructor
+     * @param classElements class elements
+     */
+    public ClassNode(final int line, final long token, final int finish, final IdentNode ident, final Expression classHeritage, final PropertyNode constructor,
+                     final List<PropertyNode> classElements) {
+        super(token, finish);
+        this.line = line;
+        this.ident = ident;
+        this.classHeritage = classHeritage;
+        this.constructor = constructor;
+        this.classElements = classElements;
+    }
+
+    /**
+     * Class identifier. Optional.
+     *
+     * @return the class identifier
+     */
+    public IdentNode getIdent() {
+        return ident;
+    }
+
+    /**
+     * The expression of the {@code extends} clause. Optional.
+     *
+     * @return the class heritage
+     */
+    public Expression getClassHeritage() {
+        return classHeritage;
+    }
+
+    /**
+     * Get the constructor method definition.
+     *
+     * @return the constructor
+     */
+    public PropertyNode getConstructor() {
+        return constructor;
+    }
+
+    /**
+     * Get method definitions except the constructor.
+     *
+     * @return the class elements
+     */
+    public List<PropertyNode> getClassElements() {
+        return Collections.unmodifiableList(classElements);
+    }
+
+    /**
+     * Returns the line number.
+     *
+     * @return the line number
+     */
+    public int getLineNumber() {
+        return line;
+    }
+
+    @Override
+    public Type getType() {
+        return Type.OBJECT;
+    }
+
+    @Override
+    public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
+        if (visitor.enterClassNode(this)) {
+            return visitor.leaveClassNode(this);
+        }
+
+        return this;
+    }
+
+    @Override
+    public void toString(final StringBuilder sb, final boolean printType) {
+        sb.append("class");
+        if (ident != null) {
+            sb.append(' ');
+            ident.toString(sb, printType);
+        }
+        if (classHeritage != null) {
+            sb.append(" extends");
+            classHeritage.toString(sb, printType);
+        }
+        sb.append(" {");
+        if (constructor != null) {
+            constructor.toString(sb, printType);
+        }
+        for (final PropertyNode classElement : classElements) {
+            sb.append(" ");
+            classElement.toString(sb, printType);
+        }
+        sb.append("}");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ExpressionList.java	Wed Apr 27 15:50:33 2016 +0200
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2015, 2016, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package jdk.nashorn.internal.ir;
+
+import java.util.Collections;
+import java.util.List;
+
+import jdk.nashorn.internal.codegen.types.Type;
+import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+
+/**
+ * IR for CoverParenthesizedExpressionAndArrowParameterList, used only during parsing.
+ */
+public final class ExpressionList extends Expression {
+    private static final long serialVersionUID = 1L;
+
+    private final List<Expression> expressions;
+
+    /**
+     * Constructor.
+     *
+     * @param token token
+     * @param finish finish
+     * @param expressions expression
+     */
+    public ExpressionList(final long token, final int finish, final List<Expression> expressions) {
+        super(token, finish);
+        this.expressions = expressions;
+    }
+
+    /**
+     * Get the list of expressions.
+     *
+     * @return the list of expressions
+     */
+    public List<Expression> getExpressions() {
+        return Collections.unmodifiableList(expressions);
+    }
+
+    @Override
+    public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Type getType() {
+        return null;
+    }
+
+    @Override
+    public void toString(StringBuilder sb, boolean printType) {
+        sb.append("(");
+        boolean first = true;
+        for (Expression expression : expressions) {
+            if (first) {
+                first = false;
+            } else {
+                sb.append(", ");
+            }
+            expression.toString(sb, printType);
+        }
+        sb.append(")");
+    }
+}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ForNode.java	Wed Jul 05 21:38:12 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ForNode.java	Wed Apr 27 15:50:33 2016 +0200
@@ -90,7 +90,6 @@
         this.init = init;
         this.modify = modify;
         this.iterator = null;
-
     }
 
     private ForNode(final ForNode forNode, final Expression init, final JoinPredecessorExpression test,
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java	Wed Jul 05 21:38:12 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java	Wed Apr 27 15:50:33 2016 +0200
@@ -69,7 +69,13 @@
         /** a getter, @see {@link UserAccessorProperty} */
         GETTER,
         /** a setter, @see {@link UserAccessorProperty} */
-        SETTER
+        SETTER,
+        /** an arrow function */
+        ARROW,
+        /** a generator function */
+        GENERATOR,
+        /** a module function */
+        MODULE
     }
 
     /** Source of entity. */
@@ -122,6 +128,12 @@
     /** Root class for function */
     private final Class<?> rootClass;
 
+    /** The ES6 module */
+    private final Module module;
+
+    /** The debug flags */
+    private final int debugFlags;
+
     /** Is anonymous function flag. */
     public static final int IS_ANONYMOUS                = 1 << 0;
 
@@ -172,49 +184,21 @@
     /**
      * Is this function the top-level program?
      */
-    public static final int IS_PROGRAM = 1 << 13;
+    public static final int IS_PROGRAM                  = 1 << 13;
 
     /**
      * Flag indicating whether this function uses the local variable symbol for itself. Only named function expressions
      * can have this flag set if they reference themselves (e.g. "(function f() { return f })". Declared functions will
      * use the symbol in their parent scope instead when they reference themselves by name.
      */
-    public static final int USES_SELF_SYMBOL = 1 << 14;
+    public static final int USES_SELF_SYMBOL            = 1 << 14;
 
     /** Does this function use the "this" keyword? */
-    public static final int USES_THIS = 1 << 15;
+    public static final int USES_THIS                   = 1 << 15;
 
     /** Is this declared in a dynamic context */
-    public static final int IN_DYNAMIC_CONTEXT = 1 << 16;
-
-    /**
-     * The following flags are derived from directive comments within this function.
-     * Note that even IS_STRICT is one such flag but that requires special handling.
-     */
+    public static final int IN_DYNAMIC_CONTEXT          = 1 << 16;
 
-    /** parser, print parse tree */
-    public static final int IS_PRINT_PARSE       = 1 << 17;
-    /** parser, print lower parse tree */
-    public static final int IS_PRINT_LOWER_PARSE = 1 << 18;
-    /** parser, print AST */
-    public static final int IS_PRINT_AST         = 1 << 19;
-    /** parser, print lower AST */
-    public static final int IS_PRINT_LOWER_AST   = 1 << 20;
-    /** parser, print symbols */
-    public static final int IS_PRINT_SYMBOLS     = 1 << 21;
-
-    // callsite tracing, profiling within this function
-    /** profile callsites in this function? */
-    public static final int IS_PROFILE         = 1 << 22;
-
-    /** trace callsite enterexit in this function? */
-    public static final int IS_TRACE_ENTEREXIT = 1 << 23;
-
-    /** trace callsite misses in this function? */
-    public static final int IS_TRACE_MISSES    = 1 << 24;
-
-    /** trace callsite values in this function? */
-    public static final int IS_TRACE_VALUES    = 1 << 25;
 
     /**
      * Whether this function needs the callee {@link ScriptFunction} instance passed to its code as a
@@ -222,18 +206,41 @@
      * Rather, it is always calculated (see {@link #needsCallee()}). {@link RecompilableScriptFunctionData}
      * will, however, cache the value of this flag.
      */
-    public static final int NEEDS_CALLEE       = 1 << 26;
+    public static final int NEEDS_CALLEE                = 1 << 17;
 
     /**
      * Is the function node cached?
      */
-    public static final int IS_CACHED = 1 << 27;
+    public static final int IS_CACHED                   = 1 << 18;
+
+    /**
+     * Does this function contain a super call? (cf. ES6 14.3.5 Static Semantics: HasDirectSuper)
+     */
+    public static final int ES6_HAS_DIRECT_SUPER        = 1 << 19;
+
+    /**
+     * Does this function use the super binding?
+     */
+    public static final int ES6_USES_SUPER              = 1 << 20;
 
-    /** extension callsite flags mask */
-    public static final int EXTENSION_CALLSITE_FLAGS = IS_PRINT_PARSE |
-        IS_PRINT_LOWER_PARSE | IS_PRINT_AST | IS_PRINT_LOWER_AST |
-        IS_PRINT_SYMBOLS | IS_PROFILE | IS_TRACE_ENTEREXIT |
-        IS_TRACE_MISSES | IS_TRACE_VALUES;
+    /**
+     * Is this function a (class or object) method?
+     */
+    public static final int ES6_IS_METHOD               = 1 << 21;
+
+    /**
+     * Is this the constructor method?
+     */
+    public static final int ES6_IS_CLASS_CONSTRUCTOR    = 1 << 22;
+
+    /** Is this the constructor of a subclass (i.e., a class with an extends declaration)? */
+    public static final int ES6_IS_SUBCLASS_CONSTRUCTOR = 1 << 23;
+
+    /** is this a strong mode function? */
+    public static final int ES6_IS_STRONG               = 1 << 24;
+
+    /** Does this function use new.target? */
+    public static final int ES6_USES_NEW_TARGET         = 1 << 25;
 
     /** Does this function or any nested functions contain an eval? */
     private static final int HAS_DEEP_EVAL = HAS_EVAL | HAS_NESTED_EVAL;
@@ -247,8 +254,44 @@
     /** Does this function need the parent scope? It needs it if either it or its descendants use variables from it, or have a deep eval, or it's the program. */
     public static final int NEEDS_PARENT_SCOPE = USES_ANCESTOR_SCOPE | HAS_DEEP_EVAL | IS_PROGRAM;
 
+
+    /**
+     * The following flags are derived from directive comments within this function.
+     * Note that even IS_STRICT is one such flag but that requires special handling.
+     */
+
+    /** parser, print parse tree */
+    public static final int DEBUG_PRINT_PARSE       = 1 << 0;
+    /** parser, print lower parse tree */
+    public static final int DEBUG_PRINT_LOWER_PARSE = 1 << 1;
+    /** parser, print AST */
+    public static final int DEBUG_PRINT_AST         = 1 << 2;
+    /** parser, print lower AST */
+    public static final int DEBUG_PRINT_LOWER_AST   = 1 << 3;
+    /** parser, print symbols */
+    public static final int DEBUG_PRINT_SYMBOLS     = 1 << 4;
+
+    // callsite tracing, profiling within this function
+    /** profile callsites in this function? */
+    public static final int DEBUG_PROFILE           = 1 << 5;
+
+    /** trace callsite enterexit in this function? */
+    public static final int DEBUG_TRACE_ENTEREXIT   = 1 << 6;
+
+    /** trace callsite misses in this function? */
+    public static final int DEBUG_TRACE_MISSES      = 1 << 7;
+
+    /** trace callsite values in this function? */
+    public static final int DEBUG_TRACE_VALUES      = 1 << 8;
+
+    /** extension callsite flags mask */
+    public static final int DEBUG_CALLSITE_FLAGS = DEBUG_PRINT_PARSE |
+            DEBUG_PRINT_LOWER_PARSE | DEBUG_PRINT_AST | DEBUG_PRINT_LOWER_AST |
+            DEBUG_PRINT_SYMBOLS | DEBUG_PROFILE | DEBUG_TRACE_ENTEREXIT |
+            DEBUG_TRACE_MISSES | DEBUG_TRACE_VALUES;
+
     /** What is the return type of this function? */
-    private Type returnType = Type.UNKNOWN;
+    public Type returnType = Type.UNKNOWN;
 
     /**
      * Constructor
@@ -267,6 +310,8 @@
      * @param flags      initial flags
      * @param body       body of the function
      * @param endParserState The parser state at the end of the parsing.
+     * @param module     the module
+     * @param debugFlags the debug flags
      */
     public FunctionNode(
         final Source source,
@@ -282,7 +327,9 @@
         final FunctionNode.Kind kind,
         final int flags,
         final Block body,
-        final Object endParserState) {
+        final Object endParserState,
+        final Module module,
+        final int debugFlags) {
         super(token, finish);
 
         this.source           = source;
@@ -299,7 +346,9 @@
         this.body             = body;
         this.thisProperties   = 0;
         this.rootClass        = null;
-        this.endParserState    = endParserState;
+        this.endParserState   = endParserState;
+        this.module           = module;
+        this.debugFlags       = debugFlags;
     }
 
     private FunctionNode(
@@ -335,6 +384,8 @@
         this.ident           = functionNode.ident;
         this.kind            = functionNode.kind;
         this.firstToken      = functionNode.firstToken;
+        this.module          = functionNode.module;
+        this.debugFlags      = functionNode.debugFlags;
     }
 
     @Override
@@ -366,23 +417,23 @@
         }
 
         // quick check for extension callsite flags turned on by directives.
-        if ((flags & EXTENSION_CALLSITE_FLAGS) == 0) {
+        if ((debugFlags & DEBUG_CALLSITE_FLAGS) == 0) {
             return callsiteFlags;
         }
 
-        if (getFlag(IS_PROFILE)) {
+        if (getDebugFlag(DEBUG_PROFILE)) {
             callsiteFlags |= CALLSITE_PROFILE;
         }
 
-        if (getFlag(IS_TRACE_MISSES)) {
+        if (getDebugFlag(DEBUG_TRACE_MISSES)) {
             callsiteFlags |= CALLSITE_TRACE | CALLSITE_TRACE_MISSES;
         }
 
-        if (getFlag(IS_TRACE_VALUES)) {
+        if (getDebugFlag(DEBUG_TRACE_VALUES)) {
             callsiteFlags |= CALLSITE_TRACE | CALLSITE_TRACE_ENTEREXIT | CALLSITE_TRACE_VALUES;
         }
 
-        if (getFlag(IS_TRACE_ENTEREXIT)) {
+        if (getDebugFlag(DEBUG_TRACE_ENTEREXIT)) {
             callsiteFlags |= CALLSITE_TRACE | CALLSITE_TRACE_ENTEREXIT;
         }
 
@@ -466,23 +517,23 @@
     public static int getDirectiveFlag(final String directive) {
         switch (directive) {
             case "nashorn callsite trace enterexit":
-                return IS_TRACE_ENTEREXIT;
+                return DEBUG_TRACE_ENTEREXIT;
             case "nashorn callsite trace misses":
-                return IS_TRACE_MISSES;
+                return DEBUG_TRACE_MISSES;
             case "nashorn callsite trace objects":
-                return IS_TRACE_VALUES;
+                return DEBUG_TRACE_VALUES;
             case "nashorn callsite profile":
-                return IS_PROFILE;
+                return DEBUG_PROFILE;
             case "nashorn print parse":
-                return IS_PRINT_PARSE;
+                return DEBUG_PRINT_PARSE;
             case "nashorn print lower parse":
-                return IS_PRINT_LOWER_PARSE;
+                return DEBUG_PRINT_LOWER_PARSE;
             case "nashorn print ast":
-                return IS_PRINT_AST;
+                return DEBUG_PRINT_AST;
             case "nashorn print lower ast":
-                return IS_PRINT_LOWER_AST;
+                return DEBUG_PRINT_LOWER_AST;
             case "nashorn print symbols":
-                return IS_PRINT_SYMBOLS;
+                return DEBUG_PRINT_SYMBOLS;
             default:
                 // unknown/unsupported directive
                 return 0;
@@ -579,6 +630,25 @@
     }
 
     /**
+     * Returns the debug flags for this function.
+     *
+     * @return the debug flags
+     */
+    public int getDebugFlags() {
+        return debugFlags;
+    }
+
+    /**
+     * Checks whether a debug flag is set for this function.
+     *
+     * @param debugFlag the debug flag
+     * @return true if the flag is set
+     */
+    public boolean getDebugFlag(final int debugFlag) {
+        return (debugFlags & debugFlag) != 0;
+    }
+
+    /**
      * Returns true if the function is the top-level program.
      * @return True if this function node represents the top-level program.
      */
@@ -1065,6 +1135,86 @@
         return setFlag(lc, IS_CACHED);
     }
 
+    /**
+     * Checks if the function is generated in strong mode.
+     *
+     * @return true if strong mode enabled for function
+     */
+    public boolean isStrong() {
+        return getFlag(ES6_IS_STRONG);
+    }
+
+    /**
+     * Checks if this is an ES6 method.
+     *
+     * @return true if the ES6 method flag is set
+     */
+    public boolean isMethod() {
+        return getFlag(ES6_IS_METHOD);
+    }
+
+    /**
+     * Checks if this function uses the ES6 super binding.
+     *
+     * @return true if the ES6 super flag is set
+     */
+    public boolean usesSuper() {
+        return getFlag(ES6_USES_SUPER);
+    }
+
+    /**
+     * Checks if this function directly uses the super binding.
+     *
+     * @return true if the ES6 has-direct-super flag is set
+     */
+    public boolean hasDirectSuper() {
+        return getFlag(ES6_HAS_DIRECT_SUPER);
+    }
+
+    /**
+     * Checks if this is an ES6 class constructor.
+     *
+     * @return true if the ES6 class constructor flag is set
+     */
+    public boolean isClassConstructor() {
+        return getFlag(ES6_IS_CLASS_CONSTRUCTOR);
+    }
+
+    /**
+     * Checks if this is an ES6 subclass constructor.
+     *
+     * @return true if the ES6 subclass constructor flag is set
+     */
+    public boolean isSubclassConstructor() {
+        return getFlag(ES6_IS_SUBCLASS_CONSTRUCTOR);
+    }
+
+    /**
+     * Checks if this function uses the ES6 new-targert.
+     *
+     * @return true if the ES6 new-target flag is set
+     */
+    public boolean usesNewTarget() {
+        return getFlag(ES6_USES_NEW_TARGET);
+    }
+
+    /**
+     * Checks if this is an ES6 module.
+     *
+     * @return true if this is an ES6 module
+     */
+    public boolean isModule() {
+        return kind == Kind.MODULE;
+    }
+
+    /**
+     * Returns the functions's ES6 module.
+     *
+     * @return the module, or null if this function is not part of one
+     */
+    public Module getModule() {
+        return module;
+    }
 
     /**
      * Get the compile unit used to compile this function
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IdentNode.java	Wed Jul 05 21:38:12 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IdentNode.java	Wed Apr 27 15:50:33 2016 +0200
@@ -49,6 +49,11 @@
     private static final int FUTURESTRICT_NAME = 1 << 3;
     private static final int IS_DECLARED_HERE  = 1 << 4;
     private static final int IS_DEAD           = 1 << 5;
+    private static final int DIRECT_SUPER      = 1 << 6;
+    private static final int REST_PARAMETER    = 1 << 7;
+    private static final int PROTO_PROPERTY    = 1 << 8;
+    private static final int DEFAULT_PARAMETER = 1 << 9;
+    private static final int DESTRUCTURED_PARAMETER = 1 << 10;
 
     /** Identifier. */
     private final String name;
@@ -382,4 +387,94 @@
     public LocalVariableConversion getLocalVariableConversion() {
         return conversion;
     }
+
+    /**
+     * Checks if this is a direct super identifier
+     *
+     * @return true if the direct super flag is set
+     */
+    public boolean isDirectSuper() {
+        return (flags & DIRECT_SUPER) != 0;
+    }
+
+    /**
+     * Return a new identifier with the direct super flag set.
+     *
+     * @return the new identifier
+     */
+    public IdentNode setIsDirectSuper() {
+        return new IdentNode(this, name, type, flags | DIRECT_SUPER, programPoint, conversion);
+    }
+
+    /**
+     * Checks if this is a rest parameter
+     *
+     * @return true if the rest parameter flag is set
+     */
+    public boolean isRestParameter() {
+        return (flags & REST_PARAMETER) != 0;
+    }
+
+    /**
+     * Return a new identifier with the rest parameter flag set.
+     *
+     * @return the new identifier
+     */
+    public IdentNode setIsRestParameter() {
+        return new IdentNode(this, name, type, flags | REST_PARAMETER, programPoint, conversion);
+    }
+
+    /**
+     * Checks if this is a proto property name.
+     *
+     * @return true if this is the proto property name
+     */
+    public boolean isProtoPropertyName() {
+        return (flags & PROTO_PROPERTY) != 0;
+    }
+
+    /**
+     * Return a new identifier with the proto property name flag set.
+     *
+     * @return the new identifier
+     */
+    public IdentNode setIsProtoPropertyName() {
+        return new IdentNode(this, name, type, flags | PROTO_PROPERTY, programPoint, conversion);
+    }
+
+    /**
+     * Checks whether this is a default parameter.
+     *
+     * @return true if this is a default parameter
+     */
+    public boolean isDefaultParameter() {
+        return (flags & DEFAULT_PARAMETER) != 0;
+    }
+
+    /**
+     * Return a new identifier with the default parameter flag set.
+     *
+     * @return the new identifier
+     */
+    public IdentNode setIsDefaultParameter() {
+        return new IdentNode(this, name, type, flags | DEFAULT_PARAMETER, programPoint, conversion);
+    }
+
+    /**
+     * Checks whether this is a destructured parameter.
+     *
+     * @return true if this is a destructured parameter
+     */
+    public boolean isDestructuredParameter() {
+        return (flags & DESTRUCTURED_PARAMETER) != 0;
+    }
+
+    /**
+     * Return a new identifier with the destructured parameter flag set.
+     *
+     * @return the new identifier
+     */
+    public IdentNode setIsDestructuredParameter() {
+        return new IdentNode(this, name, type, flags | DESTRUCTURED_PARAMETER, programPoint, conversion);
+    }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IndexNode.java	Wed Jul 05 21:38:12 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IndexNode.java	Wed Apr 27 15:50:33 2016 +0200
@@ -47,12 +47,13 @@
      * @param index   index for access
      */
     public IndexNode(final long token, final int finish, final Expression base, final Expression index) {
-        super(token, finish, base, false);
+        super(token, finish, base, false, false);
         this.index = index;
     }
 
-    private IndexNode(final IndexNode indexNode, final Expression base, final Expression index, final boolean isFunction, final Type type, final int programPoint) {
-        super(indexNode, base, isFunction, type, programPoint);
+    private IndexNode(final IndexNode indexNode, final Expression base, final Expression index, final boolean isFunction,
+                      final Type type, final int programPoint, final boolean isSuper) {
+        super(indexNode, base, isFunction, type, programPoint, isSuper);
         this.index = index;
     }
 
@@ -101,7 +102,7 @@
         if (this.base == base) {
             return this;
         }
-        return new IndexNode(this, base, index, isFunction(), type, programPoint);
+        return new IndexNode(this, base, index, isFunction(), type, programPoint, isSuper());
     }
 
     /**
@@ -113,7 +114,7 @@
         if(this.index == index) {
             return this;
         }
-        return new IndexNode(this, base, index, isFunction(), type, programPoint);
+        return new IndexNode(this, base, index, isFunction(), type, programPoint, isSuper());
     }
 
     @Override
@@ -121,7 +122,7 @@
         if (this.type == type) {
             return this;
         }
-        return new IndexNode(this, base, index, isFunction(), type, programPoint);
+        return new IndexNode(this, base, index, isFunction(), type, programPoint, isSuper());
     }
 
     @Override
@@ -129,7 +130,7 @@
         if (isFunction()) {
             return this;
         }
-        return new IndexNode(this, base, index, true, type, programPoint);
+        return new IndexNode(this, base, index, true, type, programPoint, isSuper());
     }
 
     @Override
@@ -137,6 +138,14 @@
         if (this.programPoint == programPoint) {
             return this;
         }
-        return new IndexNode(this, base, index, isFunction(), type, programPoint);
+        return new IndexNode(this, base, index, isFunction(), type, programPoint, isSuper());
+    }
+
+    @Override
+    public IndexNode setIsSuper() {
+        if (isSuper()) {
+            return this;
+        }
+        return new IndexNode(this, base, index, isFunction(), type, programPoint, true);
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Module.java	Wed Apr 27 15:50:33 2016 +0200
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) 2015, 2016, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package jdk.nashorn.internal.ir;
+
+import java.util.List;
+
+/**
+ * ES6 Module information.
+ */
+public final class Module {
+
+    /** The synthetic binding name assigned to export default declarations with unnamed expressions. */
+    public static final String DEFAULT_EXPORT_BINDING_NAME = "*default*";
+
+    /** The {@code export default} name. */
+    public static final String DEFAULT_NAME = "default";
+
+    /** The {@code export *} name. */
+    public static final String STAR_NAME = "*";
+
+    /**
+     * A module ExportEntry record.
+     *
+     * @link http://www.ecma-international.org/ecma-262/6.0/#sec-source-text-module-records
+     */
+    public static final class ExportEntry {
+        private final String exportName;
+        private final String moduleRequest;
+        private final String importName;
+        private final String localName;
+
+        private ExportEntry(final String exportName, final String moduleRequest, final String importName, final String localName) {
+            this.exportName = exportName;
+            this.moduleRequest = moduleRequest;
+            this.importName = importName;
+            this.localName = localName;
+        }
+
+        /**
+         * Creates a {@code export *} export entry.
+         *
+         * @param moduleRequest the module request
+         * @return the export entry
+         */
+        public static ExportEntry exportStarFrom(final String moduleRequest) {
+            return new ExportEntry(null, moduleRequest, STAR_NAME, null);
+        }
+
+        /**
+         * Creates a {@code export default} export entry.
+         *
+         * @return the export entry
+         */
+        public static ExportEntry exportDefault() {
+            return exportDefault(DEFAULT_EXPORT_BINDING_NAME);
+        }
+
+        /**
+         * Creates a {@code export default} export entry with a local name.
+         *
+         * @param localName the local name
+         * @return the export entry
+         */
+        public static ExportEntry exportDefault(final String localName) {
+            return new ExportEntry(DEFAULT_NAME, null, null, localName);
+        }
+
+        /**
+         * Creates a export entry with a local name and export name.
+         *
+         * @param exportName the export name
+         * @param localName the local name
+         * @return the export entry
+         */
+        public static ExportEntry exportSpecifier(final String exportName, final String localName) {
+            return new ExportEntry(exportName, null, null, localName);
+        }
+
+        /**
+         * Creates a export entry with an export name.
+         *
+         * @param exportName the export name
+         * @return the export entry
+         */
+        public static ExportEntry exportSpecifier(final String exportName) {
+            return exportSpecifier(exportName, exportName);
+        }
+
+        /**
+         * Create a copy of this entry with the specified {@code module request} string.
+         *
+         * @param moduleRequest the module request
+         * @return the new export entry
+         */
+        public ExportEntry withFrom(@SuppressWarnings("hiding") final String moduleRequest) {
+            return new ExportEntry(exportName, moduleRequest, localName, null);
+        }
+
+        /**
+         * Returns the entry's export name.
+         *
+         * @return the export name
+         */
+        public String getExportName() {
+            return exportName;
+        }
+
+        /**
+         * Returns the entry's module request.
+         *
+         * @return the module request
+         */
+        public String getModuleRequest() {
+            return moduleRequest;
+        }
+
+        /**
+         * Returns the entry's import name.
+         *
+         * @return the import name
+         */
+        public String getImportName() {
+            return importName;
+        }
+
+        /**
+         * Returns the entry's local name.
+         *
+         * @return the local name
+         */
+        public String getLocalName() {
+            return localName;
+        }
+
+        @Override
+        public String toString() {
+            return "ExportEntry [exportName=" + exportName + ", moduleRequest=" + moduleRequest + ", importName=" + importName + ", localName=" + localName + "]";
+        }
+    }
+
+    /**
+     * An ImportEntry record.
+     *
+     * @link http://www.ecma-international.org/ecma-262/6.0/#sec-source-text-module-records
+     */
+    public static final class ImportEntry {
+        private final String moduleRequest;
+        private final String importName;
+        private final String localName;
+
+        private ImportEntry(final String moduleRequest, final String importName, final String localName) {
+            this.moduleRequest = moduleRequest;
+            this.importName = importName;
+            this.localName = localName;
+        }
+
+        /**
+         * Creates an import entry with default name.
+         *
+         * @param localName the local name
+         * @return the import entry
+         */
+        public static ImportEntry importDefault(final String localName) {
+            return new ImportEntry(null, DEFAULT_NAME, localName);
+        }
+
+        /**
+         * Creates an import entry with {@code *} import name.
+         *
+         * @param localName the local name
+         * @return the import entry
+         */
+        public static ImportEntry importStarAsNameSpaceFrom(final String localName) {
+            return new ImportEntry(null, STAR_NAME, localName);
+        }
+
+        /**
+         * Creates an import entry with the given import and local names.
+         *
+         * @param importName the import name
+         * @param localName the local name
+         * @return the import entry
+         */
+        public static ImportEntry importSpecifier(final String importName, final String localName) {
+            return new ImportEntry(null, importName, localName);
+        }
+
+        /**
+         * Creates a new import entry with the given import name.
+         *
+         * @param importName the import name
+         * @return the import entry
+         */
+        public static ImportEntry importSpecifier(final String importName) {
+            return importSpecifier(importName, importName);
+        }
+
+        /**
+         * Returns a copy of this import entry with the given module request.
+         *
+         * @param moduleRequest the module request
+         * @return the new import entry
+         */
+        public ImportEntry withFrom(@SuppressWarnings("hiding") final String moduleRequest) {
+            return new ImportEntry(moduleRequest, importName, localName);
+        }
+
+        /**
+         * Returns the entry's module request.
+         *
+         * @return the module request
+         */
+        public String getModuleRequest() {
+            return moduleRequest;
+        }
+
+        /**
+         * Returns the entry's import name.
+         *
+         * @return the import name
+         */
+        public String getImportName() {
+            return importName;
+        }
+
+        /**
+         * Returns the entry's local name.
+         *
+         * @return the local name
+         */
+        public String getLocalName() {
+            return localName;
+        }
+
+        @Override
+        public String toString() {
+            return "ImportEntry [moduleRequest=" + moduleRequest + ", importName=" + importName + ", localName=" + localName + "]";
+        }
+    }
+
+    private final List<String> requestedModules;
+    private final List<ImportEntry> importEntries;
+    private final List<ExportEntry> localExportEntries;
+    private final List<ExportEntry> indirectExportEntries;
+    private final List<ExportEntry> starExportEntries;
+
+    /**
+     * Creates a module with the specified requested modules and import and export entries.
+     *
+     * @param requestedModules the requested modules
+     * @param importEntries the import entries
+     * @param localExportEntries local export entries
+     * @param indirectExportEntries indirect export entries
+     * @param starExportEntries star export entries
+     */
+    public Module(final List<String> requestedModules, final List<ImportEntry> importEntries, final List<ExportEntry> localExportEntries,
+                  final List<ExportEntry> indirectExportEntries, final List<ExportEntry> starExportEntries) {
+        this.requestedModules = requestedModules;
+        this.importEntries = importEntries;
+        this.localExportEntries = localExportEntries;
+        this.indirectExportEntries = indirectExportEntries;
+        this.starExportEntries = starExportEntries;
+    }
+
+    /**
+     * Returns the list of requested modules.
+     *
+     * @return the requested modules
+     */
+    public List<String> getRequestedModules() {
+        return requestedModules;
+    }
+
+    /**
+     * Returns the list of import entries.
+     *
+     * @return the import entries
+     */
+    public List<ImportEntry> getImportEntries() {
+        return importEntries;
+    }
+
+    /**
+     * Returns the list of local export entries.
+     *
+     * @return the local export entries
+     */
+    public List<ExportEntry> getLocalExportEntries() {
+        return localExportEntries;
+    }
+
+    /**
+     * Returns the list of indirect export entries.
+     *
+     * @return the indirect export entries
+     */
+    public List<ExportEntry> getIndirectExportEntries() {
+        return indirectExportEntries;
+    }
+
+    /**
+     * Returns the list of star export entries.
+     *
+     * @return the star export entries
+     */
+    public List<ExportEntry> getStarExportEntries() {
+        return starExportEntries;
+    }
+
+    @Override
+    public String toString() {
+        return "Module [requestedModules=" + requestedModules + ", importEntries=" + importEntries + ", localExportEntries=" + localExportEntries + ", indirectExportEntries=" +
+                indirectExportEntries + ", starExportEntries=" + starExportEntries + "]";
+    }
+}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/PropertyNode.java	Wed Jul 05 21:38:12 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/PropertyNode.java	Wed Apr 27 15:50:33 2016 +0200
@@ -36,7 +36,7 @@
     private static final long serialVersionUID = 1L;
 
     /** Property key. */
-    private final PropertyKey key;
+    private final Expression key;
 
     /** Property value. */
     private final Expression value;
@@ -47,6 +47,12 @@
     /** Property getter. */
     private final FunctionNode setter;
 
+    /** static property flag */
+    private final boolean isStatic;
+
+    /** Computed property flag */
+    private final boolean computed;
+
     /**
      * Constructor
      *
@@ -56,21 +62,27 @@
      * @param value   the value of this property
      * @param getter  getter function body
      * @param setter  setter function body
+     * @param isStatic is this a static property?
+     * @param computed is this a computed property?
      */
-    public PropertyNode(final long token, final int finish, final PropertyKey key, final Expression value, final FunctionNode getter, final FunctionNode setter) {
+    public PropertyNode(final long token, final int finish, final Expression key, final Expression value, final FunctionNode getter, final FunctionNode setter, final boolean isStatic, final boolean computed) {
         super(token, finish);
         this.key    = key;
         this.value  = value;
         this.getter = getter;
         this.setter = setter;
+        this.isStatic = isStatic;
+        this.computed = computed;
     }
 
-    private PropertyNode(final PropertyNode propertyNode, final PropertyKey key, final Expression value, final FunctionNode getter, final FunctionNode setter) {
+    private PropertyNode(final PropertyNode propertyNode, final Expression key, final Expression value, final FunctionNode getter, final FunctionNode setter, final boolean isStatic, final boolean computed) {
         super(propertyNode);
         this.key    = key;
         this.value  = value;
         this.getter = getter;
         this.setter = setter;
+        this.isStatic = isStatic;
+        this.computed = computed;
     }
 
     /**
@@ -78,14 +90,14 @@
      * @return key name
      */
     public String getKeyName() {
-        return key.getPropertyName();
+        return key instanceof PropertyKey ? ((PropertyKey) key).getPropertyName() : null;
     }
 
     @Override
     public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
         if (visitor.enterPropertyNode(this)) {
             return visitor.leavePropertyNode(
-                setKey((PropertyKey)((Node)key).accept(visitor)).
+                setKey((Expression) key.accept(visitor)).
                 setValue(value == null ? null : (Expression)value.accept(visitor)).
                 setGetter(getter == null ? null : (FunctionNode)getter.accept(visitor)).
                 setSetter(setter == null ? null : (FunctionNode)setter.accept(visitor)));
@@ -134,7 +146,7 @@
         if (this.getter == getter) {
             return this;
         }
-        return new PropertyNode(this, key, value, getter, setter);
+        return new PropertyNode(this, key, value, getter, setter, isStatic, computed);
     }
 
     /**
@@ -142,14 +154,14 @@
      * @return the key
      */
     public Expression getKey() {
-        return (Expression)key;
+        return key;
     }
 
-    private PropertyNode setKey(final PropertyKey key) {
+    private PropertyNode setKey(final Expression key) {
         if (this.key == key) {
             return this;
         }
-        return new PropertyNode(this, key, value, getter, setter);
+        return new PropertyNode(this, key, value, getter, setter, isStatic, computed);
     }
 
     /**
@@ -169,7 +181,7 @@
         if (this.setter == setter) {
             return this;
         }
-        return new PropertyNode(this, key, value, getter, setter);
+        return new PropertyNode(this, key, value, getter, setter, isStatic, computed);
     }
 
     /**
@@ -189,6 +201,24 @@
         if (this.value == value) {
             return this;
         }
-        return new PropertyNode(this, key, value, getter, setter);
-   }
+        return new PropertyNode(this, key, value, getter, setter, isStatic, computed);
+    }
+
+    /**
+     * Returns true if this is a static property.
+     *
+     * @return true if static flag is set
+     */
+    public boolean isStatic() {
+        return isStatic;
+    }
+
+    /**
+     * Returns true if this is a computed property.
+     *
+     * @return true if the computed flag is set
+     */
+    public boolean isComputed() {
+        return computed;
+    }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java	Wed Jul 05 21:38:12 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java	Wed Apr 27 15:50:33 2016 +0200
@@ -133,8 +133,8 @@
             return enterASSIGN_SHR(binaryNode);
         case ASSIGN_SUB:
             return enterASSIGN_SUB(binaryNode);
-        case BIND:
-            return enterBIND(binaryNode);
+        case ARROW:
+            return enterARROW(binaryNode);
         case BIT_AND:
             return enterBIT_AND(binaryNode);
         case BIT_OR:
@@ -217,8 +217,8 @@
             return leaveASSIGN_SHR(binaryNode);
         case ASSIGN_SUB:
             return leaveASSIGN_SUB(binaryNode);
-        case BIND:
-            return leaveBIND(binaryNode);
+        case ARROW:
+            return leaveARROW(binaryNode);
         case BIT_AND:
             return leaveBIT_AND(binaryNode);
         case BIT_OR:
@@ -735,22 +735,22 @@
     }
 
     /**
-     * Binary enter - callback for entering a bind operator
+     * Binary enter - callback for entering a arrow operator
      *
      * @param  binaryNode the node
      * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public boolean enterBIND(final BinaryNode binaryNode) {
+    public boolean enterARROW(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
     /**
-     * Binary leave - callback for leaving a bind operator
+     * Binary leave - callback for leaving a arrow operator
      *
      * @param  binaryNode the node
      * @return processed node, which will replace the original one, or the original node
      */
-    public Node leaveBIND(final BinaryNode binaryNode) {
+    public Node leaveARROW(final BinaryNode binaryNode) {
         return leaveDefault(binaryNode);
     }
 
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeVisitor.java	Wed Jul 05 21:38:12 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeVisitor.java	Wed Apr 27 15:50:33 2016 +0200
@@ -33,6 +33,7 @@
 import jdk.nashorn.internal.ir.CallNode;
 import jdk.nashorn.internal.ir.CaseNode;
 import jdk.nashorn.internal.ir.CatchNode;
+import jdk.nashorn.internal.ir.ClassNode;
 import jdk.nashorn.internal.ir.ContinueNode;
 import jdk.nashorn.internal.ir.DebuggerNode;
 import jdk.nashorn.internal.ir.EmptyNode;
@@ -897,5 +898,23 @@
         return leaveDefault(withNode);
     }
 
+    /**
+     * Callback for entering a ClassNode
+     *
+     * @param  classNode  the node
+     * @return true if traversal should continue and node children be traversed, false otherwise
+     */
+    public boolean enterClassNode(final ClassNode classNode) {
+        return enterDefault(classNode);
+    }
 
+    /**
+     * Callback for leaving a ClassNode
+     *
+     * @param  classNode  the node
+     * @return processed node, which will replace the original one, or the original node
+     */
+    public Node leaveClassNode(final ClassNode classNode) {
+        return leaveDefault(classNode);
+    }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java	Wed Jul 05 21:38:12 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java	Wed Apr 27 15:50:33 2016 +0200
@@ -28,35 +28,55 @@
 import static jdk.nashorn.internal.codegen.CompilerConstants.ANON_FUNCTION_PREFIX;
 import static jdk.nashorn.internal.codegen.CompilerConstants.EVAL;
 import static jdk.nashorn.internal.codegen.CompilerConstants.PROGRAM;
+import static jdk.nashorn.internal.parser.TokenType.ARROW;
 import static jdk.nashorn.internal.parser.TokenType.ASSIGN;
 import static jdk.nashorn.internal.parser.TokenType.CASE;
 import static jdk.nashorn.internal.parser.TokenType.CATCH;
+import static jdk.nashorn.internal.parser.TokenType.CLASS;
 import static jdk.nashorn.internal.parser.TokenType.COLON;
 import static jdk.nashorn.internal.parser.TokenType.COMMARIGHT;
+import static jdk.nashorn.internal.parser.TokenType.COMMENT;
 import static jdk.nashorn.internal.parser.TokenType.CONST;
 import static jdk.nashorn.internal.parser.TokenType.DECPOSTFIX;
 import static jdk.nashorn.internal.parser.TokenType.DECPREFIX;
+import static jdk.nashorn.internal.parser.TokenType.ELLIPSIS;
 import static jdk.nashorn.internal.parser.TokenType.ELSE;
 import static jdk.nashorn.internal.parser.TokenType.EOF;
 import static jdk.nashorn.internal.parser.TokenType.EOL;
+import static jdk.nashorn.internal.parser.TokenType.EQ_STRICT;
+import static jdk.nashorn.internal.parser.TokenType.ESCSTRING;
+import static jdk.nashorn.internal.parser.TokenType.EXPORT;
+import static jdk.nashorn.internal.parser.TokenType.EXTENDS;
 import static jdk.nashorn.internal.parser.TokenType.FINALLY;
 import static jdk.nashorn.internal.parser.TokenType.FUNCTION;
 import static jdk.nashorn.internal.parser.TokenType.IDENT;
 import static jdk.nashorn.internal.parser.TokenType.IF;
+import static jdk.nashorn.internal.parser.TokenType.IMPORT;
 import static jdk.nashorn.internal.parser.TokenType.INCPOSTFIX;
 import static jdk.nashorn.internal.parser.TokenType.LBRACE;
+import static jdk.nashorn.internal.parser.TokenType.LBRACKET;
 import static jdk.nashorn.internal.parser.TokenType.LET;
 import static jdk.nashorn.internal.parser.TokenType.LPAREN;
+import static jdk.nashorn.internal.parser.TokenType.MUL;
+import static jdk.nashorn.internal.parser.TokenType.PERIOD;
 import static jdk.nashorn.internal.parser.TokenType.RBRACE;
 import static jdk.nashorn.internal.parser.TokenType.RBRACKET;
 import static jdk.nashorn.internal.parser.TokenType.RPAREN;
 import static jdk.nashorn.internal.parser.TokenType.SEMICOLON;
+import static jdk.nashorn.internal.parser.TokenType.SPREAD_ARRAY;
+import static jdk.nashorn.internal.parser.TokenType.STATIC;
+import static jdk.nashorn.internal.parser.TokenType.STRING;
+import static jdk.nashorn.internal.parser.TokenType.SUPER;
 import static jdk.nashorn.internal.parser.TokenType.TEMPLATE;
 import static jdk.nashorn.internal.parser.TokenType.TEMPLATE_HEAD;
 import static jdk.nashorn.internal.parser.TokenType.TEMPLATE_MIDDLE;
 import static jdk.nashorn.internal.parser.TokenType.TEMPLATE_TAIL;
 import static jdk.nashorn.internal.parser.TokenType.TERNARY;
+import static jdk.nashorn.internal.parser.TokenType.VAR;
+import static jdk.nashorn.internal.parser.TokenType.VOID;
 import static jdk.nashorn.internal.parser.TokenType.WHILE;
+import static jdk.nashorn.internal.parser.TokenType.YIELD;
+import static jdk.nashorn.internal.parser.TokenType.YIELD_STAR;
 
 import java.io.Serializable;
 import java.util.ArrayDeque;
@@ -68,6 +88,8 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
+import java.util.function.Consumer;
 import jdk.nashorn.internal.codegen.CompilerConstants;
 import jdk.nashorn.internal.codegen.Namespace;
 import jdk.nashorn.internal.ir.AccessNode;
@@ -79,11 +101,13 @@
 import jdk.nashorn.internal.ir.CallNode;
 import jdk.nashorn.internal.ir.CaseNode;
 import jdk.nashorn.internal.ir.CatchNode;
+import jdk.nashorn.internal.ir.ClassNode;
 import jdk.nashorn.internal.ir.ContinueNode;
 import jdk.nashorn.internal.ir.DebuggerNode;
 import jdk.nashorn.internal.ir.EmptyNode;
 import jdk.nashorn.internal.ir.ErrorNode;
 import jdk.nashorn.internal.ir.Expression;
+import jdk.nashorn.internal.ir.ExpressionList;
 import jdk.nashorn.internal.ir.ExpressionStatement;
 import jdk.nashorn.internal.ir.ForNode;
 import jdk.nashorn.internal.ir.FunctionNode;
@@ -92,7 +116,9 @@
 import jdk.nashorn.internal.ir.IndexNode;
 import jdk.nashorn.internal.ir.JoinPredecessorExpression;
 import jdk.nashorn.internal.ir.LabelNode;
+import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.LiteralNode;
+import jdk.nashorn.internal.ir.Module;
 import jdk.nashorn.internal.ir.Node;
 import jdk.nashorn.internal.ir.ObjectNode;
 import jdk.nashorn.internal.ir.PropertyKey;
@@ -110,6 +136,7 @@
 import jdk.nashorn.internal.ir.WithNode;
 import jdk.nashorn.internal.ir.debug.ASTWriter;
 import jdk.nashorn.internal.ir.debug.PrintVisitor;
+import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.runtime.Context;
 import jdk.nashorn.internal.runtime.ErrorManager;
 import jdk.nashorn.internal.runtime.JSErrorType;
@@ -254,6 +281,14 @@
     }
 
     /**
+     * Set up first token. Skips opening EOL.
+     */
+    private void scanFirstToken() {
+        k = -1;
+        next();
+    }
+
+    /**
      * Execute parse and return the resulting function node.
      * Errors will be thrown and the error manager will contain information
      * if parsing should fail
@@ -280,9 +315,7 @@
             lexer.line = lexer.pendingLine = lineOffset + 1;
             line = lineOffset;
 
-            // Set up first token (skips opening EOL.)
-            k = -1;
-            next();
+            scanFirstToken();
             // Begin parse.
             return program(scriptName, allowPropertyFunction);
         } catch (final Exception e) {
@@ -301,6 +334,44 @@
     }
 
     /**
+     * Parse and return the resulting module.
+     * Errors will be thrown and the error manager will contain information
+     * if parsing should fail
+     *
+     * @param moduleName name for the module, given to the parsed FunctionNode
+     * @param startPos start position in source
+     * @param len length of parse
+     *
+     * @return function node resulting from successful parse
+     */
+    public FunctionNode parseModule(final String moduleName, final int startPos, final int len) {
+        try {
+            stream = new TokenStream();
+            lexer  = new Lexer(source, startPos, len, stream, scripting && !env._no_syntax_extensions, env._es6, reparsedFunction != null);
+            lexer.line = lexer.pendingLine = lineOffset + 1;
+            line = lineOffset;
+
+            scanFirstToken();
+            // Begin parse.
+            return module(moduleName);
+        } catch (final Exception e) {
+            handleParseException(e);
+
+            return null;
+        }
+    }
+
+    /**
+     * Entry point for parsing a module.
+     *
+     * @param moduleName the module name
+     * @return the parsed module
+     */
+    public FunctionNode parseModule(final String moduleName) {
+        return parseModule(moduleName, 0, source.getLength());
+    }
+
+    /**
      * Parse and return the list of function parameter list. A comma
      * separated list of function parameter identifiers is expected to be parsed.
      * Errors will be thrown and the error manager will contain information
@@ -314,11 +385,9 @@
             stream = new TokenStream();
             lexer  = new Lexer(source, stream, scripting && !env._no_syntax_extensions, env._es6);
 
-            // Set up first token (skips opening EOL.)
-            k = -1;
-            next();
-
-            return formalParameterList(TokenType.EOF);
+            scanFirstToken();
+
+            return formalParameterList(TokenType.EOF, false);
         } catch (final Exception e) {
             handleParseException(e);
             return null;
@@ -339,9 +408,7 @@
             lexer  = new Lexer(source, stream, scripting && !env._no_syntax_extensions, env._es6);
             final int functionLine = line;
 
-            // Set up first token (skips opening EOL.)
-            k = -1;
-            next();
+            scanFirstToken();
 
             // Make a fake token for the function.
             final long functionToken = Token.toDesc(FUNCTION, 0, source.getLength());
@@ -432,7 +499,7 @@
         }
 
         // Skip to a recovery point.
-loop:
+        loop:
         while (true) {
             switch (type) {
             case EOF:
@@ -474,7 +541,7 @@
         sb.append(ident.getName());
 
         final String name = namespace.uniqueName(sb.toString());
-        assert parentFunction != null || name.equals(PROGRAM.symbolName()) || name.startsWith(RecompilableScriptFunctionData.RECOMPILATION_PREFIX) : "name = " + name;
+        assert parentFunction != null || name.equals(PROGRAM.symbolName()) : "name = " + name;
 
         int flags = 0;
         if (isStrictMode) {
@@ -489,7 +556,8 @@
         return functionNode;
     }
 
-    private FunctionNode createFunctionNode(final ParserContextFunctionNode function, final long startToken, final IdentNode ident, final List<IdentNode> parameters, final FunctionNode.Kind kind, final int functionLine, final Block body){
+    private FunctionNode createFunctionNode(final ParserContextFunctionNode function, final long startToken, final IdentNode ident, final List<IdentNode> parameters, final FunctionNode.Kind kind, final int functionLine, final Block body) {
+        // assert body.isFunctionBody() || body.getFlag(Block.IS_PARAMETER_BLOCK) && ((BlockStatement) body.getLastStatement()).getBlock().isFunctionBody();
         // Start new block.
         final FunctionNode functionNode =
             new FunctionNode(
@@ -506,7 +574,9 @@
                 kind,
                 function.getFlags(),
                 body,
-                function.getEndParserState());
+                function.getEndParserState(),
+                function.getModule(),
+                function.getDebugFlags());
 
         printAST(functionNode);
 
@@ -544,23 +614,39 @@
             expect(RBRACE);
         }
 
-        final int flags = newBlock.getFlags() | (needsBraces? 0 : Block.IS_SYNTHETIC);
+        final int flags = newBlock.getFlags() | (needsBraces ? 0 : Block.IS_SYNTHETIC);
         return new Block(blockToken, finish, flags, newBlock.getStatements());
     }
 
+    /**
+     * Get the statements in a case clause.
+     */
+    private List<Statement> caseStatementList() {
+        final ParserContextBlockNode newBlock = newBlock();
+        try {
+            statementList();
+        } finally {
+            restoreBlock(newBlock);
+        }
+        return newBlock.getStatements();
+    }
 
     /**
      * Get all the statements generated by a single statement.
      * @return Statements.
      */
     private Block getStatement() {
+        return getStatement(false);
+    }
+
+    private Block getStatement(boolean labelledStatement) {
         if (type == LBRACE) {
             return getBlock(true);
         }
         // Set up new block. Captures first token.
         final ParserContextBlockNode newBlock = newBlock();
         try {
-            statement(false, false, true);
+            statement(false, false, true, labelledStatement);
         } finally {
             restoreBlock(newBlock);
         }
@@ -576,6 +662,9 @@
 
         if (EVAL.symbolName().equals(name)) {
             markEval(lc);
+        } else if (SUPER.getName().equals(name)) {
+            assert ident.isDirectSuper();
+            markSuperCall(lc);
         }
     }
 
@@ -585,7 +674,8 @@
      */
     private void detectSpecialProperty(final IdentNode ident) {
         if (isArguments(ident)) {
-            lc.getCurrentFunction().setFlag(FunctionNode.USES_ARGUMENTS);
+            // skip over arrow functions, e.g. function f() { return (() => arguments.length)(); }
+            getCurrentNonArrowFunction().setFlag(FunctionNode.USES_ARGUMENTS);
         }
     }
 
@@ -593,11 +683,15 @@
         return env._es6;
     }
 
+    private boolean isES6() {
+        return env._es6;
+    }
+
     private static boolean isArguments(final String name) {
         return ARGUMENTS_NAME.equals(name);
     }
 
-    private static boolean isArguments(final IdentNode ident) {
+    static boolean isArguments(final IdentNode ident) {
         return isArguments(ident.getName());
     }
 
@@ -634,20 +728,20 @@
         case ASSIGN_SHL:
         case ASSIGN_SHR:
         case ASSIGN_SUB:
-            if (!(lhs instanceof AccessNode ||
-                  lhs instanceof IndexNode ||
-                  lhs instanceof IdentNode)) {
-                return referenceError(lhs, rhs, env._early_lvalue_error);
-            }
-
             if (lhs instanceof IdentNode) {
                 if (!checkIdentLValue((IdentNode)lhs)) {
                     return referenceError(lhs, rhs, false);
                 }
-                verifyStrictIdent((IdentNode)lhs, "assignment");
+                verifyIdent((IdentNode)lhs, "assignment");
+                break;
+            } else if (lhs instanceof AccessNode || lhs instanceof IndexNode) {
+                break;
+            } else if (opType == ASSIGN && isDestructuringLhs(lhs)) {
+                verifyDestructuringAssignmentPattern(lhs, "assignment");
+                break;
+            } else {
+                return referenceError(lhs, rhs, env._early_lvalue_error);
             }
-            break;
-
         default:
             break;
         }
@@ -659,6 +753,114 @@
         return new BinaryNode(op, lhs, rhs);
     }
 
+    private boolean isDestructuringLhs(Expression lhs) {
+        if (lhs instanceof ObjectNode || lhs instanceof LiteralNode.ArrayLiteralNode) {
+            return isES6();
+        }
+        return false;
+    }
+
+    private void verifyDestructuringAssignmentPattern(Expression pattern, String contextString) {
+        assert pattern instanceof ObjectNode || pattern instanceof LiteralNode.ArrayLiteralNode;
+        pattern.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+            @Override
+            public boolean enterLiteralNode(LiteralNode<?> literalNode) {
+                if (literalNode.isArray()) {
+                    boolean restElement = false;
+                    for (Expression element : literalNode.getElementExpressions()) {
+                        if (element != null) {
+                            if (restElement) {
+                                throw error(String.format("Unexpected element after rest element"), element.getToken());
+                            }
+                            if (element.isTokenType(SPREAD_ARRAY)) {
+                                restElement = true;
+                                Expression lvalue = ((UnaryNode) element).getExpression();
+                                if (!checkValidLValue(lvalue, contextString)) {
+                                    throw error(AbstractParser.message("invalid.lvalue"), lvalue.getToken());
+                                }
+                            }
+                            element.accept(this);
+                        }
+                    }
+                    return false;
+                } else {
+                    return enterDefault(literalNode);
+                }
+            }
+
+            @Override
+            public boolean enterObjectNode(ObjectNode objectNode) {
+                return true;
+            }
+
+            @Override
+            public boolean enterPropertyNode(PropertyNode propertyNode) {
+                if (propertyNode.getValue() != null) {
+                    propertyNode.getValue().accept(this);
+                    return false;
+                } else {
+                    return enterDefault(propertyNode);
+                }
+            }
+
+            @Override
+            public boolean enterIdentNode(IdentNode identNode) {
+                verifyIdent(identNode, contextString);
+                if (!checkIdentLValue(identNode)) {
+                    referenceError(identNode, null, true);
+                    return false;
+                }
+                return false;
+            }
+
+            @Override
+            public boolean enterAccessNode(AccessNode accessNode) {
+                return false;
+            }
+
+            @Override
+            public boolean enterIndexNode(IndexNode indexNode) {
+                return false;
+            }
+
+            @Override
+            public boolean enterBinaryNode(BinaryNode binaryNode) {
+                if (binaryNode.isTokenType(ASSIGN)) {
+                    binaryNode.lhs().accept(this);
+                    // Initializer(rhs) can be any AssignmentExpression
+                    return false;
+                } else {
+                    return enterDefault(binaryNode);
+                }
+            }
+
+            @Override
+            public boolean enterUnaryNode(UnaryNode unaryNode) {
+                if (unaryNode.isTokenType(SPREAD_ARRAY)) {
+                    // rest element
+                    return true;
+                } else {
+                    return enterDefault(unaryNode);
+                }
+            }
+
+            @Override
+            protected boolean enterDefault(Node node) {
+                throw error(String.format("unexpected node in AssignmentPattern: %s", node));
+            }
+        });
+    }
+
+    private static Expression newBinaryExpression(final long op, final Expression lhs, final Expression rhs) {
+        final TokenType opType = Token.descType(op);
+
+        // Build up node.
+        if (BinaryNode.isLogical(opType)) {
+            return new BinaryNode(op, new JoinPredecessorExpression(lhs), new JoinPredecessorExpression(rhs));
+        }
+        return new BinaryNode(op, lhs, rhs);
+    }
+
 
     /**
      * Reduce increment/decrement to simpler operations.
@@ -717,7 +919,7 @@
 
         restoreBlock(body);
         body.setFlag(Block.NEEDS_SCOPE);
-        final Block programBody = new Block(functionToken, finish, body.getFlags() | Block.IS_SYNTHETIC, body.getStatements());
+        final Block programBody = new Block(functionToken, finish, body.getFlags() | Block.IS_SYNTHETIC | Block.IS_BODY, body.getStatements());
         lc.pop(script);
         script.setLastToken(token);
 
@@ -776,7 +978,7 @@
 
                 try {
                     // Get the next element.
-                    statement(true, allowPropertyFunction, false);
+                    statement(true, allowPropertyFunction, false, false);
                     allowPropertyFunction = false;
 
                     // check for directive prologues
@@ -816,16 +1018,16 @@
 
                                     // verify that function name as well as parameter names
                                     // satisfy strict mode restrictions.
-                                    verifyStrictIdent(function.getIdent(), "function name");
+                                    verifyIdent(function.getIdent(), "function name");
                                     for (final IdentNode param : function.getParameters()) {
-                                        verifyStrictIdent(param, "function parameter");
+                                        verifyIdent(param, "function parameter");
                                     }
                                 }
                             } else if (Context.DEBUG) {
-                                final int flag = FunctionNode.getDirectiveFlag(directive);
-                                if (flag != 0) {
+                                final int debugFlag = FunctionNode.getDirectiveFlag(directive);
+                                if (debugFlag != 0) {
                                     final ParserContextFunctionNode function = lc.getCurrentFunction();
-                                    function.setFlag(flag);
+                                    function.setDebugFlag(debugFlag);
                                 }
                             }
                         }
@@ -849,29 +1051,53 @@
     }
 
     /**
+     * Parse any of the basic statement types.
+     *
      * Statement :
-     *      Block
+     *      BlockStatement
      *      VariableStatement
      *      EmptyStatement
      *      ExpressionStatement
      *      IfStatement
-     *      IterationStatement
+     *      BreakableStatement
      *      ContinueStatement
      *      BreakStatement
      *      ReturnStatement
      *      WithStatement
      *      LabelledStatement
-     *      SwitchStatement
      *      ThrowStatement
      *      TryStatement
      *      DebuggerStatement
      *
-     * see 12
+     * BreakableStatement :
+     *      IterationStatement
+     *      SwitchStatement
+     *
+     * BlockStatement :
+     *      Block
+     *
+     * Block :
+     *      { StatementList opt }
      *
-     * Parse any of the basic statement types.
+     * StatementList :
+     *      StatementListItem
+     *      StatementList StatementListItem
+     *
+     * StatementItem :
+     *      Statement
+     *      Declaration
+     *
+     * Declaration :
+     *     HoistableDeclaration
+     *     ClassDeclaration
+     *     LexicalDeclaration
+     *
+     * HoistableDeclaration :
+     *     FunctionDeclaration
+     *     GeneratorDeclaration
      */
     private void statement() {
-        statement(false, false, false);
+        statement(false, false, false, false);
     }
 
     /**
@@ -879,14 +1105,7 @@
      * @param allowPropertyFunction allow property "get" and "set" functions?
      * @param singleStatement are we in a single statement context?
      */
-    private void statement(final boolean topLevel, final boolean allowPropertyFunction, final boolean singleStatement) {
-        if (type == FUNCTION) {
-            // As per spec (ECMA section 12), function declarations as arbitrary statement
-            // is not "portable". Implementation can issue a warning or disallow the same.
-            functionExpression(true, topLevel);
-            return;
-        }
-
+    private void statement(final boolean topLevel, final boolean allowPropertyFunction, final boolean singleStatement, final boolean labelledStatement) {
         switch (type) {
         case LBRACE:
             block();
@@ -918,9 +1137,6 @@
         case RETURN:
             returnStatement();
             break;
-        case YIELD:
-            yieldStatement();
-            break;
         case WITH:
             withStatement();
             break;
@@ -941,13 +1157,32 @@
         case EOF:
             expect(SEMICOLON);
             break;
+        case FUNCTION:
+            // As per spec (ECMA section 12), function declarations as arbitrary statement
+            // is not "portable". Implementation can issue a warning or disallow the same.
+            if (singleStatement) {
+                // ES6 B.3.2 Labelled Function Declarations
+                // It is a Syntax Error if any strict mode source code matches this rule:
+                // LabelledItem : FunctionDeclaration.
+                if (!labelledStatement || isStrictMode) {
+                    throw error(AbstractParser.message("expected.stmt", "function declaration"), token);
+                }
+            }
+            functionExpression(true, topLevel || labelledStatement);
+            return;
         default:
-            if (useBlockScope() && (type == LET || type == CONST)) {
+            if (useBlockScope() && (type == LET && lookaheadIsLetDeclaration(false) || type == CONST)) {
                 if (singleStatement) {
                     throw error(AbstractParser.message("expected.stmt", type.getName() + " declaration"), token);
                 }
                 variableStatement(type);
                 break;
+            } else if (type == CLASS && isES6()) {
+                if (singleStatement) {
+                    throw error(AbstractParser.message("expected.stmt", "class declaration"), token);
+                }
+                classDeclaration(false);
+                break;
             }
             if (env._const_as_var && type == CONST) {
                 variableStatement(TokenType.VAR);
@@ -963,11 +1198,11 @@
                     final String ident = (String)getValue();
                     final long propertyToken = token;
                     final int propertyLine = line;
-                    if("get".equals(ident)) {
+                    if ("get".equals(ident)) {
                         next();
                         addPropertyFunctionStatement(propertyGetterFunction(propertyToken, propertyLine));
                         return;
-                    } else if("set".equals(ident)) {
+                    } else if ("set".equals(ident)) {
                         next();
                         addPropertyFunctionStatement(propertySetterFunction(propertyToken, propertyLine));
                         return;
@@ -986,6 +1221,267 @@
     }
 
     /**
+     * ClassDeclaration[Yield, Default] :
+     *   class BindingIdentifier[?Yield] ClassTail[?Yield]
+     *   [+Default] class ClassTail[?Yield]
+     */
+    private ClassNode classDeclaration(boolean isDefault) {
+        int classLineNumber = line;
+
+        ClassNode classExpression = classExpression(!isDefault);
+
+        if (!isDefault) {
+            VarNode classVar = new VarNode(classLineNumber, classExpression.getToken(), classExpression.getIdent().getFinish(), classExpression.getIdent(), classExpression, VarNode.IS_CONST);
+            appendStatement(classVar);
+        }
+        return classExpression;
+    }
+
+    /**
+     * ClassExpression[Yield] :
+     *   class BindingIdentifier[?Yield]opt ClassTail[?Yield]
+     */
+    private ClassNode classExpression(boolean isStatement) {
+        assert type == CLASS;
+        int classLineNumber = line;
+        long classToken = token;
+        next();
+
+        IdentNode className = null;
+        if (isStatement || type == IDENT) {
+            className = getIdent();
+        }
+
+        return classTail(classLineNumber, classToken, className);
+    }
+
+    private static final class ClassElementKey {
+        private final boolean isStatic;
+        private final String propertyName;
+
+        private ClassElementKey(boolean isStatic, String propertyName) {
+            this.isStatic = isStatic;
+            this.propertyName = propertyName;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + (isStatic ? 1231 : 1237);
+            result = prime * result + ((propertyName == null) ? 0 : propertyName.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof ClassElementKey) {
+                ClassElementKey other = (ClassElementKey) obj;
+                return this.isStatic == other.isStatic && Objects.equals(this.propertyName, other.propertyName);
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Parse ClassTail and ClassBody.
+     *
+     * ClassTail[Yield] :
+     *   ClassHeritage[?Yield]opt { ClassBody[?Yield]opt }
+     * ClassHeritage[Yield] :
+     *   extends LeftHandSideExpression[?Yield]
+     *
+     * ClassBody[Yield] :
+     *   ClassElementList[?Yield]
+     * ClassElementList[Yield] :
+     *   ClassElement[?Yield]
+     *   ClassElementList[?Yield] ClassElement[?Yield]
+     * ClassElement[Yield] :
+     *   MethodDefinition[?Yield]
+     *   static MethodDefinition[?Yield]
+     *   ;
+     */
+    private ClassNode classTail(final int classLineNumber, final long classToken, final IdentNode className) {
+        final boolean oldStrictMode = isStrictMode;
+        isStrictMode = true;
+        try {
+            Expression classHeritage = null;
+            if (type == EXTENDS) {
+                next();
+                classHeritage = leftHandSideExpression();
+            }
+
+            expect(LBRACE);
+
+            PropertyNode constructor = null;
+            final ArrayList<PropertyNode> classElements = new ArrayList<>();
+            final Map<ClassElementKey, Integer> keyToIndexMap = new HashMap<>();
+            for (;;) {
+                if (type == SEMICOLON) {
+                    next();
+                    continue;
+                }
+                if (type == RBRACE) {
+                    break;
+                }
+                final long classElementToken = token;
+                boolean isStatic = false;
+                if (type == STATIC) {
+                    isStatic = true;
+                    next();
+                }
+                boolean generator = false;
+                if (isES6() && type == MUL) {
+                    generator = true;
+                    next();
+                }
+                final PropertyNode classElement = methodDefinition(isStatic, classHeritage != null, generator);
+                if (classElement.isComputed()) {
+                    classElements.add(classElement);
+                } else if (!classElement.isStatic() && classElement.getKeyName().equals("constructor")) {
+                    if (constructor == null) {
+                        constructor = classElement;
+                    } else {
+                        throw error(AbstractParser.message("multiple.constructors"), classElementToken);
+                    }
+                } else {
+                    // Check for duplicate method definitions and combine accessor methods.
+                    // In ES6, a duplicate is never an error regardless of strict mode (in consequence of computed property names).
+
+                    final ClassElementKey key = new ClassElementKey(classElement.isStatic(), classElement.getKeyName());
+                    final Integer existing = keyToIndexMap.get(key);
+
+                    if (existing == null) {
+                        keyToIndexMap.put(key, classElements.size());
+                        classElements.add(classElement);
+                    } else {
+                        final PropertyNode existingProperty = classElements.get(existing);
+
+                        final Expression   value  = classElement.getValue();
+                        final FunctionNode getter = classElement.getGetter();
+                        final FunctionNode setter = classElement.getSetter();
+
+                        if (value != null || existingProperty.getValue() != null) {
+                            keyToIndexMap.put(key, classElements.size());
+                            classElements.add(classElement);
+                        } else if (getter != null) {
+                            assert existingProperty.getGetter() != null || existingProperty.getSetter() != null;
+                            classElements.set(existing, existingProperty.setGetter(getter));
+                        } else if (setter != null) {
+                            assert existingProperty.getGetter() != null || existingProperty.getSetter() != null;
+                            classElements.set(existing, existingProperty.setSetter(setter));
+                        }
+                    }
+                }
+            }
+
+            final long lastToken = token;
+            expect(RBRACE);
+
+            if (constructor == null) {
+                constructor = createDefaultClassConstructor(classLineNumber, classToken, lastToken, className, classHeritage != null);
+            }
+
+            classElements.trimToSize();
+            return new ClassNode(classLineNumber, classToken, finish, className, classHeritage, constructor, classElements);
+        } finally {
+            isStrictMode = oldStrictMode;
+        }
+    }
+
+    private PropertyNode createDefaultClassConstructor(int classLineNumber, long classToken, long lastToken, IdentNode className, boolean subclass) {
+        final int ctorFinish = finish;
+        final List<Statement> statements;
+        final List<IdentNode> parameters;
+        final long identToken = Token.recast(classToken, TokenType.IDENT);
+        if (subclass) {
+            final IdentNode superIdent = createIdentNode(identToken, ctorFinish, SUPER.getName()).setIsDirectSuper();
+            final IdentNode argsIdent = createIdentNode(identToken, ctorFinish, "args").setIsRestParameter();
+            final Expression spreadArgs = new UnaryNode(Token.recast(classToken, TokenType.SPREAD_ARGUMENT), argsIdent);
+            final CallNode superCall = new CallNode(classLineNumber, classToken, ctorFinish, superIdent, Collections.singletonList(spreadArgs), false);
+            statements = Collections.singletonList(new ExpressionStatement(classLineNumber, classToken, ctorFinish, superCall));
+            parameters = Collections.singletonList(argsIdent);
+        } else {
+            statements = Collections.emptyList();
+            parameters = Collections.emptyList();
+        }
+
+        final Block body = new Block(classToken, ctorFinish, Block.IS_BODY, statements);
+        final IdentNode ctorName = className != null ? className : createIdentNode(identToken, ctorFinish, "constructor");
+        final ParserContextFunctionNode function = createParserContextFunctionNode(ctorName, classToken, FunctionNode.Kind.NORMAL, classLineNumber, parameters);
+        function.setLastToken(lastToken);
+
+        function.setFlag(FunctionNode.ES6_IS_METHOD);
+        function.setFlag(FunctionNode.ES6_IS_CLASS_CONSTRUCTOR);
+        if (subclass) {
+            function.setFlag(FunctionNode.ES6_IS_SUBCLASS_CONSTRUCTOR);
+            function.setFlag(FunctionNode.ES6_HAS_DIRECT_SUPER);
+        }
+        if (className == null) {
+            function.setFlag(FunctionNode.IS_ANONYMOUS);
+        }
+
+        final PropertyNode constructor = new PropertyNode(classToken, ctorFinish, ctorName, createFunctionNode(
+                        function,
+                        classToken,
+                        ctorName,
+                        parameters,
+                        FunctionNode.Kind.NORMAL,
+                        classLineNumber,
+                        body
+                        ), null, null, false, false);
+        return constructor;
+    }
+
+    private PropertyNode methodDefinition(final boolean isStatic, final boolean subclass, final boolean generator) {
+        final long methodToken = token;
+        final int methodLine = line;
+        final boolean computed = type == LBRACKET;
+        final boolean isIdent = type == IDENT;
+        final Expression propertyName = propertyName();
+        int flags = FunctionNode.ES6_IS_METHOD;
+        if (!computed) {
+            final String name = ((PropertyKey)propertyName).getPropertyName();
+            if (!generator && isIdent && type != LPAREN && name.equals("get")) {
+                final PropertyFunction methodDefinition = propertyGetterFunction(methodToken, methodLine, flags);
+                verifyAllowedMethodName(methodDefinition.key, isStatic, methodDefinition.computed, generator, true);
+                return new PropertyNode(methodToken, finish, methodDefinition.key, null, methodDefinition.functionNode, null, isStatic, methodDefinition.computed);
+            } else if (!generator && isIdent && type != LPAREN && name.equals("set")) {
+                final PropertyFunction methodDefinition = propertySetterFunction(methodToken, methodLine, flags);
+                verifyAllowedMethodName(methodDefinition.key, isStatic, methodDefinition.computed, generator, true);
+                return new PropertyNode(methodToken, finish, methodDefinition.key, null, null, methodDefinition.functionNode, isStatic, methodDefinition.computed);
+            } else {
+                if (!isStatic && !generator && name.equals("constructor")) {
+                    flags |= FunctionNode.ES6_IS_CLASS_CONSTRUCTOR;
+                    if (subclass) {
+                        flags |= FunctionNode.ES6_IS_SUBCLASS_CONSTRUCTOR;
+                    }
+                }
+                verifyAllowedMethodName(propertyName, isStatic, computed, generator, false);
+            }
+        }
+        final PropertyFunction methodDefinition = propertyMethodFunction(propertyName, methodToken, methodLine, generator, flags, computed);
+        return new PropertyNode(methodToken, finish, methodDefinition.key, methodDefinition.functionNode, null, null, isStatic, computed);
+    }
+
+    /**
+     * ES6 14.5.1 Static Semantics: Early Errors.
+     */
+    private void verifyAllowedMethodName(final Expression key, final boolean isStatic, final boolean computed, final boolean generator, final boolean accessor) {
+        if (!computed) {
+            if (!isStatic && generator && ((PropertyKey) key).getPropertyName().equals("constructor")) {
+                throw error(AbstractParser.message("generator.constructor"), key.getToken());
+            }
+            if (!isStatic && accessor && ((PropertyKey) key).getPropertyName().equals("constructor")) {
+                throw error(AbstractParser.message("accessor.constructor"), key.getToken());
+            }
+            if (isStatic && ((PropertyKey) key).getPropertyName().equals("prototype")) {
+                throw error(AbstractParser.message("static.prototype.method"), key.getToken());
+            }
+        }
+    }
+
+    /**
      * block :
      *      { StatementList? }
      *
@@ -1008,7 +1504,7 @@
      */
     private void statementList() {
         // Accumulate statements until end of list. */
-loop:
+        loop:
         while (type != EOF) {
             switch (type) {
             case EOF:
@@ -1026,6 +1522,22 @@
     }
 
     /**
+     * Make sure that the identifier name used is allowed.
+     *
+     * @param ident         Identifier that is verified
+     * @param contextString String used in error message to give context to the user
+     */
+    private void verifyIdent(final IdentNode ident, final String contextString) {
+        verifyStrictIdent(ident, contextString);
+        if (isES6()) {
+            final TokenType tokenType = TokenLookup.lookupKeyword(ident.getName().toCharArray(), 0, ident.getName().length());
+            if (tokenType != IDENT && tokenType.getKind() != TokenKind.FUTURESTRICT) {
+                throw error(expectMessage(IDENT));
+            }
+        }
+    }
+
+    /**
      * Make sure that in strict mode, the identifier name used is allowed.
      *
      * @param ident         Identifier that is verified
@@ -1066,15 +1578,16 @@
      * Parse a VAR statement.
      * @param isStatement True if a statement (not used in a FOR.)
      */
-    private List<VarNode> variableStatement(final TokenType varType) {
-        return variableStatement(varType, true, -1);
+    private void variableStatement(final TokenType varType) {
+        variableDeclarationList(varType, true, -1);
     }
 
-    private List<VarNode> variableStatement(final TokenType varType, final boolean isStatement, final int sourceOrder) {
+    private List<Expression> variableDeclarationList(final TokenType varType, final boolean isStatement, final int sourceOrder) {
         // VAR tested in caller.
+        assert varType == VAR || varType == LET || varType == CONST;
         next();
 
-        final List<VarNode> vars = new ArrayList<>();
+        final List<Expression> bindings = new ArrayList<>();
         int varFlags = 0;
         if (varType == LET) {
             varFlags |= VarNode.IS_LET;
@@ -1082,13 +1595,29 @@
             varFlags |= VarNode.IS_CONST;
         }
 
+        Expression missingAssignment = null;
         while (true) {
             // Get starting token.
             final int  varLine  = line;
             final long varToken = token;
             // Get name of var.
-            final IdentNode name = getIdent();
-            verifyStrictIdent(name, "variable name");
+            if (type == YIELD && inGeneratorFunction()) {
+                expect(IDENT);
+            }
+
+            final String contextString = "variable name";
+            Expression binding = bindingIdentifierOrPattern(contextString);
+            final boolean isDestructuring = !(binding instanceof IdentNode);
+            if (isDestructuring) {
+                final int finalVarFlags = varFlags;
+                verifyDestructuringBindingPattern(binding, new Consumer<IdentNode>() {
+                    public void accept(final IdentNode identNode) {
+                        verifyIdent(identNode, contextString);
+                        final VarNode var = new VarNode(varLine, varToken, sourceOrder, identNode.getFinish(), identNode.setIsDeclaredHere(), null, finalVarFlags);
+                        appendStatement(var);
+                    }
+                });
+            }
 
             // Assume no init.
             Expression init = null;
@@ -1098,22 +1627,53 @@
                 next();
 
                 // Get initializer expression. Suppress IN if not statement.
-                defaultNames.push(name);
+                if (!isDestructuring) {
+                    defaultNames.push(binding);
+                }
                 try {
                     init = assignmentExpression(!isStatement);
                 } finally {
-                    defaultNames.pop();
+                    if (!isDestructuring) {
+                        defaultNames.pop();
+                    }
                 }
-            } else if (varType == CONST && isStatement) {
-                throw error(AbstractParser.message("missing.const.assignment", name.getName()));
+            } else if (isStatement) {
+                if (isDestructuring) {
+                    throw error(AbstractParser.message("missing.destructuring.assignment"), token);
+                } else if (varType == CONST) {
+                    throw error(AbstractParser.message("missing.const.assignment", ((IdentNode)binding).getName()));
+                }
+                // else, if we are in a for loop, delay checking until we know the kind of loop
             }
 
-            // Only set declaration flag on lexically scoped let/const as it adds runtime overhead.
-            final IdentNode actualName = varType == LET || varType == CONST ? name.setIsDeclaredHere() : name;
-            // Allocate var node.
-            final VarNode var = new VarNode(varLine, varToken, sourceOrder, finish, actualName, init, varFlags);
-            vars.add(var);
-            appendStatement(var);
+            if (!isDestructuring) {
+                assert init != null || varType != CONST || !isStatement;
+                final IdentNode ident = (IdentNode)binding;
+                if (!isStatement && ident.getName().equals("let")) {
+                    throw error(AbstractParser.message("let.binding.for")); //ES6 13.7.5.1
+                }
+                // Only set declaration flag on lexically scoped let/const as it adds runtime overhead.
+                final IdentNode name = varType == LET || varType == CONST ? ident.setIsDeclaredHere() : ident;
+                binding = name;
+                final VarNode var = new VarNode(varLine, varToken, sourceOrder, finish, name, init, varFlags);
+                appendStatement(var);
+                if (init == null && varType == CONST) {
+                    if (missingAssignment == null) {
+                        missingAssignment = binding;
+                    }
+                }
+            } else {
+                assert init != null || !isStatement;
+                binding = init == null ? binding : verifyAssignment(Token.recast(varToken, ASSIGN), binding, init);
+                if (isStatement) {
+                    appendStatement(new ExpressionStatement(varLine, binding.getToken(), finish, binding));
+                } else if (init == null) {
+                    if (missingAssignment == null) {
+                        missingAssignment = binding;
+                    }
+                }
+            }
+            bindings.add(binding);
 
             if (type != COMMARIGHT) {
                 break;
@@ -1124,9 +1684,128 @@
         // If is a statement then handle end of line.
         if (isStatement) {
             endOfLine();
+        } else {
+            if (type == SEMICOLON) {
+                // late check for missing assignment, now we know it's a for (init; test; modify) loop
+                if (missingAssignment != null) {
+                    if (missingAssignment instanceof IdentNode) {
+                        throw error(AbstractParser.message("missing.const.assignment", ((IdentNode)missingAssignment).getName()));
+                    } else {
+                        throw error(AbstractParser.message("missing.destructuring.assignment"), missingAssignment.getToken());
+                    }
+                }
+            }
         }
 
-        return vars;
+        return bindings;
+    }
+
+    private boolean isBindingIdentifier() {
+        return type == IDENT || isNonStrictModeIdent();
+    }
+
+    private IdentNode bindingIdentifier(final String contextString) {
+        final IdentNode name = getIdent();
+        verifyIdent(name, contextString);
+        return name;
+    }
+
+    private Expression bindingPattern() {
+        if (type == LBRACKET) {
+            return arrayLiteral();
+        } else if (type == LBRACE) {
+            return objectLiteral();
+        } else {
+            throw error(AbstractParser.message("expected.binding"));
+        }
+    }
+
+    private Expression bindingIdentifierOrPattern(final String contextString) {
+        if (isBindingIdentifier() || !isES6()) {
+            return bindingIdentifier(contextString);
+        } else {
+            return bindingPattern();
+        }
+    }
+
+    /**
+     * Verify destructuring variable declaration binding pattern and extract bound variable declarations.
+     */
+    private void verifyDestructuringBindingPattern(final Expression pattern, final Consumer<IdentNode> identifierCallback) {
+        assert pattern instanceof ObjectNode || pattern instanceof LiteralNode.ArrayLiteralNode;
+        pattern.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+            @Override
+            public boolean enterLiteralNode(final LiteralNode<?> literalNode) {
+                if (literalNode.isArray()) {
+                    boolean restElement = false;
+                    for (final Expression element : literalNode.getElementExpressions()) {
+                        if (restElement) {
+                            throw error(String.format("Unexpected element after rest element"), element.getToken());
+                        }
+                        if (element != null) {
+                            if (element.isTokenType(SPREAD_ARRAY)) {
+                                restElement = true;
+                                if (!(((UnaryNode) element).getExpression() instanceof IdentNode)) {
+                                    throw error(String.format("Expected a valid binding identifier"), element.getToken());
+
+                                }
+                            }
+                            element.accept(this);
+                        }
+                    }
+                    return false;
+                } else {
+                    return enterDefault(literalNode);
+                }
+            }
+
+            @Override
+            public boolean enterObjectNode(final ObjectNode objectNode) {
+                return true;
+            }
+
+            @Override
+            public boolean enterPropertyNode(final PropertyNode propertyNode) {
+                if (propertyNode.getValue() != null) {
+                    propertyNode.getValue().accept(this);
+                    return false;
+                } else {
+                    return enterDefault(propertyNode);
+                }
+            }
+
+            @Override
+            public boolean enterIdentNode(final IdentNode identNode) {
+                identifierCallback.accept(identNode);
+                return false;
+            }
+
+            @Override
+            public boolean enterBinaryNode(final BinaryNode binaryNode) {
+                if (binaryNode.isTokenType(ASSIGN)) {
+                    binaryNode.lhs().accept(this);
+                    // Initializer(rhs) can be any AssignmentExpression
+                    return false;
+                } else {
+                    return enterDefault(binaryNode);
+                }
+            }
+
+            @Override
+            public boolean enterUnaryNode(final UnaryNode unaryNode) {
+                if (unaryNode.isTokenType(SPREAD_ARRAY)) {
+                    // rest element
+                    return true;
+                } else {
+                    return enterDefault(unaryNode);
+                }
+            }
+
+            @Override
+            protected boolean enterDefault(final Node node) {
+                throw error(String.format("unexpected node in BindingPattern: %s", node));
+            }
+        });
     }
 
     /**
@@ -1230,7 +1909,7 @@
         final ParserContextLoopNode forNode = new ParserContextLoopNode();
         lc.push(forNode);
         Block body = null;
-        List<VarNode> vars = null;
+        List<Expression> vars = null;
         Expression init = null;
         JoinPredecessorExpression test = null;
         JoinPredecessorExpression modify = null;
@@ -1254,20 +1933,20 @@
             switch (type) {
             case VAR:
                 // Var declaration captured in for outer block.
-                vars = variableStatement(type, false, forStart);
+                vars = variableDeclarationList(type, false, forStart);
                 break;
             case SEMICOLON:
                 break;
             default:
-                if (useBlockScope() && (type == LET || type == CONST)) {
+                if (useBlockScope() && (type == LET && lookaheadIsLetDeclaration(true) || type == CONST)) {
                     flags |= ForNode.PER_ITERATION_SCOPE;
                     // LET/CONST declaration captured in container block created above.
-                    vars = variableStatement(type, false, forStart);
+                    vars = variableDeclarationList(type, false, forStart);
                     break;
                 }
                 if (env._const_as_var && type == CONST) {
                     // Var declaration captured in for outer block.
-                    vars = variableStatement(TokenType.VAR, false, forStart);
+                    vars = variableDeclarationList(TokenType.VAR, false, forStart);
                     break;
                 }
 
@@ -1309,7 +1988,11 @@
                 if (vars != null) {
                     // for (var i in obj)
                     if (vars.size() == 1) {
-                        init = new IdentNode(vars.get(0).getName());
+                        init = new IdentNode((IdentNode)vars.get(0));
+                        if (init.isTokenType(ASSIGN)) {
+                            throw error(AbstractParser.message("for.in.loop.initializer"), init.getToken());
+                        }
+                        assert init instanceof IdentNode || isDestructuringLhs(init);
                     } else {
                         // for (var i, j in obj) is invalid
                         throw error(AbstractParser.message("many.vars.in.for.in.loop", isForOf ? "of" : "in"), vars.get(1).getToken());
@@ -1351,10 +2034,9 @@
         } finally {
             lc.pop(forNode);
 
-            if (vars != null) {
-                for (final VarNode var : vars) {
-                    appendStatement(var);
-                }
+            for (final Statement var : forNode.getStatements()) {
+                assert var instanceof VarNode;
+                appendStatement(var);
             }
             if (body != null) {
                 appendStatement(new ForNode(forLine, forToken, body.getFinish(), body, (forNode.getFlags() | flags), init, test, modify));
@@ -1371,6 +2053,49 @@
         }
     }
 
+    private boolean checkValidLValue(final Expression init, final String contextString) {
+        if (init instanceof IdentNode) {
+            if (!checkIdentLValue((IdentNode)init)) {
+                return false;
+            }
+            verifyIdent((IdentNode)init, contextString);
+            return true;
+        } else if (init instanceof AccessNode || init instanceof IndexNode) {
+            return true;
+        } else if (isDestructuringLhs(init)) {
+            verifyDestructuringAssignmentPattern(init, contextString);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    private boolean lookaheadIsLetDeclaration(final boolean ofContextualKeyword) {
+        assert type == LET;
+        for (int i = 1;; i++) {
+            TokenType t = T(k + i);
+            switch (t) {
+            case EOL:
+            case COMMENT:
+                continue;
+            case IDENT:
+                if (ofContextualKeyword && isES6() && "of".equals(getValue(getToken(k + i)))) {
+                    return false;
+                }
+                // fall through
+            case LBRACKET:
+            case LBRACE:
+                return true;
+            default:
+                // accept future strict tokens in non-strict mode (including LET)
+                if (!isStrictMode && t.getKind() == TokenKind.FUTURESTRICT) {
+                    return true;
+                }
+                return false;
+            }
+        }
+    }
+
     /**
      * ...IterationStatement :
      *           ...
@@ -1559,7 +2284,7 @@
      */
     private void returnStatement() {
         // check for return outside function
-        if (lc.getCurrentFunction().getKind() == FunctionNode.Kind.SCRIPT) {
+        if (lc.getCurrentFunction().getKind() == FunctionNode.Kind.SCRIPT || lc.getCurrentFunction().getKind() == FunctionNode.Kind.MODULE) {
             throw error(AbstractParser.message("invalid.return"));
         }
 
@@ -1591,39 +2316,61 @@
     }
 
     /**
-     * YieldStatement :
-     *      yield Expression? ; // [no LineTerminator here]
-     *
-     * JavaScript 1.8
+     * Parse YieldExpression.
      *
-     * Parse YIELD statement.
+     * YieldExpression[In] :
+     *   yield
+     *   yield [no LineTerminator here] AssignmentExpression[?In, Yield]
+     *   yield [no LineTerminator here] * AssignmentExpression[?In, Yield]
      */
-    private void yieldStatement() {
+    private Expression yieldExpression(final boolean noIn) {
+        assert inGeneratorFunction();
         // Capture YIELD token.
-        final int  yieldLine  = line;
-        final long yieldToken = token;
+        long yieldToken = token;
         // YIELD tested in caller.
+        assert type == YIELD;
         nextOrEOL();
 
         Expression expression = null;
 
-        // SEMICOLON or expression.
+        boolean yieldAsterisk = false;
+        if (type == MUL) {
+            yieldAsterisk = true;
+            yieldToken = Token.recast(yieldToken, YIELD_STAR);
+            next();
+        }
+
         switch (type) {
         case RBRACE:
         case SEMICOLON:
         case EOL:
         case EOF:
-            break;
+        case COMMARIGHT:
+        case RPAREN:
+        case RBRACKET:
+        case COLON:
+            if (!yieldAsterisk) {
+                // treat (yield) as (yield void 0)
+                expression = newUndefinedLiteral(yieldToken, finish);
+                if (type == EOL) {
+                    next();
+                }
+                break;
+            } else {
+                // AssignmentExpression required, fall through
+            }
 
         default:
-            expression = expression();
+            expression = assignmentExpression(noIn);
             break;
         }
 
-        endOfLine();
-
         // Construct and add YIELD node.
-        appendStatement(new ReturnNode(yieldLine, yieldToken, finish, expression));
+        return new UnaryNode(yieldToken, expression);
+    }
+
+    private static UnaryNode newUndefinedLiteral(final long token, final int finish) {
+        return new UnaryNode(Token.recast(token, VOID), LiteralNode.newInstance(token, finish, 0));
     }
 
     /**
@@ -1679,11 +2426,15 @@
     private void switchStatement() {
         final int  switchLine  = line;
         final long switchToken = token;
+
+        // Block to capture variables declared inside the switch statement.
+        final ParserContextBlockNode switchBlock = newBlock();
+
         // SWITCH tested in caller.
         next();
 
         // Create and add switch statement.
-        final ParserContextSwitchNode switchNode= new ParserContextSwitchNode();
+        final ParserContextSwitchNode switchNode = new ParserContextSwitchNode();
         lc.push(switchNode);
 
         CaseNode defaultCase = null;
@@ -1727,7 +2478,7 @@
                 expect(COLON);
 
                 // Get CASE body.
-                final Block statements = getBlock(false);
+                final Block statements = getBlock(false); // TODO: List<Statement> statements = caseStatementList();
                 final CaseNode caseNode = new CaseNode(caseToken, finish, caseExpression, statements);
 
                 if (caseExpression == null) {
@@ -1740,9 +2491,11 @@
             next();
         } finally {
             lc.pop(switchNode);
+            restoreBlock(switchBlock);
         }
 
-        appendStatement(new SwitchNode(switchLine, switchToken, finish, expression, cases, defaultCase));
+        final SwitchNode switchStatement = new SwitchNode(switchLine, switchToken, finish, expression, cases, defaultCase);
+        appendStatement(new BlockStatement(switchLine, new Block(switchToken, finish, switchBlock.getFlags() | Block.IS_SYNTHETIC | Block.IS_SWITCH_BLOCK, switchStatement)));
     }
 
     /**
@@ -1769,7 +2522,7 @@
         Block body = null;
         try {
             lc.push(labelNode);
-            body = getStatement();
+            body = getStatement(true);
         } finally {
             assert lc.peek() instanceof ParserContextLabelNode;
             lc.pop(labelNode);
@@ -1935,13 +2688,19 @@
     /**
      * PrimaryExpression :
      *      this
-     *      Identifier
+     *      IdentifierReference
      *      Literal
      *      ArrayLiteral
      *      ObjectLiteral
      *      RegularExpressionLiteral
      *      TemplateLiteral
+     *      CoverParenthesizedExpressionAndArrowParameterList
+     *
+     * CoverParenthesizedExpressionAndArrowParameterList :
      *      ( Expression )
+     *      ( )
+     *      ( ... BindingIdentifier )
+     *      ( Expression , ... BindingIdentifier )
      *
      * Parse primary expression.
      * @return Expression node.
@@ -1956,7 +2715,7 @@
         case THIS:
             final String name = type.getName();
             next();
-            lc.getCurrentFunction().setFlag(FunctionNode.USES_THIS);
+            markThis(lc);
             return new IdentNode(primaryToken, finish, name);
         case IDENT:
             final IdentNode ident = getIdent();
@@ -1997,6 +2756,22 @@
         case LPAREN:
             next();
 
+            if (isES6()) {
+                if (type == RPAREN) {
+                    // ()
+                    nextOrEOL();
+                    expectDontAdvance(ARROW);
+                    return new ExpressionList(primaryToken, finish, Collections.emptyList());
+                } else if (type == ELLIPSIS) {
+                    // (...rest)
+                    final IdentNode restParam = formalParameterList(false).get(0);
+                    expectDontAdvance(RPAREN);
+                    nextOrEOL();
+                    expectDontAdvance(ARROW);
+                    return new ExpressionList(primaryToken, finish, Collections.singletonList(restParam));
+                }
+            }
+
             final Expression expression = expression();
 
             expect(RPAREN);
@@ -2073,8 +2848,9 @@
         final List<Expression> elements = new ArrayList<>();
         // Track elisions.
         boolean elision = true;
-loop:
+        loop:
         while (true) {
+            long spreadToken = 0;
             switch (type) {
             case RBRACKET:
                 next();
@@ -2093,14 +2869,24 @@
 
                 break;
 
+            case ELLIPSIS:
+                if (isES6()) {
+                    spreadToken = token;
+                    next();
+                }
+                // fall through
+
             default:
                 if (!elision) {
                     throw error(AbstractParser.message("expected.comma", type.getNameOrType()));
                 }
+
                 // Add expression element.
-                final Expression expression = assignmentExpression(false);
-
+                Expression expression = assignmentExpression(false);
                 if (expression != null) {
+                    if (spreadToken != 0) {
+                        expression = new UnaryNode(Token.recast(spreadToken, SPREAD_ARRAY), expression);
+                    }
                     elements.add(expression);
                 } else {
                     expect(RBRACKET);
@@ -2141,7 +2927,7 @@
 
         // Create a block for the object literal.
         boolean commaSeen = true;
-loop:
+        loop:
         while (true) {
             switch (type) {
                 case RBRACE:
@@ -2164,6 +2950,12 @@
                     commaSeen = false;
                     // Get and add the next property.
                     final PropertyNode property = propertyAssignment();
+
+                    if (property.isComputed()) {
+                        elements.add(property);
+                        break;
+                    }
+
                     final String key = property.getKeyName();
                     final Integer existing = map.get(key);
 
@@ -2185,36 +2977,23 @@
                     final FunctionNode prevGetter = existingProperty.getGetter();
                     final FunctionNode prevSetter = existingProperty.getSetter();
 
-                    // ECMA 11.1.5 strict mode restrictions
-                    if (isStrictMode && value != null && prevValue != null) {
-                        throw error(AbstractParser.message("property.redefinition", key), property.getToken());
-                    }
-
-                    final boolean isPrevAccessor = prevGetter != null || prevSetter != null;
-                    final boolean isAccessor     = getter != null     || setter != null;
-
-                    // data property redefined as accessor property
-                    if (prevValue != null && isAccessor) {
-                        throw error(AbstractParser.message("property.redefinition", key), property.getToken());
-                    }
-
-                    // accessor property redefined as data
-                    if (isPrevAccessor && value != null) {
-                        throw error(AbstractParser.message("property.redefinition", key), property.getToken());
-                    }
-
-                    if (isAccessor && isPrevAccessor) {
-                        if (getter != null && prevGetter != null ||
-                                setter != null && prevSetter != null) {
-                            throw error(AbstractParser.message("property.redefinition", key), property.getToken());
+                    if (!isES6()) {
+                        checkPropertyRedefinition(property, value, getter, setter, prevValue, prevGetter, prevSetter);
+                    } else {
+                        if (property.getKey() instanceof IdentNode && ((IdentNode)property.getKey()).isProtoPropertyName() &&
+                                        existingProperty.getKey() instanceof IdentNode && ((IdentNode)existingProperty.getKey()).isProtoPropertyName()) {
+                            throw error(AbstractParser.message("multiple.proto.key"), property.getToken());
                         }
                     }
 
-                    if (value != null) {
+                    if (value != null || prevValue != null) {
+                        map.put(key, elements.size());
                         elements.add(property);
                     } else if (getter != null) {
+                        assert prevGetter != null || prevSetter != null;
                         elements.set(existing, existingProperty.setGetter(getter));
                     } else if (setter != null) {
+                        assert prevGetter != null || prevSetter != null;
                         elements.set(existing, existingProperty.setSetter(setter));
                     }
                     break;
@@ -2224,18 +3003,43 @@
         return new ObjectNode(objectToken, finish, elements);
     }
 
+    private void checkPropertyRedefinition(final PropertyNode property, final Expression value, final FunctionNode getter, final FunctionNode setter, final Expression prevValue, final FunctionNode prevGetter, final FunctionNode prevSetter) {
+        // ECMA 11.1.5 strict mode restrictions
+        if (isStrictMode && value != null && prevValue != null) {
+            throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken());
+        }
+
+        final boolean isPrevAccessor = prevGetter != null || prevSetter != null;
+        final boolean isAccessor     = getter != null     || setter != null;
+
+        // data property redefined as accessor property
+        if (prevValue != null && isAccessor) {
+            throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken());
+        }
+
+        // accessor property redefined as data
+        if (isPrevAccessor && value != null) {
+            throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken());
+        }
+
+        if (isAccessor && isPrevAccessor) {
+            if (getter != null && prevGetter != null ||
+                    setter != null && prevSetter != null) {
+                throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken());
+            }
+        }
+    }
+
     /**
-     * PropertyName :
+     * LiteralPropertyName :
      *      IdentifierName
      *      StringLiteral
      *      NumericLiteral
      *
-     * See 11.1.5
-     *
      * @return PropertyName node
      */
     @SuppressWarnings("fallthrough")
-    private PropertyKey propertyName() {
+    private PropertyKey literalPropertyName() {
         switch (type) {
         case IDENT:
             return getIdent().setIsPropertyName();
@@ -2257,6 +3061,34 @@
     }
 
     /**
+     * ComputedPropertyName :
+     *      AssignmentExpression
+     *
+     * @return PropertyName node
+     */
+    private Expression computedPropertyName() {
+        expect(LBRACKET);
+        Expression expression = assignmentExpression(false);
+        expect(RBRACKET);
+        return expression;
+    }
+
+    /**
+     * PropertyName :
+     *      LiteralPropertyName
+     *      ComputedPropertyName
+     *
+     * @return PropertyName node
+     */
+    private Expression propertyName() {
+        if (type == LBRACKET && isES6()) {
+            return computedPropertyName();
+        } else {
+            return (Expression)literalPropertyName();
+        }
+    }
+
+    /**
      * PropertyAssignment :
      *      PropertyName : AssignmentExpression
      *      get PropertyName ( ) { FunctionBody }
@@ -2280,51 +3112,95 @@
         final long propertyToken = token;
         final int  functionLine  = line;
 
-        PropertyKey propertyName;
-
+        final Expression propertyName;
+        final boolean isIdentifier;
+
+        boolean generator = false;
+        if (type == MUL && isES6()) {
+            generator = true;
+            next();
+        }
+
+        final boolean computed = type == LBRACKET;
         if (type == IDENT) {
             // Get IDENT.
             final String ident = (String)expectValue(IDENT);
 
-            if (type != COLON) {
+            if (type != COLON && (type != LPAREN || !isES6())) {
                 final long getSetToken = propertyToken;
 
                 switch (ident) {
                 case "get":
                     final PropertyFunction getter = propertyGetterFunction(getSetToken, functionLine);
-                    return new PropertyNode(propertyToken, finish, getter.ident, null, getter.functionNode, null);
+                    return new PropertyNode(propertyToken, finish, getter.key, null, getter.functionNode, null, false, getter.computed);
 
                 case "set":
                     final PropertyFunction setter = propertySetterFunction(getSetToken, functionLine);
-                    return new PropertyNode(propertyToken, finish, setter.ident, null, null, setter.functionNode);
+                    return new PropertyNode(propertyToken, finish, setter.key, null, null, setter.functionNode, false, setter.computed);
                 default:
                     break;
                 }
             }
 
-            propertyName = createIdentNode(propertyToken, finish, ident).setIsPropertyName();
+            isIdentifier = true;
+            IdentNode identNode = createIdentNode(propertyToken, finish, ident).setIsPropertyName();
+            if (type == COLON && ident.equals("__proto__")) {
+                identNode = identNode.setIsProtoPropertyName();
+            }
+            propertyName = identNode;
         } else {
+            isIdentifier = isNonStrictModeIdent();
             propertyName = propertyName();
         }
 
-        expect(COLON);
-
-        defaultNames.push(propertyName);
-        try {
-            return new PropertyNode(propertyToken, finish, propertyName, assignmentExpression(false), null, null);
-        } finally {
-            defaultNames.pop();
+        Expression propertyValue;
+
+        if (generator) {
+            expectDontAdvance(LPAREN);
         }
+
+        if (type == LPAREN && isES6()) {
+            propertyValue = propertyMethodFunction(propertyName, propertyToken, functionLine, generator, FunctionNode.ES6_IS_METHOD, computed).functionNode;
+        } else if (isIdentifier && (type == COMMARIGHT || type == RBRACE || type == ASSIGN) && isES6()) {
+            propertyValue = createIdentNode(propertyToken, finish, ((IdentNode) propertyName).getPropertyName());
+            if (type == ASSIGN && isES6()) {
+                // TODO if not destructuring, this is a SyntaxError
+                final long assignToken = token;
+                next();
+                final Expression rhs = assignmentExpression(false);
+                propertyValue = verifyAssignment(assignToken, propertyValue, rhs);
+            }
+        } else {
+            expect(COLON);
+
+            defaultNames.push(propertyName);
+            try {
+                propertyValue = assignmentExpression(false);
+            } finally {
+                defaultNames.pop();
+            }
+        }
+
+        return new PropertyNode(propertyToken, finish, propertyName, propertyValue, null, null, false, computed);
     }
 
     private PropertyFunction propertyGetterFunction(final long getSetToken, final int functionLine) {
-        final PropertyKey getIdent = propertyName();
-        final String getterName = getIdent.getPropertyName();
-        final IdentNode getNameNode = createIdentNode(((Node)getIdent).getToken(), finish, NameCodec.encode("get " + getterName));
+        return propertyGetterFunction(getSetToken, functionLine, FunctionNode.ES6_IS_METHOD);
+    }
+
+    private PropertyFunction propertyGetterFunction(final long getSetToken, final int functionLine, final int flags) {
+        final boolean computed = type == LBRACKET;
+        final Expression propertyName = propertyName();
+        final String getterName = propertyName instanceof PropertyKey ? ((PropertyKey) propertyName).getPropertyName() : getDefaultValidFunctionName(functionLine, false);
+        final IdentNode getNameNode = createIdentNode((propertyName).getToken(), finish, NameCodec.encode("get " + getterName));
         expect(LPAREN);
         expect(RPAREN);
 
         final ParserContextFunctionNode functionNode = createParserContextFunctionNode(getNameNode, getSetToken, FunctionNode.Kind.GETTER, functionLine, Collections.<IdentNode>emptyList());
+        functionNode.setFlag(flags);
+        if (computed) {
+            functionNode.setFlag(FunctionNode.IS_ANONYMOUS);
+        }
         lc.push(functionNode);
 
         Block functionBody;
@@ -2345,20 +3221,25 @@
                 functionLine,
                 functionBody);
 
-        return new PropertyFunction(getIdent, function);
+        return new PropertyFunction(propertyName, function, computed);
     }
 
     private PropertyFunction propertySetterFunction(final long getSetToken, final int functionLine) {
-        final PropertyKey setIdent = propertyName();
-        final String setterName = setIdent.getPropertyName();
-        final IdentNode setNameNode = createIdentNode(((Node)setIdent).getToken(), finish, NameCodec.encode("set " + setterName));
+        return propertySetterFunction(getSetToken, functionLine, FunctionNode.ES6_IS_METHOD);
+    }
+
+    private PropertyFunction propertySetterFunction(final long getSetToken, final int functionLine, final int flags) {
+        final boolean computed = type == LBRACKET;
+        final Expression propertyName = propertyName();
+        final String setterName = propertyName instanceof PropertyKey ? ((PropertyKey) propertyName).getPropertyName() : getDefaultValidFunctionName(functionLine, false);
+        final IdentNode setNameNode = createIdentNode((propertyName).getToken(), finish, NameCodec.encode("set " + setterName));
         expect(LPAREN);
         // be sloppy and allow missing setter parameter even though
         // spec does not permit it!
         final IdentNode argIdent;
-        if (type == IDENT || isNonStrictModeIdent()) {
+        if (isBindingIdentifier()) {
             argIdent = getIdent();
-            verifyStrictIdent(argIdent, "setter argument");
+            verifyIdent(argIdent, "setter argument");
         } else {
             argIdent = null;
         }
@@ -2370,6 +3251,10 @@
 
 
         final ParserContextFunctionNode functionNode = createParserContextFunctionNode(setNameNode, getSetToken, FunctionNode.Kind.SETTER, functionLine, parameters);
+        functionNode.setFlag(flags);
+        if (computed) {
+            functionNode.setFlag(FunctionNode.IS_ANONYMOUS);
+        }
         lc.push(functionNode);
 
         Block functionBody;
@@ -2389,33 +3274,81 @@
                 functionLine,
                 functionBody);
 
-        return new PropertyFunction(setIdent, function);
+        return new PropertyFunction(propertyName, function, computed);
+    }
+
+    private PropertyFunction propertyMethodFunction(Expression key, final long methodToken, final int methodLine, final boolean generator, final int flags, boolean computed) {
+        final String methodName = key instanceof PropertyKey ? ((PropertyKey) key).getPropertyName() : getDefaultValidFunctionName(methodLine, false);
+        final IdentNode methodNameNode = createIdentNode(((Node)key).getToken(), finish, methodName);
+
+        FunctionNode.Kind functionKind = generator ? FunctionNode.Kind.GENERATOR : FunctionNode.Kind.NORMAL;
+        final ParserContextFunctionNode functionNode = createParserContextFunctionNode(methodNameNode, methodToken, functionKind, methodLine, null);
+        functionNode.setFlag(flags);
+        if (computed) {
+            functionNode.setFlag(FunctionNode.IS_ANONYMOUS);
+        }
+        lc.push(functionNode);
+
+        try {
+            final ParserContextBlockNode parameterBlock = newBlock();
+            final List<IdentNode> parameters;
+            try {
+                expect(LPAREN);
+                parameters = formalParameterList(generator);
+                functionNode.setParameters(parameters);
+                expect(RPAREN);
+            } finally {
+                restoreBlock(parameterBlock);
+            }
+
+            Block functionBody = functionBody(functionNode);
+
+            functionBody = maybeWrapBodyInParameterBlock(functionBody, parameterBlock);
+
+            final FunctionNode  function = createFunctionNode(
+                            functionNode,
+                            methodToken,
+                            methodNameNode,
+                            parameters,
+                            functionKind,
+                            methodLine,
+                            functionBody);
+            return new PropertyFunction(key, function, computed);
+        } finally {
+            lc.pop(functionNode);
+        }
     }
 
     private static class PropertyFunction {
-        final PropertyKey ident;
+        final Expression key;
         final FunctionNode functionNode;
-
-        PropertyFunction(final PropertyKey ident, final FunctionNode function) {
-            this.ident = ident;
+        final boolean computed;
+
+        PropertyFunction(final Expression key, final FunctionNode function, final boolean computed) {
+            this.key = key;
             this.functionNode = function;
+            this.computed = computed;
         }
     }
 
     /**
-     * Parse left hand side expression.
-     *
      * LeftHandSideExpression :
      *      NewExpression
      *      CallExpression
      *
      * CallExpression :
      *      MemberExpression Arguments
+     *      SuperCall
      *      CallExpression Arguments
      *      CallExpression [ Expression ]
      *      CallExpression . IdentifierName
-     *      CallExpression TemplateLiteral
+     *
+     * SuperCall :
+     *      super Arguments
      *
+     * See 11.2
+     *
+     * Parse left hand side expression.
      * @return Expression node.
      */
     private Expression leftHandSideExpression() {
@@ -2435,7 +3368,7 @@
             lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false);
         }
 
-loop:
+        loop:
         while (true) {
             // Capture token.
             callLine  = line;
@@ -2479,6 +3412,7 @@
                 // tagged template literal
                 final List<Expression> arguments = templateLiteralArgumentList();
 
+                // Create call node.
                 lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false);
 
                 break;
@@ -2506,6 +3440,20 @@
         // NEW is tested in caller.
         next();
 
+        if (type == PERIOD && isES6()) {
+            next();
+            if (type == IDENT && "target".equals(getValue())) {
+                if (lc.getCurrentFunction().isProgram()) {
+                    throw error(AbstractParser.message("new.target.in.function"), token);
+                }
+                next();
+                markNewTarget(lc);
+                return new IdentNode(newToken, finish, "new.target");
+            } else {
+                throw error(AbstractParser.message("expected.target"), token);
+            }
+        }
+
         // Get function base.
         final int  callLine    = line;
         final Expression constructor = memberExpression();
@@ -2541,21 +3489,33 @@
     }
 
     /**
-     * Parse member expression.
-     *
      * MemberExpression :
      *      PrimaryExpression
-     *      FunctionExpression
+     *        FunctionExpression
+     *        ClassExpression
+     *        GeneratorExpression
      *      MemberExpression [ Expression ]
      *      MemberExpression . IdentifierName
      *      MemberExpression TemplateLiteral
+     *      SuperProperty
+     *      MetaProperty
      *      new MemberExpression Arguments
      *
+     * SuperProperty :
+     *      super [ Expression ]
+     *      super . IdentifierName
+     *
+     * MetaProperty :
+     *      NewTarget
+     *
+     * Parse member expression.
      * @return Expression node.
      */
+    @SuppressWarnings("fallthrough")
     private Expression memberExpression() {
         // Prepare to build operation.
         Expression lhs;
+        boolean isSuper = false;
 
         switch (type) {
         case NEW:
@@ -2568,13 +3528,53 @@
             lhs = functionExpression(false, false);
             break;
 
+        case CLASS:
+            if (isES6()) {
+                lhs = classExpression(false);
+                break;
+            } else {
+                // fall through
+            }
+
+        case SUPER:
+            if (isES6()) {
+                final ParserContextFunctionNode currentFunction = getCurrentNonArrowFunction();
+                if (currentFunction.isMethod()) {
+                    long identToken = Token.recast(token, IDENT);
+                    next();
+                    lhs = createIdentNode(identToken, finish, SUPER.getName());
+
+                    switch (type) {
+                        case LBRACKET:
+                        case PERIOD:
+                            getCurrentNonArrowFunction().setFlag(FunctionNode.ES6_USES_SUPER);
+                            isSuper = true;
+                            break;
+                        case LPAREN:
+                            if (currentFunction.isSubclassConstructor()) {
+                                lhs = ((IdentNode)lhs).setIsDirectSuper();
+                                break;
+                            } else {
+                                // fall through to throw error
+                            }
+                        default:
+                            throw error(AbstractParser.message("invalid.super"), identToken);
+                    }
+                    break;
+                } else {
+                    // fall through
+                }
+            } else {
+                // fall through
+            }
+
         default:
             // Get primary expression.
             lhs = primaryExpression();
             break;
         }
 
-loop:
+        loop:
         while (true) {
             // Capture token.
             final long callToken = token;
@@ -2591,6 +3591,11 @@
                 // Create indexing node.
                 lhs = new IndexNode(callToken, finish, lhs, index);
 
+                if (isSuper) {
+                    isSuper = false;
+                    lhs = ((BaseNode) lhs).setIsSuper();
+                }
+
                 break;
             }
             case PERIOD: {
@@ -2605,6 +3610,11 @@
                 // Create property access node.
                 lhs = new AccessNode(callToken, finish, lhs, property.getName());
 
+                if (isSuper) {
+                    isSuper = false;
+                    lhs = ((BaseNode) lhs).setIsSuper();
+                }
+
                 break;
             }
             case TEMPLATE:
@@ -2632,7 +3642,9 @@
      *
      * ArgumentList :
      *      AssignmentExpression
+     *      ... AssignmentExpression
      *      ArgumentList , AssignmentExpression
+     *      ArgumentList , ... AssignmentExpression
      *
      * See 11.2
      *
@@ -2656,8 +3668,18 @@
                 first = false;
             }
 
+            long spreadToken = 0;
+            if (type == ELLIPSIS && isES6()) {
+                spreadToken = token;
+                next();
+            }
+
             // Get argument expression.
-            nodeList.add(assignmentExpression(false));
+            Expression expression = assignmentExpression(false);
+            if (spreadToken != 0) {
+                expression = new UnaryNode(Token.recast(spreadToken, TokenType.SPREAD_ARGUMENT), expression);
+            }
+            nodeList.add(expression);
         }
 
         expect(RPAREN);
@@ -2697,11 +3719,24 @@
         final long functionToken = token;
         final int  functionLine  = line;
         // FUNCTION is tested in caller.
+        assert type == FUNCTION;
         next();
 
+        boolean generator = false;
+        if (type == MUL && isES6()) {
+            generator = true;
+            next();
+        }
+
         IdentNode name = null;
 
-        if (type == IDENT || isNonStrictModeIdent()) {
+        if (isBindingIdentifier()) {
+            if (type == YIELD && ((!isStatement && generator) || (isStatement && inGeneratorFunction()))) {
+                // 12.1.1 Early SyntaxError if:
+                // GeneratorExpression with BindingIdentifier yield
+                // HoistableDeclaration with BindingIdentifier yield in generator function body
+                expect(IDENT);
+            }
             name = getIdent();
             verifyStrictIdent(name, "function name");
         } else if (isStatement) {
@@ -2723,25 +3758,36 @@
             isAnonymous = true;
         }
 
-        expect(LPAREN);
-        final List<IdentNode> parameters = formalParameterList();
-        expect(RPAREN);
-
-        final ParserContextFunctionNode functionNode = createParserContextFunctionNode(name, functionToken, FunctionNode.Kind.NORMAL, functionLine, parameters);
+        FunctionNode.Kind functionKind = generator ? FunctionNode.Kind.GENERATOR : FunctionNode.Kind.NORMAL;
+        List<IdentNode> parameters = Collections.emptyList();
+        final ParserContextFunctionNode functionNode = createParserContextFunctionNode(name, functionToken, functionKind, functionLine, parameters);
         lc.push(functionNode);
+
         Block functionBody = null;
         // Hide the current default name across function boundaries. E.g. "x3 = function x1() { function() {}}"
         // If we didn't hide the current default name, then the innermost anonymous function would receive "x3".
         hideDefaultName();
-        try{
+        try {
+            final ParserContextBlockNode parameterBlock = newBlock();
+            try {
+                expect(LPAREN);
+                parameters = formalParameterList(generator);
+                functionNode.setParameters(parameters);
+                expect(RPAREN);
+            } finally {
+                restoreBlock(parameterBlock);
+            }
+
             functionBody = functionBody(functionNode);
+
+            functionBody = maybeWrapBodyInParameterBlock(functionBody, parameterBlock);
         } finally {
             defaultNames.pop();
             lc.pop(functionNode);
         }
 
         if (isStatement) {
-            if (topLevel || useBlockScope()) {
+            if (topLevel || useBlockScope() || (!isStrictMode && env._function_statement == ScriptEnvironment.FunctionStatementBehavior.ACCEPT)) {
                 functionNode.setFlag(FunctionNode.IS_DECLARED);
             } else if (isStrictMode) {
                 throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("strict.no.func.decl.here"), functionToken);
@@ -2759,45 +3805,14 @@
             functionNode.setFlag(FunctionNode.IS_ANONYMOUS);
         }
 
-        final int arity = parameters.size();
-
-        final boolean strict = functionNode.isStrict();
-        if (arity > 1) {
-            final HashSet<String> parametersSet = new HashSet<>(arity);
-
-            for (int i = arity - 1; i >= 0; i--) {
-                final IdentNode parameter = parameters.get(i);
-                String parameterName = parameter.getName();
-
-                if (isArguments(parameterName)) {
-                    functionNode.setFlag(FunctionNode.DEFINES_ARGUMENTS);
-                }
-
-                if (parametersSet.contains(parameterName)) {
-                    // redefinition of parameter name
-                    if (strict) {
-                        throw error(AbstractParser.message("strict.param.redefinition", parameterName), parameter.getToken());
-                    }
-                    // rename in non-strict mode
-                    parameterName = functionNode.uniqueName(parameterName);
-                    final long parameterToken = parameter.getToken();
-                    parameters.set(i, new IdentNode(parameterToken, Token.descPosition(parameterToken), functionNode.uniqueName(parameterName)));
-                }
-
-                parametersSet.add(parameterName);
-            }
-        } else if (arity == 1) {
-            if (isArguments(parameters.get(0))) {
-                functionNode.setFlag(FunctionNode.DEFINES_ARGUMENTS);
-            }
-        }
+        verifyParameterList(parameters, functionNode);
 
         final FunctionNode function = createFunctionNode(
                 functionNode,
                 functionToken,
                 name,
                 parameters,
-                FunctionNode.Kind.NORMAL,
+                functionKind,
                 functionLine,
                 functionBody);
 
@@ -2822,6 +3837,40 @@
         return function;
     }
 
+    private void verifyParameterList(final List<IdentNode> parameters, final ParserContextFunctionNode functionNode) {
+        final IdentNode duplicateParameter = functionNode.getDuplicateParameterBinding();
+        if (duplicateParameter != null) {
+            if (functionNode.isStrict() || functionNode.getKind() == FunctionNode.Kind.ARROW || !functionNode.isSimpleParameterList()) {
+                throw error(AbstractParser.message("strict.param.redefinition", duplicateParameter.getName()), duplicateParameter.getToken());
+            }
+
+            final int arity = parameters.size();
+            final HashSet<String> parametersSet = new HashSet<>(arity);
+
+            for (int i = arity - 1; i >= 0; i--) {
+                final IdentNode parameter = parameters.get(i);
+                String parameterName = parameter.getName();
+
+                if (parametersSet.contains(parameterName)) {
+                    // redefinition of parameter name, rename in non-strict mode
+                    parameterName = functionNode.uniqueName(parameterName);
+                    final long parameterToken = parameter.getToken();
+                    parameters.set(i, new IdentNode(parameterToken, Token.descPosition(parameterToken), functionNode.uniqueName(parameterName)));
+                }
+                parametersSet.add(parameterName);
+            }
+        }
+    }
+
+    private static Block maybeWrapBodyInParameterBlock(Block functionBody, ParserContextBlockNode parameterBlock) {
+        assert functionBody.isFunctionBody();
+        if (!parameterBlock.getStatements().isEmpty()) {
+            parameterBlock.appendStatement(new BlockStatement(functionBody));
+            return new Block(parameterBlock.getToken(), functionBody.getFinish(), (functionBody.getFlags() | Block.IS_PARAMETER_BLOCK) & ~Block.IS_BODY, parameterBlock.getStatements());
+        }
+        return functionBody;
+    }
+
     private String getDefaultValidFunctionName(final int functionLine, final boolean isStatement) {
         final String defaultFunctionName = getDefaultFunctionName();
         if (isValidIdentifier(defaultFunctionName)) {
@@ -2836,14 +3885,14 @@
     }
 
     private static boolean isValidIdentifier(final String name) {
-        if(name == null || name.isEmpty()) {
+        if (name == null || name.isEmpty()) {
             return false;
         }
-        if(!Character.isJavaIdentifierStart(name.charAt(0))) {
+        if (!Character.isJavaIdentifierStart(name.charAt(0))) {
             return false;
         }
-        for(int i = 1; i < name.length(); ++i) {
-            if(!Character.isJavaIdentifierPart(name.charAt(i))) {
+        for (int i = 1; i < name.length(); ++i) {
+            if (!Character.isJavaIdentifierPart(name.charAt(i))) {
                 return false;
             }
         }
@@ -2851,12 +3900,12 @@
     }
 
     private String getDefaultFunctionName() {
-        if(!defaultNames.isEmpty()) {
+        if (!defaultNames.isEmpty()) {
             final Object nameExpr = defaultNames.peek();
-            if(nameExpr instanceof PropertyKey) {
+            if (nameExpr instanceof PropertyKey) {
                 markDefaultNameUsed();
                 return ((PropertyKey)nameExpr).getPropertyName();
-            } else if(nameExpr instanceof AccessNode) {
+            } else if (nameExpr instanceof AccessNode) {
                 markDefaultNameUsed();
                 return ((AccessNode)nameExpr).getProperty();
             }
@@ -2885,8 +3934,8 @@
      * Parse function parameter list.
      * @return List of parameter nodes.
      */
-    private List<IdentNode> formalParameterList() {
-        return formalParameterList(RPAREN);
+    private List<IdentNode> formalParameterList(final boolean yield) {
+        return formalParameterList(RPAREN, yield);
     }
 
     /**
@@ -2902,7 +3951,7 @@
      * Parse function parameter list.
      * @return List of parameter nodes.
      */
-    private List<IdentNode> formalParameterList(final TokenType endType) {
+    private List<IdentNode> formalParameterList(final TokenType endType, final boolean yield) {
         // Prepare to gather parameters.
         final ArrayList<IdentNode> parameters = new ArrayList<>();
         // Track commas.
@@ -2916,12 +3965,84 @@
                 first = false;
             }
 
-            // Get and add parameter.
-            final IdentNode ident = getIdent();
-
-            // ECMA 13.1 strict mode restrictions
-            verifyStrictIdent(ident, "function parameter");
-
+            boolean restParameter = false;
+            if (type == ELLIPSIS && isES6()) {
+                next();
+                restParameter = true;
+            }
+
+            if (type == YIELD && yield) {
+                expect(IDENT);
+            }
+
+            final long paramToken = token;
+            final int paramLine = line;
+            final String contextString = "function parameter";
+            IdentNode ident;
+            if (isBindingIdentifier() || restParameter || !isES6()) {
+                ident = bindingIdentifier(contextString);
+
+                if (restParameter) {
+                    ident = ident.setIsRestParameter();
+                    // rest parameter must be last
+                    expectDontAdvance(endType);
+                    parameters.add(ident);
+                    break;
+                } else if (type == ASSIGN && isES6()) {
+                    next();
+                    ident = ident.setIsDefaultParameter();
+
+                    if (type == YIELD && yield) {
+                        // error: yield in default expression
+                        expect(IDENT);
+                    }
+
+                    // default parameter
+                    Expression initializer = assignmentExpression(false);
+
+                    ParserContextFunctionNode currentFunction = lc.getCurrentFunction();
+                    if (currentFunction != null) {
+                        // desugar to: param = (param === undefined) ? initializer : param;
+                        // possible alternative: if (param === undefined) param = initializer;
+                        BinaryNode test = new BinaryNode(Token.recast(paramToken, EQ_STRICT), ident, newUndefinedLiteral(paramToken, finish));
+                        TernaryNode value = new TernaryNode(Token.recast(paramToken, TERNARY), test, new JoinPredecessorExpression(initializer), new JoinPredecessorExpression(ident));
+                        BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), ident, value);
+                        lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment));
+                    }
+                }
+
+                ParserContextFunctionNode currentFunction = lc.getCurrentFunction();
+                if (currentFunction != null) {
+                    currentFunction.addParameterBinding(ident);
+                    if (ident.isRestParameter() || ident.isDefaultParameter()) {
+                        currentFunction.setSimpleParameterList(false);
+                    }
+                }
+            } else {
+                final Expression pattern = bindingPattern();
+                // Introduce synthetic temporary parameter to capture the object to be destructured.
+                ident = createIdentNode(paramToken, pattern.getFinish(), String.format("arguments[%d]", parameters.size())).setIsDestructuredParameter();
+                verifyDestructuringParameterBindingPattern(pattern, paramToken, paramLine, contextString);
+
+                Expression value = ident;
+                if (type == ASSIGN) {
+                    next();
+                    ident = ident.setIsDefaultParameter();
+
+                    // binding pattern with initializer. desugar to: (param === undefined) ? initializer : param
+                    Expression initializer = assignmentExpression(false);
+                    // TODO initializer must not contain yield expression if yield=true (i.e. this is generator function's parameter list)
+                    BinaryNode test = new BinaryNode(Token.recast(paramToken, EQ_STRICT), ident, newUndefinedLiteral(paramToken, finish));
+                    value = new TernaryNode(Token.recast(paramToken, TERNARY), test, new JoinPredecessorExpression(initializer), new JoinPredecessorExpression(ident));
+                }
+
+                ParserContextFunctionNode currentFunction = lc.getCurrentFunction();
+                if (currentFunction != null) {
+                    // destructuring assignment
+                    BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), pattern, value);
+                    lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment));
+                }
+            }
             parameters.add(ident);
         }
 
@@ -2929,6 +4050,23 @@
         return parameters;
     }
 
+    private void verifyDestructuringParameterBindingPattern(final Expression pattern, final long paramToken, final int paramLine, final String contextString) {
+        verifyDestructuringBindingPattern(pattern, new Consumer<IdentNode>() {
+            public void accept(IdentNode identNode) {
+                verifyIdent(identNode, contextString);
+
+                ParserContextFunctionNode currentFunction = lc.getCurrentFunction();
+                if (currentFunction != null) {
+                    // declare function-scope variables for destructuring bindings
+                    lc.getFunctionBody(currentFunction).appendStatement(new VarNode(paramLine, Token.recast(paramToken, VAR), pattern.getFinish(), identNode, null));
+                    // detect duplicate bounds names in parameter list
+                    currentFunction.addParameterBinding(identNode);
+                    currentFunction.setSimpleParameterList(false);
+                }
+            }
+        });
+    }
+
     /**
      * FunctionBody :
      *      SourceElements?
@@ -2958,7 +4096,7 @@
             final int functionId = functionNode.getId();
             parseBody = reparsedFunction == null || functionId <= reparsedFunction.getFunctionNodeId();
             // Nashorn extension: expression closures
-            if (!env._no_syntax_extensions && type != LBRACE) {
+            if ((!env._no_syntax_extensions || functionNode.getKind() == FunctionNode.Kind.ARROW) && type != LBRACE) {
                 /*
                  * Example:
                  *
@@ -2967,7 +4105,7 @@
                  */
 
                 // just expression as function body
-                final Expression expr = assignmentExpression(true);
+                final Expression expr = assignmentExpression(false);
                 lastToken = previousToken;
                 functionNode.setLastToken(previousToken);
                 assert lc.getCurrentBlock() == lc.getFunctionBody(functionNode);
@@ -2982,6 +4120,7 @@
                     final ReturnNode returnNode = new ReturnNode(functionNode.getLineNumber(), expr.getToken(), lastFinish, expr);
                     appendStatement(returnNode);
                 }
+                // bodyFinish = finish;
             } else {
                 expectDontAdvance(LBRACE);
                 if (parseBody || !skipFunctionBody(functionNode)) {
@@ -3054,7 +4193,7 @@
                 }
             }
         }
-        functionBody = new Block(bodyToken, bodyFinish, body.getFlags(), body.getStatements());
+        functionBody = new Block(bodyToken, bodyFinish, body.getFlags() | Block.IS_BODY, body.getStatements());
         return functionBody;
     }
 
@@ -3095,8 +4234,7 @@
         // Doesn't really matter, but it's safe to treat it as if there were a semicolon before
         // the RBRACE.
         type = SEMICOLON;
-        k = -1;
-        next();
+        scanFirstToken();
 
         return true;
     }
@@ -3126,11 +4264,11 @@
     }
 
     private void printAST(final FunctionNode functionNode) {
-        if (functionNode.getFlag(FunctionNode.IS_PRINT_AST)) {
+        if (functionNode.getDebugFlag(FunctionNode.DEBUG_PRINT_AST)) {
             env.getErr().println(new ASTWriter(functionNode));
         }
 
-        if (functionNode.getFlag(FunctionNode.IS_PRINT_PARSE)) {
+        if (functionNode.getDebugFlag(FunctionNode.DEBUG_PRINT_PARSE)) {
             env.getErr().println(new PrintVisitor(functionNode, true, false));
         }
     }
@@ -3222,20 +4360,7 @@
                 throw error(AbstractParser.message("expected.lvalue", type.getNameOrType()));
             }
 
-            if (!(lhs instanceof AccessNode ||
-                  lhs instanceof IndexNode ||
-                  lhs instanceof IdentNode)) {
-                return referenceError(lhs, null, env._early_lvalue_error);
-            }
-
-            if (lhs instanceof IdentNode) {
-                if (!checkIdentLValue((IdentNode)lhs)) {
-                    return referenceError(lhs, null, false);
-                }
-                verifyStrictIdent((IdentNode)lhs, "operand for " + opType.getName() + " operator");
-            }
-
-            return incDecExpression(unaryToken, opType, lhs, false);
+            return verifyIncDecExpression(unaryToken, opType, lhs, false);
 
         default:
             break;
@@ -3247,29 +4372,16 @@
             switch (type) {
             case INCPREFIX:
             case DECPREFIX:
+                final long opToken = token;
                 final TokenType opType = type;
                 final Expression lhs = expression;
                 // ++, -- without operand..
                 if (lhs == null) {
                     throw error(AbstractParser.message("expected.lvalue", type.getNameOrType()));
                 }
-
-                if (!(lhs instanceof AccessNode ||
-                   lhs instanceof IndexNode ||
-                   lhs instanceof IdentNode)) {
-                    next();
-                    return referenceError(lhs, null, env._early_lvalue_error);
-                }
-                if (lhs instanceof IdentNode) {
-                    if (!checkIdentLValue((IdentNode)lhs)) {
-                        next();
-                        return referenceError(lhs, null, false);
-                    }
-                    verifyStrictIdent((IdentNode)lhs, "operand for " + opType.getName() + " operator");
-                }
-                expression = incDecExpression(token, type, expression, true);
                 next();
-                break;
+
+                return verifyIncDecExpression(opToken, opType, lhs, true);
             default:
                 break;
             }
@@ -3282,6 +4394,25 @@
         return expression;
     }
 
+    private Expression verifyIncDecExpression(final long unaryToken, final TokenType opType, final Expression lhs, final boolean isPostfix) {
+        assert lhs != null;
+
+        if (!(lhs instanceof AccessNode ||
+              lhs instanceof IndexNode ||
+              lhs instanceof IdentNode)) {
+            return referenceError(lhs, null, env._early_lvalue_error);
+        }
+
+        if (lhs instanceof IdentNode) {
+            if (!checkIdentLValue((IdentNode)lhs)) {
+                return referenceError(lhs, null, false);
+            }
+            verifyIdent((IdentNode)lhs, "operand for " + opType.getName() + " operator");
+        }
+
+        return incDecExpression(unaryToken, opType, lhs, isPostfix);
+    }
+
     /**
      * {@code
      * MultiplicativeExpression :
@@ -3380,7 +4511,42 @@
         // at expression start point!
 
         // Include commas in expression parsing.
-        return expression(unaryExpression(), COMMARIGHT.getPrecedence(), false);
+        return expression(false);
+    }
+
+    private Expression expression(final boolean noIn) {
+        Expression assignmentExpression = assignmentExpression(noIn);
+        while (type == COMMARIGHT) {
+            long commaToken = token;
+            next();
+
+            boolean rhsRestParameter = false;
+            if (type == ELLIPSIS && isES6()) {
+                // (a, b, ...rest) is not a valid expression, unless we're parsing the parameter list of an arrow function (we need to throw the right error).
+                // But since the rest parameter is always last, at least we know that the expression has to end here and be followed by RPAREN and ARROW, so peek ahead.
+                if (isRestParameterEndOfArrowFunctionParameterList()) {
+                    next();
+                    rhsRestParameter = true;
+                }
+            }
+
+            Expression rhs = assignmentExpression(noIn);
+
+            if (rhsRestParameter) {
+                rhs = ((IdentNode)rhs).setIsRestParameter();
+                // Our only valid move is to end Expression here and continue with ArrowFunction.
+                // We've already checked that this is the parameter list of an arrow function (see above).
+                // RPAREN is next, so we'll finish the binary expression and drop out of the loop.
+                assert type == RPAREN;
+            }
+
+            assignmentExpression = new BinaryNode(commaToken, assignmentExpression, rhs);
+        }
+        return assignmentExpression;
+    }
+
+    private Expression expression(final int minPrecedence, final boolean noIn) {
+        return expression(unaryExpression(), minPrecedence, noIn);
     }
 
     private JoinPredecessorExpression joinPredecessorExpression() {
@@ -3448,12 +4614,316 @@
         return lhs;
     }
 
+    /**
+     * AssignmentExpression.
+     *
+     * AssignmentExpression[In, Yield] :
+     *   ConditionalExpression[?In, ?Yield]
+     *   [+Yield] YieldExpression[?In]
+     *   ArrowFunction[?In, ?Yield]
+     *   LeftHandSideExpression[?Yield] = AssignmentExpression[?In, ?Yield]
+     *   LeftHandSideExpression[?Yield] AssignmentOperator AssignmentExpression[?In, ?Yield]
+     */
     protected Expression assignmentExpression(final boolean noIn) {
         // This method is protected so that subclass can get details
         // at assignment expression start point!
 
-        // Exclude commas in expression parsing.
-        return expression(unaryExpression(), ASSIGN.getPrecedence(), noIn);
+        if (type == YIELD && inGeneratorFunction() && isES6()) {
+            return yieldExpression(noIn);
+        }
+
+        final long startToken = token;
+        final int startLine = line;
+        final Expression exprLhs = conditionalExpression(noIn);
+
+        if (type == ARROW && isES6()) {
+            if (checkNoLineTerminator()) {
+                final Expression paramListExpr;
+                if (exprLhs instanceof ExpressionList) {
+                    paramListExpr = (((ExpressionList)exprLhs).getExpressions().isEmpty() ? null : ((ExpressionList)exprLhs).getExpressions().get(0));
+                } else {
+                    paramListExpr = exprLhs;
+                }
+                return arrowFunction(startToken, startLine, paramListExpr);
+            }
+        }
+        assert !(exprLhs instanceof ExpressionList);
+
+        if (isAssignmentOperator(type)) {
+            final boolean isAssign = type == ASSIGN;
+            if (isAssign) {
+                defaultNames.push(exprLhs);
+            }
+            try {
+                final long assignToken = token;
+                next();
+                final Expression exprRhs = assignmentExpression(noIn);
+                return verifyAssignment(assignToken, exprLhs, exprRhs);
+            } finally {
+                if (isAssign) {
+                    defaultNames.pop();
+                }
+            }
+        } else {
+            return exprLhs;
+        }
+    }
+
+    /**
+     * Is type one of {@code = *= /= %= += -= <<= >>= >>>= &= ^= |=}?
+     */
+    private static boolean isAssignmentOperator(TokenType type) {
+        switch (type) {
+        case ASSIGN:
+        case ASSIGN_ADD:
+        case ASSIGN_BIT_AND:
+        case ASSIGN_BIT_OR:
+        case ASSIGN_BIT_XOR:
+        case ASSIGN_DIV:
+        case ASSIGN_MOD:
+        case ASSIGN_MUL:
+        case ASSIGN_SAR:
+        case ASSIGN_SHL:
+        case ASSIGN_SHR:
+        case ASSIGN_SUB:
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * ConditionalExpression.
+     */
+    private Expression conditionalExpression(boolean noIn) {
+        return expression(TERNARY.getPrecedence(), noIn);
+    }
+
+    /**
+     * ArrowFunction.
+     *
+     * @param startToken start token of the ArrowParameters expression
+     * @param functionLine start line of the arrow function
+     * @param paramListExpr ArrowParameters expression or {@code null} for {@code ()} (empty list)
+     */
+    private Expression arrowFunction(final long startToken, final int functionLine, final Expression paramListExpr) {
+        // caller needs to check that there's no LineTerminator between parameter list and arrow
+        assert type != ARROW || checkNoLineTerminator();
+        expect(ARROW);
+
+        final long functionToken = Token.recast(startToken, ARROW);
+        final IdentNode name = new IdentNode(functionToken, Token.descPosition(functionToken), "=>:" + functionLine);
+        final ParserContextFunctionNode functionNode = createParserContextFunctionNode(name, functionToken, FunctionNode.Kind.ARROW, functionLine, null);
+        functionNode.setFlag(FunctionNode.IS_ANONYMOUS);
+
+        lc.push(functionNode);
+        try {
+            ParserContextBlockNode parameterBlock = newBlock();
+            final List<IdentNode> parameters;
+            try {
+                parameters = convertArrowFunctionParameterList(paramListExpr, functionLine);
+                functionNode.setParameters(parameters);
+
+                if (!functionNode.isSimpleParameterList()) {
+                    markEvalInArrowParameterList(parameterBlock);
+                }
+            } finally {
+                restoreBlock(parameterBlock);
+            }
+            Block functionBody = functionBody(functionNode);
+
+            functionBody = maybeWrapBodyInParameterBlock(functionBody, parameterBlock);
+
+            verifyParameterList(parameters, functionNode);
+
+            final FunctionNode function = createFunctionNode(
+                            functionNode,
+                            functionToken,
+                            name,
+                            parameters,
+                            FunctionNode.Kind.ARROW,
+                            functionLine,
+                            functionBody);
+            return function;
+        } finally {
+            lc.pop(functionNode);
+        }
+    }
+
+    private void markEvalInArrowParameterList(final ParserContextBlockNode parameterBlock) {
+        final Iterator<ParserContextFunctionNode> iter = lc.getFunctions();
+        final ParserContextFunctionNode current = iter.next();
+        final ParserContextFunctionNode parent = iter.next();
+
+        if (parent.getFlag(FunctionNode.HAS_EVAL) != 0) {
+            // we might have flagged has-eval in the parent function during parsing the parameter list,
+            // if the parameter list contains eval; must tag arrow function as has-eval.
+            for (final Statement st : parameterBlock.getStatements()) {
+                st.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+                    @Override
+                    public boolean enterCallNode(final CallNode callNode) {
+                        if (callNode.getFunction() instanceof IdentNode && ((IdentNode) callNode.getFunction()).getName().equals("eval")) {
+                            current.setFlag(FunctionNode.HAS_EVAL);
+                        }
+                        return true;
+                    }
+                });
+            }
+            // TODO: function containing the arrow function should not be flagged has-eval
+        }
+    }
+
+    private List<IdentNode> convertArrowFunctionParameterList(final Expression paramListExpr, final int functionLine) {
+        final List<IdentNode> parameters;
+        if (paramListExpr == null) {
+            // empty parameter list, i.e. () =>
+            parameters = Collections.emptyList();
+        } else if (paramListExpr instanceof IdentNode || paramListExpr.isTokenType(ASSIGN) || isDestructuringLhs(paramListExpr)) {
+            parameters = Collections.singletonList(verifyArrowParameter(paramListExpr, 0, functionLine));
+        } else if (paramListExpr instanceof BinaryNode && Token.descType(paramListExpr.getToken()) == COMMARIGHT) {
+            parameters = new ArrayList<>();
+            Expression car = paramListExpr;
+            do {
+                final Expression cdr = ((BinaryNode) car).rhs();
+                parameters.add(0, verifyArrowParameter(cdr, parameters.size(), functionLine));
+                car = ((BinaryNode) car).lhs();
+            } while (car instanceof BinaryNode && Token.descType(car.getToken()) == COMMARIGHT);
+            parameters.add(0, verifyArrowParameter(car, parameters.size(), functionLine));
+        } else {
+            throw error(AbstractParser.message("expected.arrow.parameter"), paramListExpr.getToken());
+        }
+        return parameters;
+    }
+
+    private IdentNode verifyArrowParameter(Expression param, int index, int paramLine) {
+        final String contextString = "function parameter";
+        if (param instanceof IdentNode) {
+            IdentNode ident = (IdentNode)param;
+            verifyStrictIdent(ident, contextString);
+            ParserContextFunctionNode currentFunction = lc.getCurrentFunction();
+            if (currentFunction != null) {
+                currentFunction.addParameterBinding(ident);
+            }
+            return ident;
+        }
+
+        if (param.isTokenType(ASSIGN)) {
+            Expression lhs = ((BinaryNode) param).lhs();
+            long paramToken = lhs.getToken();
+            Expression initializer = ((BinaryNode) param).rhs();
+            if (lhs instanceof IdentNode) {
+                // default parameter
+                IdentNode ident = (IdentNode) lhs;
+
+                ParserContextFunctionNode currentFunction = lc.getCurrentFunction();
+                if (currentFunction != null) {
+                    BinaryNode test = new BinaryNode(Token.recast(paramToken, EQ_STRICT), ident, newUndefinedLiteral(paramToken, finish));
+                    TernaryNode value = new TernaryNode(Token.recast(paramToken, TERNARY), test, new JoinPredecessorExpression(initializer), new JoinPredecessorExpression(ident));
+                    BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), ident, value);
+                    lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment));
+
+                    currentFunction.addParameterBinding(ident);
+                    currentFunction.setSimpleParameterList(false);
+                }
+                return ident;
+            } else if (isDestructuringLhs(lhs)) {
+                // binding pattern with initializer
+                // Introduce synthetic temporary parameter to capture the object to be destructured.
+                IdentNode ident = createIdentNode(paramToken, param.getFinish(), String.format("arguments[%d]", index)).setIsDestructuredParameter().setIsDefaultParameter();
+                verifyDestructuringParameterBindingPattern(param, paramToken, paramLine, contextString);
+
+                ParserContextFunctionNode currentFunction = lc.getCurrentFunction();
+                if (currentFunction != null) {
+                    BinaryNode test = new BinaryNode(Token.recast(paramToken, EQ_STRICT), ident, newUndefinedLiteral(paramToken, finish));
+                    TernaryNode value = new TernaryNode(Token.recast(paramToken, TERNARY), test, new JoinPredecessorExpression(initializer), new JoinPredecessorExpression(ident));
+                    BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), param, value);
+                    lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment));
+                }
+                return ident;
+            }
+        } else if (isDestructuringLhs(param)) {
+            // binding pattern
+            long paramToken = param.getToken();
+
+            // Introduce synthetic temporary parameter to capture the object to be destructured.
+            IdentNode ident = createIdentNode(paramToken, param.getFinish(), String.format("arguments[%d]", index)).setIsDestructuredParameter();
+            verifyDestructuringParameterBindingPattern(param, paramToken, paramLine, contextString);
+
+            ParserContextFunctionNode currentFunction = lc.getCurrentFunction();
+            if (currentFunction != null) {
+                BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), param, ident);
+                lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment));
+            }
+            return ident;
+        }
+        throw error(AbstractParser.message("invalid.arrow.parameter"), param.getToken());
+    }
+
+    private boolean checkNoLineTerminator() {
+        assert type == ARROW;
+        if (last == RPAREN) {
+            return true;
+        } else if (last == IDENT) {
+            return true;
+        }
+        for (int i = k - 1; i >= 0; i--) {
+            TokenType t = T(i);
+            switch (t) {
+            case RPAREN:
+            case IDENT:
+                return true;
+            case EOL:
+                return false;
+            case COMMENT:
+                continue;
+            default:
+                if (t.getKind() == TokenKind.FUTURESTRICT) {
+                    return true;
+                }
+                return false;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Peek ahead to see if what follows after the ellipsis is a rest parameter
+     * at the end of an arrow function parameter list.
+     */
+    private boolean isRestParameterEndOfArrowFunctionParameterList() {
+        assert type == ELLIPSIS;
+        // find IDENT, RPAREN, ARROW, in that order, skipping over EOL (where allowed) and COMMENT
+        int i = 1;
+        for (;;) {
+            TokenType t = T(k + i++);
+            if (t == IDENT) {
+                break;
+            } else if (t == EOL || t == COMMENT) {
+                continue;
+            } else {
+                return false;
+            }
+        }
+        for (;;) {
+            TokenType t = T(k + i++);
+            if (t == RPAREN) {
+                break;
+            } else if (t == EOL || t == COMMENT) {
+                continue;
+            } else {
+                return false;
+            }
+        }
+        for (;;) {
+            TokenType t = T(k + i++);
+            if (t == ARROW) {
+                break;
+            } else if (t == COMMENT) {
+                continue;
+            } else {
+                return false;
+            }
+        }
+        return true;
     }
 
     /**
@@ -3551,6 +5021,380 @@
         cookedStrings.add(LiteralNode.newInstance(stringToken, finish, cookedString));
     }
 
+
+    /**
+     * Parse a module.
+     *
+     * Module :
+     *      ModuleBody?
+     *
+     * ModuleBody :
+     *      ModuleItemList
+     */
+    private FunctionNode module(final String moduleName) {
+        boolean oldStrictMode = isStrictMode;
+        try {
+            isStrictMode = true; // Module code is always strict mode code. (ES6 10.2.1)
+
+            // Make a pseudo-token for the script holding its start and length.
+            int functionStart = Math.min(Token.descPosition(Token.withDelimiter(token)), finish);
+            final long functionToken = Token.toDesc(FUNCTION, functionStart, source.getLength() - functionStart);
+            final int  functionLine  = line;
+
+            final IdentNode ident = new IdentNode(functionToken, Token.descPosition(functionToken), moduleName);
+            final ParserContextFunctionNode script = createParserContextFunctionNode(
+                            ident,
+                            functionToken,
+                            FunctionNode.Kind.MODULE,
+                            functionLine,
+                            Collections.<IdentNode>emptyList());
+            lc.push(script);
+
+            final ParserContextModuleNode module = new ParserContextModuleNode(moduleName);
+            lc.push(module);
+
+            final ParserContextBlockNode body = newBlock();
+
+            functionDeclarations = new ArrayList<>();
+            moduleBody();
+            addFunctionDeclarations(script);
+            functionDeclarations = null;
+
+            restoreBlock(body);
+            body.setFlag(Block.NEEDS_SCOPE);
+            final Block programBody = new Block(functionToken, finish, body.getFlags() | Block.IS_SYNTHETIC | Block.IS_BODY, body.getStatements());
+            lc.pop(module);
+            lc.pop(script);
+            script.setLastToken(token);
+
+            expect(EOF);
+
+            script.setModule(module.createModule());
+            return createFunctionNode(script, functionToken, ident, Collections.<IdentNode>emptyList(), FunctionNode.Kind.MODULE, functionLine, programBody);
+        } finally {
+            isStrictMode = oldStrictMode;
+        }
+    }
+
+    /**
+     * Parse module body.
+     *
+     * ModuleBody :
+     *      ModuleItemList
+     *
+     * ModuleItemList :
+     *      ModuleItem
+     *      ModuleItemList ModuleItem
+     *
+     * ModuleItem :
+     *      ImportDeclaration
+     *      ExportDeclaration
+     *      StatementListItem
+     */
+    private void moduleBody() {
+        loop:
+        while (type != EOF) {
+            switch (type) {
+            case EOF:
+                break loop;
+            case IMPORT:
+                importDeclaration();
+                break;
+            case EXPORT:
+                exportDeclaration();
+                break;
+            default:
+                // StatementListItem
+                statement(true, false, false, false);
+                break;
+            }
+        }
+    }
+
+
+    /**
+     * Parse import declaration.
+     *
+     * ImportDeclaration :
+     *     import ImportClause FromClause ;
+     *     import ModuleSpecifier ;
+     * ImportClause :
+     *     ImportedDefaultBinding
+     *     NameSpaceImport
+     *     NamedImports
+     *     ImportedDefaultBinding , NameSpaceImport
+     *     ImportedDefaultBinding , NamedImports
+     * ImportedDefaultBinding :
+     *     ImportedBinding
+     * ModuleSpecifier :
+     *     StringLiteral
+     * ImportedBinding :
+     *     BindingIdentifier
+     */
+    private void importDeclaration() {
+        expect(IMPORT);
+        final ParserContextModuleNode module = lc.getCurrentModule();
+        if (type == STRING || type == ESCSTRING) {
+            // import ModuleSpecifier ;
+            final String moduleSpecifier = (String) getValue();
+            next();
+            module.addModuleRequest(moduleSpecifier);
+        } else {
+            // import ImportClause FromClause ;
+            List<Module.ImportEntry> importEntries;
+            if (type == MUL) {
+                importEntries = Collections.singletonList(nameSpaceImport());
+            } else if (type == LBRACE) {
+                importEntries = namedImports();
+            } else if (isBindingIdentifier()) {
+                // ImportedDefaultBinding
+                final IdentNode importedDefaultBinding = bindingIdentifier("ImportedBinding");
+                Module.ImportEntry defaultImport = Module.ImportEntry.importDefault(importedDefaultBinding.getName());
+
+                if (type == COMMARIGHT) {
+                    next();
+                    importEntries = new ArrayList<>();
+                    if (type == MUL) {
+                        importEntries.add(nameSpaceImport());
+                    } else if (type == LBRACE) {
+                        importEntries.addAll(namedImports());
+                    } else {
+                        throw error(AbstractParser.message("expected.named.import"));
+                    }
+                } else {
+                    importEntries = Collections.singletonList(defaultImport);
+                }
+            } else {
+                throw error(AbstractParser.message("expected.import"));
+            }
+
+            final String moduleSpecifier = fromClause();
+            module.addModuleRequest(moduleSpecifier);
+            for (int i = 0; i < importEntries.size(); i++) {
+                module.addImportEntry(importEntries.get(i).withFrom(moduleSpecifier));
+            }
+        }
+        expect(SEMICOLON);
+    }
+
+    /**
+     * NameSpaceImport :
+     *     * as ImportedBinding
+     *
+     * @return imported binding identifier
+     */
+    private Module.ImportEntry nameSpaceImport() {
+        assert type == MUL;
+        next();
+        final long asToken = token;
+        final String as = (String) expectValue(IDENT);
+        if (!"as".equals(as)) {
+            throw error(AbstractParser.message("expected.as"), asToken);
+        }
+        final IdentNode localNameSpace = bindingIdentifier("ImportedBinding");
+        return Module.ImportEntry.importStarAsNameSpaceFrom(localNameSpace.getName());
+    }
+
+    /**
+     * NamedImports :
+     *     { }
+     *     { ImportsList }
+     *     { ImportsList , }
+     * ImportsList :
+     *     ImportSpecifier
+     *     ImportsList , ImportSpecifier
+     * ImportSpecifier :
+     *     ImportedBinding
+     *     IdentifierName as ImportedBinding
+     * ImportedBinding :
+     *     BindingIdentifier
+     */
+    private List<Module.ImportEntry> namedImports() {
+        assert type == LBRACE;
+        next();
+        List<Module.ImportEntry> importEntries = new ArrayList<>();
+        while (type != RBRACE) {
+            final boolean bindingIdentifier = isBindingIdentifier();
+            final long nameToken = token;
+            final IdentNode importName = getIdentifierName();
+            if (type == IDENT && "as".equals(getValue())) {
+                next();
+                final IdentNode localName = bindingIdentifier("ImportedBinding");
+                importEntries.add(Module.ImportEntry.importSpecifier(importName.getName(), localName.getName()));
+            } else if (!bindingIdentifier) {
+                throw error(AbstractParser.message("expected.binding.identifier"), nameToken);
+            } else {
+                importEntries.add(Module.ImportEntry.importSpecifier(importName.getName()));
+            }
+            if (type == COMMARIGHT) {
+                next();
+            } else {
+                break;
+            }
+        }
+        expect(RBRACE);
+        return importEntries;
+    }
+
+    /**
+     * FromClause :
+     *     from ModuleSpecifier
+     */
+    private String fromClause() {
+        final long fromToken = token;
+        final String name = (String) expectValue(IDENT);
+        if (!"from".equals(name)) {
+            throw error(AbstractParser.message("expected.from"), fromToken);
+        }
+        if (type == STRING || type == ESCSTRING) {
+            final String moduleSpecifier = (String) getValue();
+            next();
+            return moduleSpecifier;
+        } else {
+            throw error(expectMessage(STRING));
+        }
+    }
+
+    /**
+     * Parse export declaration.
+     *
+     * ExportDeclaration :
+     *     export * FromClause ;
+     *     export ExportClause FromClause ;
+     *     export ExportClause ;
+     *     export VariableStatement
+     *     export Declaration
+     *     export default HoistableDeclaration[Default]
+     *     export default ClassDeclaration[Default]
+     *     export default [lookahead !in {function, class}] AssignmentExpression[In] ;
+     */
+    private void exportDeclaration() {
+        expect(EXPORT);
+        final ParserContextModuleNode module = lc.getCurrentModule();
+        switch (type) {
+            case MUL: {
+                next();
+                final String moduleRequest = fromClause();
+                expect(SEMICOLON);
+                module.addModuleRequest(moduleRequest);
+                module.addStarExportEntry(Module.ExportEntry.exportStarFrom(moduleRequest));
+                break;
+            }
+            case LBRACE: {
+                final List<Module.ExportEntry> exportEntries = exportClause();
+                if (type == IDENT && "from".equals(getValue())) {
+                    final String moduleRequest = fromClause();
+                    module.addModuleRequest(moduleRequest);
+                    for (Module.ExportEntry exportEntry : exportEntries) {
+                        module.addIndirectExportEntry(exportEntry.withFrom(moduleRequest));
+                    }
+                } else {
+                    for (Module.ExportEntry exportEntry : exportEntries) {
+                        module.addLocalExportEntry(exportEntry);
+                    }
+                }
+                expect(SEMICOLON);
+                break;
+            }
+            case DEFAULT:
+                next();
+                final Expression assignmentExpression;
+                IdentNode ident;
+                final int lineNumber = line;
+                final long rhsToken = token;
+                final boolean declaration;
+                switch (type) {
+                    case FUNCTION:
+                        assignmentExpression = functionExpression(false, true);
+                        ident = ((FunctionNode) assignmentExpression).getIdent();
+                        declaration = true;
+                        break;
+                    case CLASS:
+                        assignmentExpression = classDeclaration(true);
+                        ident = ((ClassNode) assignmentExpression).getIdent();
+                        declaration = true;
+                        break;
+                    default:
+                        assignmentExpression = assignmentExpression(false);
+                        ident = null;
+                        declaration = false;
+                        break;
+                }
+                if (ident != null) {
+                    module.addLocalExportEntry(Module.ExportEntry.exportDefault(ident.getName()));
+                } else {
+                    ident = createIdentNode(Token.recast(rhsToken, IDENT), finish, Module.DEFAULT_EXPORT_BINDING_NAME);
+                    lc.appendStatementToCurrentNode(new VarNode(lineNumber, Token.recast(rhsToken, LET), finish, ident, assignmentExpression));
+                    if (!declaration) {
+                        expect(SEMICOLON);
+                    }
+                    module.addLocalExportEntry(Module.ExportEntry.exportDefault());
+                }
+                break;
+            case VAR:
+            case LET:
+            case CONST:
+                final List<Statement> statements = lc.getCurrentBlock().getStatements();
+                final int previousEnd = statements.size();
+                variableStatement(type);
+                for (final Statement statement : statements.subList(previousEnd, statements.size())) {
+                    if (statement instanceof VarNode) {
+                        module.addLocalExportEntry(Module.ExportEntry.exportSpecifier(((VarNode) statement).getName().getName()));
+                    }
+                }
+                break;
+            case CLASS: {
+                final ClassNode classDeclaration = classDeclaration(false);
+                module.addLocalExportEntry(Module.ExportEntry.exportSpecifier(classDeclaration.getIdent().getName()));
+                break;
+            }
+            case FUNCTION: {
+                final FunctionNode functionDeclaration = (FunctionNode) functionExpression(true, true);
+                module.addLocalExportEntry(Module.ExportEntry.exportSpecifier(functionDeclaration.getIdent().getName()));
+                break;
+            }
+            default:
+                throw error(AbstractParser.message("invalid.export"), token);
+        }
+    }
+
+    /**
+     * ExportClause :
+     *     { }
+     *     { ExportsList }
+     *     { ExportsList , }
+     * ExportsList :
+     *     ExportSpecifier
+     *     ExportsList , ExportSpecifier
+     * ExportSpecifier :
+     *     IdentifierName
+     *     IdentifierName as IdentifierName
+     *
+     * @return a list of ExportSpecifiers
+     */
+    private List<Module.ExportEntry> exportClause() {
+        assert type == LBRACE;
+        next();
+        List<Module.ExportEntry> exports = new ArrayList<>();
+        while (type != RBRACE) {
+            final IdentNode localName = getIdentifierName();
+            if (type == IDENT && "as".equals(getValue())) {
+                next();
+                final IdentNode exportName = getIdentifierName();
+                exports.add(Module.ExportEntry.exportSpecifier(exportName.getName(), localName.getName()));
+            } else {
+                exports.add(Module.ExportEntry.exportSpecifier(localName.getName()));
+            }
+            if (type == COMMARIGHT) {
+                next();
+            } else {
+                break;
+            }
+        }
+        expect(RBRACE);
+        return exports;
+    }
+
     @Override
     public String toString() {
         return "'JavaScript Parsing'";
@@ -3564,6 +5408,12 @@
             if (!flaggedCurrentFn) {
                 fn.setFlag(FunctionNode.HAS_EVAL);
                 flaggedCurrentFn = true;
+                if (fn.getKind() == FunctionNode.Kind.ARROW) {
+                    // possible use of this in an eval that's nested in an arrow function, e.g.:
+                    // function fun(){ return (() => eval("this"))(); };
+                    markThis(lc);
+                    markNewTarget(lc);
+                }
             } else {
                 fn.setFlag(FunctionNode.HAS_NESTED_EVAL);
             }
@@ -3583,4 +5433,55 @@
     private void appendStatement(final Statement statement) {
         lc.appendStatementToCurrentNode(statement);
     }
+
+    private static void markSuperCall(final ParserContext lc) {
+        final Iterator<ParserContextFunctionNode> iter = lc.getFunctions();
+        while (iter.hasNext()) {
+            final ParserContextFunctionNode fn = iter.next();
+            if (fn.getKind() != FunctionNode.Kind.ARROW) {
+                assert fn.isSubclassConstructor();
+                fn.setFlag(FunctionNode.ES6_HAS_DIRECT_SUPER);
+                break;
+            }
+        }
+    }
+
+    private ParserContextFunctionNode getCurrentNonArrowFunction() {
+        final Iterator<ParserContextFunctionNode> iter = lc.getFunctions();
+        while (iter.hasNext()) {
+            final ParserContextFunctionNode fn = iter.next();
+            if (fn.getKind() != FunctionNode.Kind.ARROW) {
+                return fn;
+            }
+        }
+        return null;
+    }
+
+    private static void markThis(final ParserContext lc) {
+        final Iterator<ParserContextFunctionNode> iter = lc.getFunctions();
+        while (iter.hasNext()) {
+            final ParserContextFunctionNode fn = iter.next();
+            fn.setFlag(FunctionNode.USES_THIS);
+            if (fn.getKind() != FunctionNode.Kind.ARROW) {
+                break;
+            }
+        }
+    }
+
+    private static void markNewTarget(final ParserContext lc) {
+        final Iterator<ParserContextFunctionNode> iter = lc.getFunctions();
+        while (iter.hasNext()) {
+            final ParserContextFunctionNode fn = iter.next();
+            if (fn.getKind() != FunctionNode.Kind.ARROW) {
+                if (!fn.isProgram()) {
+                    fn.setFlag(FunctionNode.ES6_USES_NEW_TARGET);
+                }
+                break;
+            }
+        }
+    }
+
+    private boolean inGeneratorFunction() {
+        return lc.getCurrentFunction().getKind() == FunctionNode.Kind.GENERATOR;
+    }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContext.java	Wed Jul 05 21:38:12 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContext.java	Wed Apr 27 15:50:33 2016 +0200
@@ -278,7 +278,12 @@
         return new NodeIterator<>(ParserContextFunctionNode.class);
     }
 
-    private class NodeIterator <T extends ParserContextNode> implements Iterator<T> {
+    public ParserContextModuleNode getCurrentModule() {
+        final Iterator<ParserContextModuleNode> iter = new NodeIterator<>(ParserContextModuleNode.class, getCurrentFunction());
+        return iter.hasNext() ? iter.next() : null;
+    }
+
+    private class NodeIterator<T extends ParserContextNode> implements Iterator<T> {
         private int index;
         private T next;
         private final Class<T> clazz;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextFunctionNode.java	Wed Jul 05 21:38:12 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextFunctionNode.java	Wed Apr 27 15:50:33 2016 +0200
@@ -24,10 +24,12 @@
  */
 package jdk.nashorn.internal.parser;
 
+import java.util.HashSet;
 import java.util.List;
 import jdk.nashorn.internal.codegen.Namespace;
 import jdk.nashorn.internal.ir.FunctionNode;
 import jdk.nashorn.internal.ir.IdentNode;
+import jdk.nashorn.internal.ir.Module;
 
 /**
  * ParserContextNode that represents a function that is currently being parsed
@@ -46,11 +48,11 @@
     /** Line number for function declaration */
     private final int line;
 
-    /** Function node kind, see {@link FunctionNode#Kind} */
+    /** Function node kind, see {@link FunctionNode.Kind} */
     private final FunctionNode.Kind kind;
 
     /** List of parameter identifiers for function */
-    private final List<IdentNode> parameters;
+    private List<IdentNode> parameters;
 
     /** Token for function start */
     private final long token;
@@ -61,6 +63,14 @@
     /** Opaque node for parser end state, see {@link Parser} */
     private Object endParserState;
 
+    private HashSet<String> parameterBoundNames;
+    private IdentNode duplicateParameterBinding;
+    private boolean simpleParameterList = true;
+
+    private Module module;
+
+    private int debugFlags;
+
     /**
      * @param token The token for the function
      * @param ident External function name
@@ -155,6 +165,10 @@
         return parameters;
     }
 
+    void setParameters(List<IdentNode> parameters) {
+        this.parameters = parameters;
+    }
+
     /**
      * Set last token
      * @param token New last token
@@ -194,4 +208,70 @@
     public int getId() {
         return isProgram() ? -1 : Token.descPosition(token);
     }
+
+    /**
+     * Returns the debug flags for this function.
+     *
+     * @return the debug flags
+     */
+    int getDebugFlags() {
+        return debugFlags;
+    }
+
+    /**
+     * Sets a debug flag for this function.
+     *
+     * @param debugFlag the debug flag
+     */
+    void setDebugFlag(final int debugFlag) {
+        debugFlags |= debugFlag;
+    }
+
+    public boolean isMethod() {
+        return getFlag(FunctionNode.ES6_IS_METHOD) != 0;
+    }
+
+    public boolean isClassConstructor() {
+        return getFlag(FunctionNode.ES6_IS_CLASS_CONSTRUCTOR) != 0;
+    }
+
+    public boolean isSubclassConstructor() {
+        return getFlag(FunctionNode.ES6_IS_SUBCLASS_CONSTRUCTOR) != 0;
+    }
+
+    boolean addParameterBinding(final IdentNode bindingIdentifier) {
+        if (Parser.isArguments(bindingIdentifier)) {
+            setFlag(FunctionNode.DEFINES_ARGUMENTS);
+        }
+
+        if (parameterBoundNames == null) {
+            parameterBoundNames = new HashSet<>();
+        }
+        if (parameterBoundNames.add(bindingIdentifier.getName())) {
+            return true;
+        } else {
+            duplicateParameterBinding = bindingIdentifier;
+            return false;
+        }
+    }
+
+    public IdentNode getDuplicateParameterBinding() {
+        return duplicateParameterBinding;
+    }
+
+    public boolean isSimpleParameterList() {
+        return simpleParameterList;
+    }
+
+    public void setSimpleParameterList(final boolean simpleParameterList) {
+        this.simpleParameterList = simpleParameterList;
+    }
+
+    public Module getModule() {
+        return module;
+    }
+
+    public void setModule(final Module module) {
+        this.module = module;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextModuleNode.java	Wed Apr 27 15:50:33 2016 +0200
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2015, 2016, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package jdk.nashorn.internal.parser;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.nashorn.internal.ir.Module;
+import jdk.nashorn.internal.ir.Module.ExportEntry;
+import jdk.nashorn.internal.ir.Module.ImportEntry;
+
+/**
+ * ParserContextNode that represents a module.
+ */
+class ParserContextModuleNode extends ParserContextBaseNode {
+
+    /** Module name. */
+    private final String name;
+
+    private List<String> requestedModules = new ArrayList<>();
+    private List<ImportEntry> importEntries = new ArrayList<>();
+    private List<ExportEntry> localExportEntries = new ArrayList<>();
+    private List<ExportEntry> indirectExportEntries = new ArrayList<>();
+    private List<ExportEntry> starExportEntries = new ArrayList<>();
+
+    /**
+     * Constructor.
+     *
+     * @param name name of the module
+     */
+    ParserContextModuleNode(final String name) {
+        this.name = name;
+    }
+
+    /**
+     * Returns the name of the module.
+     *
+     * @return name of the module
+     */
+    public String getModuleName() {
+        return name;
+    }
+
+    public void addModuleRequest(final String moduleRequest) {
+        requestedModules.add(moduleRequest);
+    }
+
+    public void addImportEntry(final ImportEntry importEntry) {
+        importEntries.add(importEntry);
+    }
+
+    public void addLocalExportEntry(final ExportEntry exportEntry) {
+        localExportEntries.add(exportEntry);
+    }
+
+    public void addIndirectExportEntry(final ExportEntry exportEntry) {
+        indirectExportEntries.add(exportEntry);
+    }
+
+    public void addStarExportEntry(final ExportEntry exportEntry) {
+        starExportEntries.add(exportEntry);
+    }
+
+    public Module createModule() {
+        return new Module(requestedModules, importEntries, localExportEntries, indirectExportEntries, starExportEntries);
+    }
+}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/TokenType.java	Wed Jul 05 21:38:12 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/TokenType.java	Wed Apr 27 15:50:33 2016 +0200
@@ -82,7 +82,7 @@
     ASSIGN         (BINARY,  "=",     2, false),
     EQ             (BINARY,  "==",    9, true),
     EQ_STRICT      (BINARY,  "===",   9, true),
-    BIND           (BINARY,  "=>",    9, true),
+    ARROW          (BINARY,  "=>",    2, true),
     GT             (BINARY,  ">",    10, true),
     GE             (BINARY,  ">=",   10, true),
     SAR            (BINARY,  ">>",   11, true),
@@ -100,6 +100,7 @@
     OR             (BINARY,  "||",    4, true),
     RBRACE         (BRACKET, "}"),
     BIT_NOT        (UNARY,   "~",     14, false),
+    ELLIPSIS       (UNARY,   "..."),
 
     // ECMA 7.6.1.1 Keywords, 7.6.1.2 Future Reserved Words.
     // All other Java keywords are commented out.
@@ -190,7 +191,10 @@
 
     COMMALEFT      (IR,       null),
     DECPOSTFIX     (IR,       null),
-    INCPOSTFIX     (IR,       null);
+    INCPOSTFIX     (IR,       null),
+    SPREAD_ARGUMENT(IR,       null),
+    SPREAD_ARRAY   (IR,       null),
+    YIELD_STAR     (IR,       null);
 
     /** Next token kind in token lookup table. */
     private TokenType next;
@@ -251,7 +255,6 @@
         return kind == BINARY && (!noIn || this != IN) && precedence != 0;
     }
 
-
     public int getLength() {
         assert name != null : "Token name not set";
         return name.length();
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java	Wed Jul 05 21:38:12 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java	Wed Apr 27 15:50:33 2016 +0200
@@ -1403,11 +1403,11 @@
                 return null;
             }
 
-            if (env._print_ast || functionNode.getFlag(FunctionNode.IS_PRINT_AST)) {
+            if (env._print_ast || functionNode.getDebugFlag(FunctionNode.DEBUG_PRINT_AST)) {
                 getErr().println(new ASTWriter(functionNode));
             }
 
-            if (env._print_parse || functionNode.getFlag(FunctionNode.IS_PRINT_PARSE)) {
+            if (env._print_parse || functionNode.getDebugFlag(FunctionNode.DEBUG_PRINT_PARSE)) {
                 getErr().println(new PrintVisitor(functionNode, true, false));
             }
         }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties	Wed Jul 05 21:38:12 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties	Wed Apr 27 15:50:33 2016 +0200
@@ -63,6 +63,27 @@
 parser.error.missing.const.assignment=Missing assignment to constant "{0}"
 parser.error.unterminated.template.expression=Expected } after expression in template literal
 
+# ES6 mode error messages
+parser.error.multiple.constructors=Class contains more than one constructor
+parser.error.generator.constructor=Class constructor must not be a generator
+parser.error.accessor.constructor=Class constructor must not be an accessor
+parser.error.static.prototype.method=Static class method must not be named 'prototype'
+parser.error.missing.destructuring.assignment=Missing assignment in destructuring declaration
+parser.error.let.binding.for='let' is not a valid binding name in a for loop
+parser.error.invalid.export=invalid export declaration
+parser.error.expected.binding=expected BindingIdentifier or BindingPattern
+parser.error.multiple.proto.key=property name __proto__ appears more than once in object literal
+parser.error.new.target.in.function=new.target expression is only allowed in functions
+parser.error.expected.target=expected 'target'
+parser.error.invalid.super=invalid use of keyword super
+parser.error.expected.arrow.parameter=expected arrow function parameter list
+parser.error.invalid.arrow.parameter=invalid arrow function parameter
+parser.error.expected.named.import=expected NameSpaceImport or NamedImports
+parser.error.expected.import=expected ImportClause or ModuleSpecifier
+parser.error.expected.as=expected 'as'
+parser.error.expected.binding.identifier=expected BindingIdentifier
+parser.error.expected.from=expected 'from'
+
 # strict mode error messages
 parser.error.strict.no.with="with" statement cannot be used in strict mode
 parser.error.strict.name="{0}" cannot be used as {1} in strict mode
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/Shell.java	Wed Jul 05 21:38:12 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/Shell.java	Wed Apr 27 15:50:33 2016 +0200
@@ -438,6 +438,9 @@
                 final File file = new File(fileName);
                 final ScriptFunction script = context.compileScript(sourceFor(fileName, file), global);
                 if (script == null || errors.getNumberOfErrors() != 0) {
+                    if (context.getEnv()._parse_only && !errors.hasErrors()) {
+                        continue; // No error, continue to consume all files in list
+                    }
                     return COMPILATION_ERROR;
                 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/parser-es6.js	Wed Apr 27 15:50:33 2016 +0200
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2016, 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-8134503: support ES6 parsing in Nashorn
+ *
+ * @test
+ * @option --language=es6
+ * @option --parse-only
+ */
+
+
+[].map(v => v + 1);
+
+class A extends B.C {
+    constructor(a, b) {
+        super(a, b);
+    }
+    someMethod(c) {
+        super.someMethod();
+    }
+    get g() {
+        return this.g;
+    }
+    set s(t) {
+        this.t = t;
+    }
+    static m() {
+        return k;
+    }
+}
+
+var obj = {
+    __proto__: theProtoObj,
+    handler,
+    r() {
+        return super.m();
+    },
+    [ '__' + (() => 'x')() ]: 1,
+    *q (x, y) {
+       yield 1;
+    }
+};
+
+var [a, , b] = [1, 2, 3];
+
+var { x: a, y: { z: b }, w: c } = abc();
+
+var {a, b, c} = abc();
+
+var o = { x, y };
+
+function g({name: x}) {
+  return x;
+}
+
+foo(a, ...b);
+
+var c = [ ...s ];
+
+var [a] = [];
+
+var [a = 1] = [];
+
+
+var f = {
+    [Symbol.iterator]: function*() {
+        var cur = 1;
+        for (;;) {
+            yield cur;
+        }
+    }
+};
+
--- a/nashorn/test/script/basic/yield.js	Wed Jul 05 21:38:12 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, 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.
- */
-
-
-/**
- * Check yield keyword is parsed and yield statement does nothing (yet).
- *
- * @test
- * @run
- */
-
-function func() {
-    yield 2;
-}
--- a/nashorn/test/script/error/NASHORN-154/function_mult_params_in_strict.js.EXPECTED	Wed Jul 05 21:38:12 2017 +0200
+++ b/nashorn/test/script/error/NASHORN-154/function_mult_params_in_strict.js.EXPECTED	Wed Apr 27 15:50:33 2016 +0200
@@ -1,3 +1,3 @@
-test/script/error/NASHORN-154/function_mult_params_in_strict.js:38:14 strict mode function cannot have duplicate parameter name "x"
+test/script/error/NASHORN-154/function_mult_params_in_strict.js:38:17 strict mode function cannot have duplicate parameter name "x"
 function func(x, x) {}
-              ^
+                 ^
--- a/nashorn/test/script/nosecurity/parserapi.js.EXPECTED	Wed Jul 05 21:38:12 2017 +0200
+++ b/nashorn/test/script/nosecurity/parserapi.js.EXPECTED	Wed Apr 27 15:50:33 2016 +0200
@@ -100,7 +100,7 @@
             "startPosition": "1181",
             "properties": [
               {
-                "endPosition": "1185",
+                "endPosition": "1187",
                 "kind": "PROPERTY",
                 "value": {
                   "endPosition": "1187",
@@ -2386,7 +2386,7 @@
           "startPosition": "1139",
           "properties": [
             {
-              "endPosition": "1143",
+              "endPosition": "1146",
               "kind": "PROPERTY",
               "value": {
                 "endPosition": "1146",
@@ -2403,7 +2403,7 @@
               }
             },
             {
-              "endPosition": "1150",
+              "endPosition": "1152",
               "kind": "PROPERTY",
               "value": {
                 "endPosition": "1152",
@@ -2443,7 +2443,7 @@
           "startPosition": "1160",
           "properties": [
             {
-              "endPosition": "1166",
+              "endPosition": "1169",
               "kind": "PROPERTY",
               "value": {
                 "endPosition": "1169",
@@ -2460,7 +2460,7 @@
               }
             },
             {
-              "endPosition": "1175",
+              "endPosition": "1177",
               "kind": "PROPERTY",
               "value": {
                 "endPosition": "1177",
@@ -2914,7 +2914,7 @@
         "startPosition": "1178",
         "properties": [
           {
-            "endPosition": "1182",
+            "endPosition": "1184",
             "kind": "PROPERTY",
             "value": {
               "endPosition": "1184",
@@ -3395,7 +3395,7 @@
         "startPosition": "1200",
         "properties": [
           {
-            "endPosition": "1206",
+            "endPosition": "1214",
             "kind": "PROPERTY",
             "value": {
               "endPosition": "1214",
@@ -4709,11 +4709,11 @@
 ,
 {
   "fileName": "parsernegativetests/strict_repeatparam.js",
-  "code": "ident (1119, 1)",
-  "columnNumber": "14",
+  "code": "ident (1122, 1)",
+  "columnNumber": "17",
   "kind": "ERROR",
-  "position": "1119",
-  "message": "parsernegativetests/strict_repeatparam.js:31:14 strict mode function cannot have duplicate parameter name \"x\"\nfunction func(x, x) {}\n              ^",
+  "position": "1122",
+  "message": "parsernegativetests/strict_repeatparam.js:31:17 strict mode function cannot have duplicate parameter name \"x\"\nfunction func(x, x) {}\n                 ^",
   "lineNumber": "31"
 }
 ,
--- a/nashorn/test/script/nosecurity/parserapi_strict.js.EXPECTED	Wed Jul 05 21:38:12 2017 +0200
+++ b/nashorn/test/script/nosecurity/parserapi_strict.js.EXPECTED	Wed Apr 27 15:50:33 2016 +0200
@@ -6,10 +6,10 @@
 
 with({}) {}
        ^
-repeat_param.js:2:15 strict mode function cannot have duplicate parameter name "x"
+repeat_param.js:2:18 strict mode function cannot have duplicate parameter name "x"
 
 function func(x, x) {}
-               ^
+                  ^
 repeat_prop.js:2:22 Property "foo" already defined
 
 var obj = { foo: 34, foo: 'hello' };
--- a/nashorn/test/script/nosecurity/treeapi/array_literal.js.EXPECTED	Wed Jul 05 21:38:12 2017 +0200
+++ b/nashorn/test/script/nosecurity/treeapi/array_literal.js.EXPECTED	Wed Apr 27 15:50:33 2016 +0200
@@ -74,7 +74,7 @@
         "properties": [
           {
             "getter": "null",
-            "endPosition": "74",
+            "endPosition": "76",
             "kind": "PROPERTY",
             "setter": "null",
             "value": {
--- a/nashorn/test/script/nosecurity/treeapi/objectLiteral.js.EXPECTED	Wed Jul 05 21:38:12 2017 +0200
+++ b/nashorn/test/script/nosecurity/treeapi/objectLiteral.js.EXPECTED	Wed Apr 27 15:50:33 2016 +0200
@@ -6,7 +6,7 @@
     "properties": [
       {
         "getter": "null",
-        "endPosition": "8",
+        "endPosition": "12",
         "kind": "PROPERTY",
         "setter": "null",
         "value": {
@@ -38,7 +38,7 @@
     "properties": [
       {
         "getter": "null",
-        "endPosition": "34",
+        "endPosition": "37",
         "kind": "PROPERTY",
         "setter": "null",
         "value": {
@@ -57,7 +57,7 @@
       },
       {
         "getter": "null",
-        "endPosition": "41",
+        "endPosition": "43",
         "kind": "PROPERTY",
         "setter": "null",
         "value": {
@@ -83,7 +83,7 @@
     "properties": [
       {
         "getter": "null",
-        "endPosition": "57",
+        "endPosition": "60",
         "kind": "PROPERTY",
         "setter": "null",
         "value": {
@@ -102,7 +102,7 @@
       },
       {
         "getter": "null",
-        "endPosition": "66",
+        "endPosition": "68",
         "kind": "PROPERTY",
         "setter": "null",
         "value": {
--- a/nashorn/test/script/nosecurity/treeapi/property.js.EXPECTED	Wed Jul 05 21:38:12 2017 +0200
+++ b/nashorn/test/script/nosecurity/treeapi/property.js.EXPECTED	Wed Apr 27 15:50:33 2016 +0200
@@ -1,7 +1,7 @@
 [
   {
     "getter": "null",
-    "endPosition": "17",
+    "endPosition": "22",
     "kind": "PROPERTY",
     "setter": "null",
     "value": {
@@ -20,7 +20,7 @@
   },
   {
     "getter": "null",
-    "endPosition": "31",
+    "endPosition": "38",
     "kind": "PROPERTY",
     "setter": "null",
     "value": {
@@ -45,7 +45,7 @@
   },
   {
     "getter": "null",
-    "endPosition": "46",
+    "endPosition": "61",
     "kind": "PROPERTY",
     "setter": "null",
     "value": {
@@ -72,7 +72,7 @@
   },
   {
     "getter": "null",
-    "endPosition": "69",
+    "endPosition": "72",
     "kind": "PROPERTY",
     "setter": "null",
     "value": {
--- a/nashorn/test/script/nosecurity/treeapi/throw.js.EXPECTED	Wed Jul 05 21:38:12 2017 +0200
+++ b/nashorn/test/script/nosecurity/treeapi/throw.js.EXPECTED	Wed Apr 27 15:50:33 2016 +0200
@@ -80,7 +80,7 @@
       "properties": [
         {
           "getter": "null",
-          "endPosition": "97",
+          "endPosition": "105",
           "kind": "PROPERTY",
           "setter": "null",
           "value": {
--- a/nashorn/test/script/nosecurity/treeapi/with.js.EXPECTED	Wed Jul 05 21:38:12 2017 +0200
+++ b/nashorn/test/script/nosecurity/treeapi/with.js.EXPECTED	Wed Apr 27 15:50:33 2016 +0200
@@ -49,7 +49,7 @@
       "properties": [
         {
           "getter": "null",
-          "endPosition": "34",
+          "endPosition": "39",
           "kind": "PROPERTY",
           "setter": "null",
           "value": {
--- a/nashorn/test/src/jdk/nashorn/internal/test/framework/ScriptRunnable.java	Wed Jul 05 21:38:12 2017 +0200
+++ b/nashorn/test/src/jdk/nashorn/internal/test/framework/ScriptRunnable.java	Wed Apr 27 15:50:33 2016 +0200
@@ -194,9 +194,9 @@
             pb.redirectError(errorFileHandle);
             final Process process = pb.start();
 
-            process.waitFor();
+            final int exitCode = process.waitFor();
 
-            if (errorFileHandle.length() > 0) {
+            if (exitCode != 0 || errorFileHandle.length() > 0) {
                 if (expectRunFailure) {
                     return;
                 }