From cb588b427097b41806010812589574dfc1242704 Mon Sep 17 00:00:00 2001 From: Alexander Stummer Date: Wed, 14 Dec 2022 11:40:35 +0100 Subject: [PATCH 1/7] Allowing symbols as WeakMap keys. --- .../js/symbol-as-weakmap-key.js | 25 +++++++ .../js/builtins/WeakMapPrototypeBuiltins.java | 70 +++++++++++++------ .../com/oracle/truffle/js/runtime/Symbol.java | 12 ++++ .../js/runtime/builtins/JSWeakMap.java | 2 +- .../js/runtime/builtins/JSWeakMapObject.java | 7 +- .../truffle/js/runtime/util/WeakMap.java | 52 +++++++++----- 6 files changed, 123 insertions(+), 45 deletions(-) create mode 100644 graal-js/src/com.oracle.truffle.js.test/js/symbol-as-weakmap-key.js diff --git a/graal-js/src/com.oracle.truffle.js.test/js/symbol-as-weakmap-key.js b/graal-js/src/com.oracle.truffle.js.test/js/symbol-as-weakmap-key.js new file mode 100644 index 00000000000..579d5b93aa9 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/js/symbol-as-weakmap-key.js @@ -0,0 +1,25 @@ +/** + * Symbols as WeakMap keys proposal. + * + * @option ecmascript-version=staging + */ + + +load('assert.js'); +//Testing valid symbol as key +const weak = new WeakMap(); + + +const key = Symbol('my ref'); +const obj = {}; + +weak.set(key, obj); + +assertSame(obj, weak.get(key)); + +//Testing for invalid, registered symbol +const key2 = Symbol.for('name'); + +assertThrows(() => weak.set(key2, obj), TypeError); + + diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/WeakMapPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/WeakMapPrototypeBuiltins.java index c88ed569ac7..618c47c8484 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/WeakMapPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/WeakMapPrototypeBuiltins.java @@ -40,6 +40,7 @@ */ package com.oracle.truffle.js.builtins; +import java.util.Map; import java.util.WeakHashMap; import com.oracle.truffle.api.CompilerDirectives; @@ -60,6 +61,7 @@ import com.oracle.truffle.js.runtime.Errors; import com.oracle.truffle.js.runtime.JSConfig; import com.oracle.truffle.js.runtime.JSContext; +import com.oracle.truffle.js.runtime.Symbol; import com.oracle.truffle.js.runtime.builtins.BuiltinEnum; import com.oracle.truffle.js.runtime.builtins.JSWeakMap; import com.oracle.truffle.js.runtime.builtins.JSWeakMapObject; @@ -111,8 +113,8 @@ protected Object createNode(JSContext context, JSBuiltin builtin, boolean constr return null; } - protected static RuntimeException typeErrorKeyIsNotObject() { - throw Errors.createTypeError("WeakMap key must be an object"); + protected static RuntimeException typeErrorKeyIsNotValid() { + throw Errors.createTypeError("WeakMap key must be an object or a symbol"); } protected static RuntimeException typeErrorWeakMapExpected() { @@ -125,14 +127,34 @@ protected JSWeakMapBaseNode(JSContext context, JSBuiltin builtin) { super(context, builtin); } - protected static Object getInvertedMap(JSObject key, DynamicObjectLibrary library) { - return library.getOrDefault(key, WeakMap.INVERTED_WEAK_MAP_KEY, null); + protected static Object getInvertedMap(Object key, DynamicObjectLibrary library) { + if(key instanceof JSObject){ + return library.getOrDefault((JSObject)key, WeakMap.INVERTED_WEAK_MAP_KEY, null); + } else if(key instanceof Symbol){ + return ((Symbol)key).getInvertedMap(); + } else { + return null; + } } @SuppressWarnings("unchecked") protected static WeakHashMap castWeakHashMap(Object map) { return CompilerDirectives.castExact(map, WeakHashMap.class); } + + protected boolean canBeHeldWeakly(Object v){ + if(v instanceof JSObject){ + return true; + } else if(v instanceof Symbol && symbolsAllowed()){ + Symbol s = (Symbol) v; + return !s.isRegistered(); + } + return false; + } + protected boolean symbolsAllowed(){ + return this.getContext().getEcmaScriptVersion() >= JSConfig.StagingECMAScriptVersion; + } + } /** @@ -145,8 +167,8 @@ public JSWeakMapDeleteNode(JSContext context, JSBuiltin builtin) { super(context, builtin); } - @Specialization - protected static boolean delete(JSWeakMapObject thisObj, JSObject key, + @Specialization(guards = {"canBeHeldWeakly(key)"}) + protected static boolean delete(JSWeakMapObject thisObj, Object key, @CachedLibrary(limit = "PropertyCacheLimit") DynamicObjectLibrary invertedGetter, @Cached("createBinaryProfile()") ConditionProfile hasInvertedProfile) { WeakMap map = (WeakMap) JSWeakMap.getInternalWeakMap(thisObj); @@ -159,8 +181,8 @@ protected static boolean delete(JSWeakMapObject thisObj, JSObject key, } @SuppressWarnings("unused") - @Specialization(guards = {"!isJSObject(key)"}) - protected static boolean deleteNonObjectKey(JSWeakMapObject thisObj, Object key) { + @Specialization(guards = {"!canBeHeldWeakly(key)"}) + protected static boolean deleteInvalidKey(JSWeakMapObject thisObj, Object key) { return false; } @@ -181,8 +203,8 @@ public JSWeakMapGetNode(JSContext context, JSBuiltin builtin) { super(context, builtin); } - @Specialization - protected Object get(JSWeakMapObject thisObj, JSObject key, + @Specialization(guards = {"canBeHeldWeakly(key)"}) + protected Object get(JSWeakMapObject thisObj, Object key, @CachedLibrary(limit = "PropertyCacheLimit") DynamicObjectLibrary invertedGetter, @Cached("createBinaryProfile()") ConditionProfile hasInvertedProfile) { WeakMap map = (WeakMap) JSWeakMap.getInternalWeakMap(thisObj); @@ -198,8 +220,8 @@ protected Object get(JSWeakMapObject thisObj, JSObject key, } @SuppressWarnings("unused") - @Specialization(guards = {"!isJSObject(key)"}) - protected static Object getNonObjectKey(JSWeakMapObject thisObj, Object key) { + @Specialization(guards = {"!canBeHeldWeakly(key)"}) + protected static Object getInvalidKey(JSWeakMapObject thisObj, Object key) { return Undefined.instance; } @@ -225,8 +247,8 @@ public JSWeakMapSetNode(JSContext context, JSBuiltin builtin) { super(context, builtin); } - @Specialization - protected Object set(JSWeakMapObject thisObj, JSObject key, Object value, + @Specialization(guards = {"canBeHeldWeakly(key)"}) + protected Object set(JSWeakMapObject thisObj, Object key, Object value, @CachedLibrary(limit = "PropertyCacheLimit") DynamicObjectLibrary invertedGetter, @CachedLibrary(limit = "PropertyCacheLimit") DynamicObjectLibrary invertedSetter, @Cached("createBinaryProfile()") ConditionProfile hasInvertedProfile) { @@ -237,15 +259,19 @@ protected Object set(JSWeakMapObject thisObj, JSObject key, Object value, mapPut(invertedMap, map, value); } else { inverted = map.newInvertedMapWithEntry(key, value); - invertedSetter.put(key, WeakMap.INVERTED_WEAK_MAP_KEY, inverted); + if(key instanceof JSObject){ + invertedSetter.put((JSObject) key, WeakMap.INVERTED_WEAK_MAP_KEY, inverted); + } else if(key instanceof Symbol){ + ((Symbol)key).setInvertedMap((Map) inverted); + } } return thisObj; } @SuppressWarnings("unused") - @Specialization(guards = {"!isJSObject(key)"}) - protected static Object setNonObjectKey(JSWeakMapObject thisObj, Object key, Object value) { - throw typeErrorKeyIsNotObject(); + @Specialization(guards = {"!canBeHeldWeakly(key)"}) + protected static Object setInvalidKey(JSWeakMapObject thisObj, Object key, Object value) { + throw typeErrorKeyIsNotValid(); } @SuppressWarnings("unused") @@ -270,8 +296,8 @@ public JSWeakMapHasNode(JSContext context, JSBuiltin builtin) { super(context, builtin); } - @Specialization - protected boolean has(JSWeakMapObject thisObj, JSObject key, + @Specialization(guards = {"canBeHeldWeakly(key)"}) + protected boolean has(JSWeakMapObject thisObj, Object key, @CachedLibrary(limit = "PropertyCacheLimit") DynamicObjectLibrary invertedGetter, @Cached("createBinaryProfile()") ConditionProfile hasInvertedProfile) { WeakMap map = (WeakMap) JSWeakMap.getInternalWeakMap(thisObj); @@ -289,8 +315,8 @@ private static boolean mapHas(WeakHashMap invertedMap, WeakMap } @SuppressWarnings("unused") - @Specialization(guards = {"!isJSObject(key)"}) - protected static boolean hasNonObjectKey(JSWeakMapObject thisObj, Object key) { + @Specialization(guards = {"!canBeHeldWeakly(key)"}) + protected static boolean hasInvalidKey(JSWeakMapObject thisObj, Object key) { return false; } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Symbol.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Symbol.java index 75ce34e66a2..9643c04888a 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Symbol.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Symbol.java @@ -56,6 +56,8 @@ import com.oracle.truffle.js.runtime.builtins.JSSymbol; import com.oracle.truffle.js.runtime.interop.JSMetaType; import com.oracle.truffle.js.runtime.objects.Undefined; +import com.oracle.truffle.js.runtime.util.WeakMap; +import java.util.Map; /** * @see JSSymbol @@ -238,4 +240,14 @@ static TriState doOther(Symbol receiver, Object other) { int identityHashCode() { return super.hashCode(); } + + private Map invertedMap; + + public Map getInvertedMap(){ + return invertedMap; + } + + public void setInvertedMap(Map invMap) { + invertedMap = invMap; + } } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSWeakMap.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSWeakMap.java index 5e2a4bacc55..04f692b3262 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSWeakMap.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSWeakMap.java @@ -74,7 +74,7 @@ public static JSWeakMapObject create(JSContext context, JSRealm realm) { } @SuppressWarnings("unchecked") - public static Map getInternalWeakMap(JSDynamicObject obj) { + public static Map getInternalWeakMap(JSDynamicObject obj) { assert isJSWeakMap(obj); return ((JSWeakMapObject) obj).getWeakHashMap(); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSWeakMapObject.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSWeakMapObject.java index 214e99c4d21..e81060b5390 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSWeakMapObject.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSWeakMapObject.java @@ -44,17 +44,16 @@ import com.oracle.truffle.api.object.Shape; import com.oracle.truffle.js.runtime.objects.JSNonProxyObject; -import com.oracle.truffle.js.runtime.objects.JSObject; public final class JSWeakMapObject extends JSNonProxyObject { - private final Map weakHashMap; + private final Map weakHashMap; - protected JSWeakMapObject(Shape shape, Map weakHashMap) { + protected JSWeakMapObject(Shape shape, Map weakHashMap) { super(shape); this.weakHashMap = weakHashMap; } - public Map getWeakHashMap() { + public Map getWeakHashMap() { return weakHashMap; } } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/WeakMap.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/WeakMap.java index c0f45a189d3..ba9fe8037da 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/WeakMap.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/WeakMap.java @@ -47,6 +47,7 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.object.HiddenKey; +import com.oracle.truffle.js.runtime.Symbol; import com.oracle.truffle.js.runtime.objects.JSDynamicObject; import com.oracle.truffle.js.runtime.objects.JSObject; import com.oracle.truffle.js.runtime.objects.JSObjectUtil; @@ -55,27 +56,42 @@ * JavaScript WeakMap that emulates ephemeron semantics by storing the value in the key itself * (i.e., in a hidden property within the key object). */ -public final class WeakMap implements Map { +public final class WeakMap implements Map{ public static final HiddenKey INVERTED_WEAK_MAP_KEY = new HiddenKey("InvertedWeakMap"); public WeakMap() { } - private static JSObject checkKey(Object key) { - if (!(key instanceof JSObject)) { - throw new IllegalArgumentException("key must be instanceof JSObject"); + private static Object checkKey(Object key) { + if (key instanceof JSObject){ + return (JSObject) key; + } else if (key instanceof Symbol) { + return (Symbol) key; + } else { + throw new IllegalArgumentException("key must be instanceof JSObject or Symbol"); } - return (JSObject) key; + } @SuppressWarnings("unchecked") - private static Map getInvertedMap(JSObject k) { - return (Map) JSDynamicObject.getOrNull(k, INVERTED_WEAK_MAP_KEY); + private static Map getInvertedMap(Object k) { + if(k instanceof JSObject){ + return (Map) JSDynamicObject.getOrNull((JSObject) k, INVERTED_WEAK_MAP_KEY); + } else if(k instanceof Symbol){ + return ((Symbol)k).getInvertedMap(); + } else { + return null; + } } - private static Map putInvertedMap(JSObject k) { + private static Map putInvertedMap(Object k) { Map invertedMap = newInvertedMap(); - JSObjectUtil.putHiddenProperty(k, INVERTED_WEAK_MAP_KEY, invertedMap); + if(k instanceof JSObject){ + JSObjectUtil.putHiddenProperty((JSObject) k, INVERTED_WEAK_MAP_KEY, invertedMap); + } else if(k instanceof Symbol){ + ((Symbol)k).setInvertedMap(invertedMap); + } + return invertedMap; } @@ -85,7 +101,7 @@ public static Map newInvertedMap() { } @TruffleBoundary - public Map newInvertedMapWithEntry(JSObject key, Object value) { + public Map newInvertedMapWithEntry(Object key, Object value) { assert getInvertedMap(key) == null; Map map = new WeakHashMap<>(); map.put(this, value); @@ -94,21 +110,21 @@ public Map newInvertedMapWithEntry(JSObject key, Object value) @Override public boolean containsKey(Object key) { - JSObject k = checkKey(key); + Object k = checkKey(key); Map invertedMap = getInvertedMap(k); return invertedMap == null ? false : invertedMap.containsKey(this); } @Override public Object get(Object key) { - JSObject k = checkKey(key); + Object k = checkKey(key); Map invertedMap = getInvertedMap(k); return invertedMap == null ? null : invertedMap.get(this); } @Override - public Object put(JSObject key, Object value) { - JSObject k = checkKey(key); + public Object put(Object key, Object value) { + Object k = checkKey(key); Map invertedMap = getInvertedMap(k); if (invertedMap == null) { invertedMap = putInvertedMap(k); @@ -118,13 +134,13 @@ public Object put(JSObject key, Object value) { @Override public Object remove(Object key) { - JSObject k = checkKey(key); + Object k = checkKey(key); Map invertedMap = getInvertedMap(k); return invertedMap == null ? null : invertedMap.remove(this); } @Override - public void putAll(Map m) { + public void putAll(Map m) { m.forEach(this::put); } @@ -149,7 +165,7 @@ public void clear() { } @Override - public Set keySet() { + public Set keySet() { throw unsupported(); } @@ -159,7 +175,7 @@ public Collection values() { } @Override - public Set> entrySet() { + public Set> entrySet() { throw unsupported(); } From da075761ffcdd223ad5afe682a71ef35bdffa4f0 Mon Sep 17 00:00:00 2001 From: Alexander Stummer Date: Wed, 22 Feb 2023 12:14:47 +0100 Subject: [PATCH 2/7] Extended Parser to parse PipeLine-Expressions. --- .../src/com/oracle/js/parser/Parser.java | 53 +++++++++-- .../src/com/oracle/js/parser/TokenType.java | 1 + .../com/oracle/js/parser/ir/BinaryNode.java | 2 +- .../com/oracle/js/parser/ir/PipelineNode.java | 17 ++++ .../com.oracle.truffle.js.test/js/pipeline.js | 87 +++++++++++++++++++ 5 files changed, 151 insertions(+), 9 deletions(-) create mode 100644 graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/PipelineNode.java create mode 100644 graal-js/src/com.oracle.truffle.js.test/js/pipeline.js diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java index a12d8e84990..7eb5a8f7ff1 100644 --- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java +++ b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java @@ -84,6 +84,7 @@ import static com.oracle.js.parser.TokenType.MUL; import static com.oracle.js.parser.TokenType.OF; import static com.oracle.js.parser.TokenType.PERIOD; +import static com.oracle.js.parser.TokenType.PIPELINE; import static com.oracle.js.parser.TokenType.PRIVATE_IDENT; import static com.oracle.js.parser.TokenType.RBRACE; import static com.oracle.js.parser.TokenType.RBRACKET; @@ -117,6 +118,7 @@ import java.util.Map; import java.util.function.Consumer; +import com.oracle.js.parser.ir.PipelineNode; import org.graalvm.collections.Pair; import com.oracle.js.parser.ir.AccessNode; @@ -362,6 +364,10 @@ public class Parser extends AbstractParser { private boolean isModule; + private int pipeDepth = 0; + + private boolean topicReferenceUsed = false; + /** * Used to pass (async) arrow function flags from head to body. * @@ -1116,7 +1122,7 @@ protected boolean enterDefault(Node node) { }); } - private Expression newBinaryExpression(final long op, final Expression lhs, final Expression rhs) { + private Expression newBinaryExpression(final long op, final Expression lhs, final Expression rhs, int level) { final TokenType opType = Token.descType(op); // Build up node. @@ -1125,6 +1131,8 @@ private Expression newBinaryExpression(final long op, final Expression lhs, fina throw error(String.format("nullish coalescing operator cannot immediately contain, or be contained within, an && or || operation")); } return new BinaryNode(op, new JoinPredecessorExpression(lhs), new JoinPredecessorExpression(rhs)); + } else if (PipelineNode.isPipeline(opType)){ + return new PipelineNode(op, lhs, rhs, level); } return new BinaryNode(op, lhs, rhs); } @@ -3920,6 +3928,7 @@ private void debuggerStatement() { *
      * PrimaryExpression :
      *      this
+     *      %
      *      IdentifierReference
      *      Literal
      *      ArrayLiteral
@@ -4007,6 +4016,15 @@ private Expression primaryExpression(boolean yield, boolean await, CoverExpressi
                         TruffleString v8IntrinsicNameTS = lexer.stringIntern(v8IntrinsicName);
                         return createIdentNode(v8IntrinsicToken, ident.getFinish(), v8IntrinsicNameTS);
                     }
+                } else {
+                    next();
+
+                    if(pipeDepth <= 0){
+                        throw error(JSErrorType.SyntaxError, "The topic reference can not be used here!");
+                    }
+                    addIdentifierReference("%" + pipeDepth);
+                    topicReferenceUsed = true;
+                    return new IdentNode(primaryToken, finish, lexer.stringIntern("%" + pipeDepth));
                 }
 
             default:
@@ -6260,20 +6278,20 @@ private Expression expression(int minPrecedence, boolean in, boolean yield, bool
         } else {
             lhs = unaryExpression(yield, await, coverExpression);
         }
-        return expression(lhs, minPrecedence, in, yield, await);
+        return expression(lhs, minPrecedence, in, yield, await, false);
     }
 
     private JoinPredecessorExpression joinPredecessorExpression(boolean yield, boolean await) {
         return new JoinPredecessorExpression(expression(yield, await));
     }
 
-    private Expression expression(Expression exprLhs, int minPrecedence, boolean in, boolean yield, boolean await) {
+    private Expression expression(Expression exprLhs, int minPrecedence, boolean in, boolean yield, boolean await, boolean pipeBody) {
         // Get the precedence of the next operator.
         int precedence = type.getPrecedence();
         Expression lhs = exprLhs;
-
+        boolean pipeParsed = false;
         // While greater precedence.
-        while (type.isOperator(in) && precedence >= minPrecedence) {
+        while (type.isOperator(in) && precedence >= minPrecedence || !pipeBody && type.isOperator(in)) {
             // Capture the operator token.
             final long op = token;
 
@@ -6293,7 +6311,14 @@ private Expression expression(Expression exprLhs, int minPrecedence, boolean in,
                 // Build up node.
                 lhs = new TernaryNode(op, lhs, new JoinPredecessorExpression(trueExpr), new JoinPredecessorExpression(falseExpr));
             } else {
+
                 final TokenType opType = type;
+
+                if (opType == PIPELINE) {
+                    pipeDepth++;
+                    pipeParsed = true;
+                }
+
                 // Skip operator.
                 next();
 
@@ -6311,11 +6336,23 @@ private Expression expression(Expression exprLhs, int minPrecedence, boolean in,
                 int nextPrecedence = type.getPrecedence();
 
                 // Subtask greater precedence.
-                while (type.isOperator(in) && (nextPrecedence > precedence || (nextPrecedence == precedence && !type.isLeftAssociative()))) {
-                    rhs = expression(rhs, nextPrecedence, in, yield, await);
+                while (type.isOperator(in) && (nextPrecedence > precedence || (nextPrecedence == precedence && !type.isLeftAssociative()))){//|| PipelineNode.isPipeline(type)) {
+                    rhs = expression(rhs, nextPrecedence, in, yield, await, pipeParsed);
                     nextPrecedence = type.getPrecedence();
                 }
-                lhs = newBinaryExpression(op, lhs, rhs);
+
+                if(opType == PIPELINE){
+                    if(!topicReferenceUsed){
+                        throw error("Pipe body must contain the topic reference token(%) at least once");
+                    }
+                    pipeDepth--;
+                    pipeParsed = false;
+                    topicReferenceUsed = false;
+                }
+
+                lhs = newBinaryExpression(op, lhs, rhs, pipeDepth + 1);
+
+
             }
 
             precedence = type.getPrecedence();
diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/TokenType.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/TokenType.java
index bb44b027cbb..f134332a484 100644
--- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/TokenType.java
+++ b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/TokenType.java
@@ -122,6 +122,7 @@ public enum TokenType {
     ASSIGN_BIT_OR  (BINARY,  "|=",    2, false),
     OR             (BINARY,  "||",    4, true),
     ASSIGN_OR      (BINARY,  "||=",   2, false, 12),
+    PIPELINE        (BINARY, "|>", 2, true),
     RBRACE         (BRACKET, "}"),
     BIT_NOT        (UNARY,   "~",    15, false),
     ELLIPSIS       (UNARY,   "..."),
diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/BinaryNode.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/BinaryNode.java
index 88cbcfdb9a5..dc2595864db 100644
--- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/BinaryNode.java
+++ b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/BinaryNode.java
@@ -48,7 +48,7 @@
 /**
  * BinaryNode nodes represent two operand operations.
  */
-public final class BinaryNode extends Expression implements Assignment {
+public class BinaryNode extends Expression implements Assignment {
     /** Left hand side argument. */
     private final Expression lhs;
 
diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/PipelineNode.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/PipelineNode.java
new file mode 100644
index 00000000000..b15575ca95a
--- /dev/null
+++ b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/PipelineNode.java
@@ -0,0 +1,17 @@
+package com.oracle.js.parser.ir;
+
+import com.oracle.js.parser.TokenType;
+
+public class PipelineNode extends BinaryNode{
+
+    private int level;
+
+    public PipelineNode(long token, Expression lhs, Expression rhs, int level) {
+        super(token, lhs, rhs);
+        this.level = level;
+    }
+
+    public static boolean isPipeline(final TokenType tokenType) {
+        return tokenType == TokenType.PIPELINE;
+    }
+}
diff --git a/graal-js/src/com.oracle.truffle.js.test/js/pipeline.js b/graal-js/src/com.oracle.truffle.js.test/js/pipeline.js
new file mode 100644
index 00000000000..33a20594ec7
--- /dev/null
+++ b/graal-js/src/com.oracle.truffle.js.test/js/pipeline.js
@@ -0,0 +1,87 @@
+/**
+ * Pipeline operator proposal.
+ */
+
+
+load('assert.js');
+
+function double(number){
+    return number * 2;
+}
+
+function add(number1, number2){
+    return number1 + number2;
+}
+
+function resolveAfter2Seconds(x) {
+  return new Promise((resolve) => {
+    setTimeout(() => {
+      resolve(x);
+    }, 2000);
+  });
+}
+
+class Rectangle {
+  constructor(height, width) {
+    this.height = height;
+    this.width = width;
+  }
+  // Getter
+  get area() {
+    return this.calcArea();
+  }
+  // Method
+  calcArea() {
+    return this.height * this.width;
+  }
+}
+
+const array = ['Apple', 'Orange', 'Strawberry'];
+
+const unaryFuncBody = 5 |> double(%);
+assertEqual(10, unaryFunc);
+
+const funcBody = double(3) |> add(%, 2);
+assertEqual(8, func);
+
+const methodPipeBody = new Rectangle(2, 3) |> %.calcArea();
+assertEqual(6, methodPipeBody);
+
+const arithmetic = (14 * 4) / 2 |> % + 1;
+assertEqual(29, arithmetic);
+
+const arrayLiteral = array.indexOf('Orange') |> array[%];
+assertEqual('Orange', arrayLiteral);
+
+const objectLiteral = 2 * 3 |> { type: "rectangle", area : %};
+assertEqual({type: "rectangle", area: 6}, objectLiteral);
+
+const templateLiteral = array[2] |> `${%}`;
+assertEqual('Strawberry', templateLiteral);
+
+const construction = (8/2) |> new Rectangle(2, %);
+assertEqual(new Rectangle(2, 4), construction);
+
+const awaiting = resolveAfter2Seconds(10) |> await %;
+assertEqual(10, awaiting);
+
+//yield
+
+//import
+
+/*
+* Test chaining of pipeline
+*/
+
+const chainingExample1 = 7 |> new Rectangle(6, %) |> %.calcArea();
+assertEqual(42, chainingExample1);
+
+/*
+* Error testing
+*/
+
+assertThrows(() => 15 |> 1 + 2, SyntaxError);
+assertThrows(() => new Rectangle(2, 3) |> %.squareFootage(), TypeError);
+
+
+

From 0724186b5e2fe0b92a5ce4c808a019703d4e907d Mon Sep 17 00:00:00 2001
From: Alexander Stummer 
Date: Tue, 11 Jul 2023 16:58:37 +0200
Subject: [PATCH 3/7] Desugaring of pipelines in Parser.

---
 .../src/com/oracle/js/parser/Parser.java      | 72 +++++++-------
 .../js/parser/ParserContextFunctionNode.java  | 15 +++
 .../com.oracle.truffle.js.test/js/pipeline.js | 97 ++++++++++++++-----
 3 files changed, 127 insertions(+), 57 deletions(-)

diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java
index 7eb5a8f7ff1..6c7d4b6121a 100644
--- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java
+++ b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java
@@ -81,6 +81,7 @@
 import static com.oracle.js.parser.TokenType.LBRACKET;
 import static com.oracle.js.parser.TokenType.LET;
 import static com.oracle.js.parser.TokenType.LPAREN;
+import static com.oracle.js.parser.TokenType.MOD;
 import static com.oracle.js.parser.TokenType.MUL;
 import static com.oracle.js.parser.TokenType.OF;
 import static com.oracle.js.parser.TokenType.PERIOD;
@@ -364,7 +365,7 @@ public class Parser extends AbstractParser {
 
     private boolean isModule;
 
-    private int pipeDepth = 0;
+    //private int pipeDepth = 0;
 
     private boolean topicReferenceUsed = false;
 
@@ -1122,17 +1123,14 @@ protected boolean enterDefault(Node node) {
         });
     }
 
-    private Expression newBinaryExpression(final long op, final Expression lhs, final Expression rhs, int level) {
+    private Expression newBinaryExpression(final long op, final Expression lhs, final Expression rhs) {
         final TokenType opType = Token.descType(op);
-
         // Build up node.
         if (BinaryNode.isLogical(opType)) {
             if (forbiddenNullishCoalescingUsage(opType, lhs, rhs)) {
                 throw error(String.format("nullish coalescing operator cannot immediately contain, or be contained within, an && or || operation"));
             }
             return new BinaryNode(op, new JoinPredecessorExpression(lhs), new JoinPredecessorExpression(rhs));
-        } else if (PipelineNode.isPipeline(opType)){
-            return new PipelineNode(op, lhs, rhs, level);
         }
         return new BinaryNode(op, lhs, rhs);
     }
@@ -3951,7 +3949,6 @@ private Expression primaryExpression(boolean yield, boolean await, CoverExpressi
         // Capture first token.
         final int primaryLine = line;
         final long primaryToken = token;
-
         switch (type) {
             case THIS: {
                 final TruffleString name = type.getNameTS();
@@ -4016,15 +4013,15 @@ private Expression primaryExpression(boolean yield, boolean await, CoverExpressi
                         TruffleString v8IntrinsicNameTS = lexer.stringIntern(v8IntrinsicName);
                         return createIdentNode(v8IntrinsicToken, ident.getFinish(), v8IntrinsicNameTS);
                     }
-                } else {
+                }else if(env.ecmaScriptVersion == 14){
                     next();
-
+                    int pipeDepth = lc.getCurrentFunction().getPipeDepth();
                     if(pipeDepth <= 0){
                         throw error(JSErrorType.SyntaxError, "The topic reference can not be used here!");
                     }
                     addIdentifierReference("%" + pipeDepth);
                     topicReferenceUsed = true;
-                    return new IdentNode(primaryToken, finish, lexer.stringIntern("%" + pipeDepth));
+                    return new IdentNode(Token.recast(token, IDENT), finish + 1, lexer.stringIntern("%" + pipeDepth));
                 }
 
             default:
@@ -6278,20 +6275,22 @@ private Expression expression(int minPrecedence, boolean in, boolean yield, bool
         } else {
             lhs = unaryExpression(yield, await, coverExpression);
         }
-        return expression(lhs, minPrecedence, in, yield, await, false);
+        if(type == MOD && lhs instanceof IdentNode && AWAIT.getName().equals(((IdentNode) lhs).getName())) {
+            return expression(lhs, MOD.getPrecedence() + 1, in, yield, await);
+        }
+        return expression(lhs, minPrecedence, in, yield, await);
     }
 
     private JoinPredecessorExpression joinPredecessorExpression(boolean yield, boolean await) {
         return new JoinPredecessorExpression(expression(yield, await));
     }
 
-    private Expression expression(Expression exprLhs, int minPrecedence, boolean in, boolean yield, boolean await, boolean pipeBody) {
+    private Expression expression(Expression exprLhs, int minPrecedence, boolean in, boolean yield, boolean await) {
         // Get the precedence of the next operator.
         int precedence = type.getPrecedence();
         Expression lhs = exprLhs;
-        boolean pipeParsed = false;
         // While greater precedence.
-        while (type.isOperator(in) && precedence >= minPrecedence || !pipeBody && type.isOperator(in)) {
+        while (type.isOperator(in) && precedence >= minPrecedence){
             // Capture the operator token.
             final long op = token;
 
@@ -6311,13 +6310,8 @@ private Expression expression(Expression exprLhs, int minPrecedence, boolean in,
                 // Build up node.
                 lhs = new TernaryNode(op, lhs, new JoinPredecessorExpression(trueExpr), new JoinPredecessorExpression(falseExpr));
             } else {
-
                 final TokenType opType = type;
 
-                if (opType == PIPELINE) {
-                    pipeDepth++;
-                    pipeParsed = true;
-                }
 
                 // Skip operator.
                 next();
@@ -6334,24 +6328,13 @@ private Expression expression(Expression exprLhs, int minPrecedence, boolean in,
 
                 // Get precedence of next operator.
                 int nextPrecedence = type.getPrecedence();
-
                 // Subtask greater precedence.
-                while (type.isOperator(in) && (nextPrecedence > precedence || (nextPrecedence == precedence && !type.isLeftAssociative()))){//|| PipelineNode.isPipeline(type)) {
-                    rhs = expression(rhs, nextPrecedence, in, yield, await, pipeParsed);
+                while (type.isOperator(in) && (nextPrecedence > precedence || (nextPrecedence == precedence && !type.isLeftAssociative()))){
+                    rhs = expression(rhs, nextPrecedence, in, yield, await);
                     nextPrecedence = type.getPrecedence();
                 }
 
-                if(opType == PIPELINE){
-                    if(!topicReferenceUsed){
-                        throw error("Pipe body must contain the topic reference token(%) at least once");
-                    }
-                    pipeDepth--;
-                    pipeParsed = false;
-                    topicReferenceUsed = false;
-                }
-
-                lhs = newBinaryExpression(op, lhs, rhs, pipeDepth + 1);
-
+                lhs = newBinaryExpression(op, lhs, rhs);
 
             }
 
@@ -6439,6 +6422,29 @@ private Expression assignmentExpression(boolean in, boolean yield, boolean await
                     popDefaultName();
                 }
             }
+        } else if(type == PIPELINE && isES2023()) {
+            boolean prevRef = topicReferenceUsed;
+            topicReferenceUsed = false;
+            lc.getCurrentFunction().increasePipeDepth();
+            int pipeDepth = lc.getCurrentFunction().getPipeDepth();
+
+            next();
+
+            Expression rhs = assignmentExpression(in, yield, await);
+            BinaryNode lhs = new BinaryNode(Token.recast(token, ASSIGN), new IdentNode(Token.recast(token, IDENT),
+                    finish + 1, lexer.stringIntern("%" + pipeDepth)), exprLhs);
+
+            if(!topicReferenceUsed){
+                throw error("Pipe body must contain the topic reference token(%) at least once");
+            }
+
+
+            lc.getCurrentFunction().decreasePipeDepth();
+
+            BinaryNode result = new BinaryNode(Token.recast(token, COMMARIGHT), lhs, rhs);
+            topicReferenceUsed = prevRef;
+
+            return result;
         } else {
             if (canBeAssignmentPattern) {
                 if (coverExpression != CoverExpressionError.DENY) {
@@ -6447,6 +6453,7 @@ private Expression assignmentExpression(boolean in, boolean yield, boolean await
                     verifyExpression(coverExprLhs);
                 }
             }
+
             return exprLhs;
         }
     }
@@ -6898,7 +6905,6 @@ private FunctionNode module(final String moduleName) {
         body.setFlag(Block.NEEDS_SCOPE);
         final Block programBody = new Block(functionToken, finish, body.getFlags() | Block.IS_SYNTHETIC | Block.IS_BODY | Block.IS_MODULE_BODY, body.getScope(), body.getStatements());
         script.setLastToken(token);
-
         expect(EOF);
 
         script.setModule(module.createModule());
diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ParserContextFunctionNode.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ParserContextFunctionNode.java
index ff0f28a557d..79c33952181 100644
--- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ParserContextFunctionNode.java
+++ b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ParserContextFunctionNode.java
@@ -110,6 +110,8 @@ class ParserContextFunctionNode extends ParserContextBaseNode {
     private List> hoistedVarDeclarations;
     private List> hoistableBlockFunctionDeclarations;
 
+    private int pipeDepth = 0;
+
     /**
      * @param token The token for the function
      * @param ident External function name
@@ -742,4 +744,17 @@ private static int calculateLength(final List parameters) {
         }
         return length;
     }
+    public int getPipeDepth(){
+        return pipeDepth;
+    }
+
+    public void increasePipeDepth(){
+        pipeDepth++;
+    }
+
+    public void decreasePipeDepth(){
+        if(pipeDepth > 0){
+            pipeDepth--;
+        }
+    }
 }
diff --git a/graal-js/src/com.oracle.truffle.js.test/js/pipeline.js b/graal-js/src/com.oracle.truffle.js.test/js/pipeline.js
index 33a20594ec7..d972f742a36 100644
--- a/graal-js/src/com.oracle.truffle.js.test/js/pipeline.js
+++ b/graal-js/src/com.oracle.truffle.js.test/js/pipeline.js
@@ -1,7 +1,11 @@
 /**
  * Pipeline operator proposal.
+ *
  */
 
+/**
+*@option --ecmascript-version=staging
+*/
 
 load('assert.js');
 
@@ -13,12 +17,10 @@ function add(number1, number2){
     return number1 + number2;
 }
 
-function resolveAfter2Seconds(x) {
-  return new Promise((resolve) => {
-    setTimeout(() => {
-      resolve(x);
-    }, 2000);
-  });
+function* foo() {
+    yield 1;
+    yield 2;
+    yield 3;
 }
 
 class Rectangle {
@@ -26,11 +28,11 @@ class Rectangle {
     this.height = height;
     this.width = width;
   }
-  // Getter
+
   get area() {
     return this.calcArea();
   }
-  // Method
+
   calcArea() {
     return this.height * this.width;
   }
@@ -38,34 +40,75 @@ class Rectangle {
 
 const array = ['Apple', 'Orange', 'Strawberry'];
 
-const unaryFuncBody = 5 |> double(%);
-assertEqual(10, unaryFunc);
+let unaryFuncBody = 5 |> double(%);
+assertEqual(10, unaryFuncBody);
 
-const funcBody = double(3) |> add(%, 2);
-assertEqual(8, func);
+let funcBody = double(3) |> add(%, 2);
+assertEqual(8, funcBody);
 
-const methodPipeBody = new Rectangle(2, 3) |> %.calcArea();
+let methodPipeBody = new Rectangle(2, 3) |> %.calcArea();
 assertEqual(6, methodPipeBody);
 
-const arithmetic = (14 * 4) / 2 |> % + 1;
+let arithmetic = (14 * 4) / 2 |> % + 1;
 assertEqual(29, arithmetic);
 
-const arrayLiteral = array.indexOf('Orange') |> array[%];
+let arrayLiteral = array.indexOf('Orange') |> array[%];
 assertEqual('Orange', arrayLiteral);
 
-const objectLiteral = 2 * 3 |> { type: "rectangle", area : %};
-assertEqual({type: "rectangle", area: 6}, objectLiteral);
+let arrayLiteral2 = 2 |> [1, %, 3];
+assertEqual(JSON.stringify([1, 2, 3]), JSON.stringify(arrayLiteral2));
+
+let objectLiteral = 2 * 3 |> { type: "rectangle", area : %};
+assertEqual(JSON.stringify({type: "rectangle", area: 6}), JSON.stringify(objectLiteral));
 
-const templateLiteral = array[2] |> `${%}`;
+let templateLiteral = array[2] |> `${%}`;
 assertEqual('Strawberry', templateLiteral);
 
-const construction = (8/2) |> new Rectangle(2, %);
-assertEqual(new Rectangle(2, 4), construction);
+let construction = (8/2) |> new Rectangle(2, %);
+assertEqual(JSON.stringify(new Rectangle(2, 4)), JSON.stringify(construction));
 
-const awaiting = resolveAfter2Seconds(10) |> await %;
-assertEqual(10, awaiting);
+//let awaiting = f() |> await %;
+//assertEqual("done!", awaiting);
+
+//let awaiting = 2 |> await f(%);
+function resolveAfter2Seconds(x) {
+  return new Promise((resolve) => {
+    setTimeout(() => {
+      resolve(x);
+    }, 2000);
+  });
+}
+
+async function f1() {
+  const x = 10 |> await resolveAfter2Seconds(%);
+  console.log(x);
+}
+
+f1();
 
 //yield
+function* counter(value) {
+   while (true) {
+     const step = value++ |> yield %;
+
+     if (step) {
+       value += step;
+     }
+   }
+}
+
+const generatorFunc = counter(0);
+assertEqual(0, generatorFunc.next().value);
+assertEqual(1, generatorFunc.next().value);
+assertEqual(2, generatorFunc.next().value);
+
+//function body
+let funcExpression = function test(value){
+  let var1 = 4 + value;
+  let var2 = 7 |> % * var1;
+  console.log("Result: " + var2);
+} |> %(2);
+
 
 //import
 
@@ -75,13 +118,19 @@ assertEqual(10, awaiting);
 
 const chainingExample1 = 7 |> new Rectangle(6, %) |> %.calcArea();
 assertEqual(42, chainingExample1);
+const chainingExample2 = 7 |> new Rectangle(6, %) |> %.calcArea() |> % % %;
+assertEqual(0, chainingExample2);
+const chainingExample3 = 7 |> new Rectangle(6, %) |> %.calcArea() |> % % 2 |> array[%];
+assertEqual('Apple', chainingExample3);
+const chainingExample4 = 7 |> new Rectangle(6, %) |> %.calcArea() |> % % 2 |> array[%] |> `${%}`;
+assertEqual('Apple', chainingExample4);
+const chainingExample5 = 7 |> new Rectangle(6, %) |> %.calcArea() |> % % 2 |> array[%] |> `${%}` |> array.indexOf(%);
+assertEqual(0, chainingExample5);
 
 /*
 * Error testing
 */
 
-assertThrows(() => 15 |> 1 + 2, SyntaxError);
 assertThrows(() => new Rectangle(2, 3) |> %.squareFootage(), TypeError);
 
 
-

From 598ac308c9025a194f0087deded0edddeb838a0e Mon Sep 17 00:00:00 2001
From: Alexander Stummer 
Date: Sat, 2 Sep 2023 11:09:53 +0200
Subject: [PATCH 4/7] Special case handling for Pipeline in strict mode

---
 .../src/com/oracle/js/parser/Parser.java            | 13 +++++++++----
 .../src/com.oracle.truffle.js.test/js/pipeline.js   | 13 -------------
 2 files changed, 9 insertions(+), 17 deletions(-)

diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java
index 6c7d4b6121a..5a34d6edb7f 100644
--- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java
+++ b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java
@@ -4014,11 +4014,11 @@ private Expression primaryExpression(boolean yield, boolean await, CoverExpressi
                         return createIdentNode(v8IntrinsicToken, ident.getFinish(), v8IntrinsicNameTS);
                     }
                 }else if(env.ecmaScriptVersion == 14){
-                    next();
                     int pipeDepth = lc.getCurrentFunction().getPipeDepth();
                     if(pipeDepth <= 0){
                         throw error(JSErrorType.SyntaxError, "The topic reference can not be used here!");
                     }
+                    next();
                     addIdentifierReference("%" + pipeDepth);
                     topicReferenceUsed = true;
                     return new IdentNode(Token.recast(token, IDENT), finish + 1, lexer.stringIntern("%" + pipeDepth));
@@ -6430,15 +6430,20 @@ private Expression assignmentExpression(boolean in, boolean yield, boolean await
 
             next();
 
+            IdentNode placeHolder = new IdentNode(Token.recast(token, IDENT),
+                    finish + 1, lexer.stringIntern("%" + pipeDepth));
+            BinaryNode lhs = new BinaryNode(Token.recast(token, ASSIGN), placeHolder, exprLhs);
             Expression rhs = assignmentExpression(in, yield, await);
-            BinaryNode lhs = new BinaryNode(Token.recast(token, ASSIGN), new IdentNode(Token.recast(token, IDENT),
-                    finish + 1, lexer.stringIntern("%" + pipeDepth)), exprLhs);
+
+            if(isStrictMode){
+                final VarNode var = new VarNode(line, Token.recast(token, LET), placeHolder.getFinish(), placeHolder.setIsDeclaredHere(), null);
+                declareVar(lc.getCurrentScope(), var);
+            }
 
             if(!topicReferenceUsed){
                 throw error("Pipe body must contain the topic reference token(%) at least once");
             }
 
-
             lc.getCurrentFunction().decreasePipeDepth();
 
             BinaryNode result = new BinaryNode(Token.recast(token, COMMARIGHT), lhs, rhs);
diff --git a/graal-js/src/com.oracle.truffle.js.test/js/pipeline.js b/graal-js/src/com.oracle.truffle.js.test/js/pipeline.js
index d972f742a36..b12bab3679b 100644
--- a/graal-js/src/com.oracle.truffle.js.test/js/pipeline.js
+++ b/graal-js/src/com.oracle.truffle.js.test/js/pipeline.js
@@ -17,12 +17,6 @@ function add(number1, number2){
     return number1 + number2;
 }
 
-function* foo() {
-    yield 1;
-    yield 2;
-    yield 3;
-}
-
 class Rectangle {
   constructor(height, width) {
     this.height = height;
@@ -67,10 +61,6 @@ assertEqual('Strawberry', templateLiteral);
 let construction = (8/2) |> new Rectangle(2, %);
 assertEqual(JSON.stringify(new Rectangle(2, 4)), JSON.stringify(construction));
 
-//let awaiting = f() |> await %;
-//assertEqual("done!", awaiting);
-
-//let awaiting = 2 |> await f(%);
 function resolveAfter2Seconds(x) {
   return new Promise((resolve) => {
     setTimeout(() => {
@@ -109,9 +99,6 @@ let funcExpression = function test(value){
   console.log("Result: " + var2);
 } |> %(2);
 
-
-//import
-
 /*
 * Test chaining of pipeline
 */

From a787c182b31b0a842711e33e7849b6170bef6632 Mon Sep 17 00:00:00 2001
From: Alexander Stummer 
Date: Sat, 2 Sep 2023 19:43:04 +0200
Subject: [PATCH 5/7] Removed comment

---
 .../com.oracle.js.parser/src/com/oracle/js/parser/Parser.java   | 2 --
 1 file changed, 2 deletions(-)

diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java
index 5a34d6edb7f..0f6fa5f40a9 100644
--- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java
+++ b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java
@@ -365,8 +365,6 @@ public class Parser extends AbstractParser {
 
     private boolean isModule;
 
-    //private int pipeDepth = 0;
-
     private boolean topicReferenceUsed = false;
 
     /**

From f177a563013edf31535a21a3e8cdc66c8cb59596 Mon Sep 17 00:00:00 2001
From: Alexander Stummer 
Date: Sat, 2 Sep 2023 20:37:34 +0200
Subject: [PATCH 6/7] Changed if condition for topic reference parsing

---
 .../com.oracle.js.parser/src/com/oracle/js/parser/Parser.java   | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java
index 1ecafba4f59..d5131df233c 100644
--- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java
+++ b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java
@@ -4035,7 +4035,7 @@ private Expression primaryExpression(boolean yield, boolean await, CoverExpressi
                         TruffleString v8IntrinsicNameTS = lexer.stringIntern(v8IntrinsicName);
                         return createIdentNode(v8IntrinsicToken, ident.getFinish(), v8IntrinsicNameTS);
                     }
-                }else if(env.ecmaScriptVersion == 14){
+                }else if(isES2023()){
                     int pipeDepth = lc.getCurrentFunction().getPipeDepth();
                     if(pipeDepth <= 0){
                         throw error(JSErrorType.SyntaxError, "The topic reference can not be used here!");

From ee66c88e981dec4d9c49e4068e812ff17b4a9712 Mon Sep 17 00:00:00 2001
From: Alexander Stummer 
Date: Thu, 14 Sep 2023 17:30:02 +0200
Subject: [PATCH 7/7] Removed previously used code

---
 .../src/com/oracle/js/parser/Parser.java        | 16 ++++++----------
 .../src/com/oracle/js/parser/ir/BinaryNode.java |  2 +-
 .../com/oracle/js/parser/ir/PipelineNode.java   | 17 -----------------
 3 files changed, 7 insertions(+), 28 deletions(-)
 delete mode 100644 graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/PipelineNode.java

diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java
index d5131df233c..d852cd54804 100644
--- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java
+++ b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java
@@ -119,7 +119,6 @@
 import java.util.Map;
 import java.util.function.Consumer;
 
-import com.oracle.js.parser.ir.PipelineNode;
 import org.graalvm.collections.Pair;
 
 import com.oracle.js.parser.ir.AccessNode;
@@ -1117,6 +1116,7 @@ protected boolean enterDefault(Node node) {
 
     private Expression newBinaryExpression(final long op, final Expression lhs, final Expression rhs) {
         final TokenType opType = Token.descType(op);
+
         // Build up node.
         if (BinaryNode.isLogical(opType)) {
             if (forbiddenNullishCoalescingUsage(opType, lhs, rhs)) {
@@ -3971,6 +3971,7 @@ private Expression primaryExpression(boolean yield, boolean await, CoverExpressi
         // Capture first token.
         final int primaryLine = line;
         final long primaryToken = token;
+
         switch (type) {
             case THIS: {
                 final TruffleString name = type.getNameTS();
@@ -6303,9 +6304,6 @@ private Expression expression(int minPrecedence, boolean in, boolean yield, bool
         } else {
             lhs = unaryExpression(yield, await, coverExpression);
         }
-        if(type == MOD && lhs instanceof IdentNode && AWAIT.getName().equals(((IdentNode) lhs).getName())) {
-            return expression(lhs, MOD.getPrecedence() + 1, in, yield, await);
-        }
         return expression(lhs, minPrecedence, in, yield, await);
     }
 
@@ -6317,8 +6315,9 @@ private Expression expression(Expression exprLhs, int minPrecedence, boolean in,
         // Get the precedence of the next operator.
         int precedence = type.getPrecedence();
         Expression lhs = exprLhs;
+
         // While greater precedence.
-        while (type.isOperator(in) && precedence >= minPrecedence){
+        while (type.isOperator(in) && precedence >= minPrecedence) {
             // Capture the operator token.
             final long op = token;
 
@@ -6339,8 +6338,6 @@ private Expression expression(Expression exprLhs, int minPrecedence, boolean in,
                 lhs = new TernaryNode(op, lhs, new JoinPredecessorExpression(trueExpr), new JoinPredecessorExpression(falseExpr));
             } else {
                 final TokenType opType = type;
-
-
                 // Skip operator.
                 next();
 
@@ -6356,14 +6353,13 @@ private Expression expression(Expression exprLhs, int minPrecedence, boolean in,
 
                 // Get precedence of next operator.
                 int nextPrecedence = type.getPrecedence();
+
                 // Subtask greater precedence.
                 while (type.isOperator(in) && (nextPrecedence > precedence || (nextPrecedence == precedence && !type.isLeftAssociative()))){
                     rhs = expression(rhs, nextPrecedence, in, yield, await);
                     nextPrecedence = type.getPrecedence();
                 }
-
                 lhs = newBinaryExpression(op, lhs, rhs);
-
             }
 
             precedence = type.getPrecedence();
@@ -6486,7 +6482,6 @@ private Expression assignmentExpression(boolean in, boolean yield, boolean await
                     verifyExpression(coverExprLhs);
                 }
             }
-
             return exprLhs;
         }
     }
@@ -6939,6 +6934,7 @@ private FunctionNode module(final String moduleName) {
         body.setFlag(Block.NEEDS_SCOPE);
         final Block programBody = new Block(functionToken, finish, body.getFlags() | Block.IS_SYNTHETIC | Block.IS_BODY | Block.IS_MODULE_BODY, body.getScope(), body.getStatements());
         script.setLastToken(token);
+
         expect(EOF);
 
         script.setModule(module.createModule());
diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/BinaryNode.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/BinaryNode.java
index dc2595864db..88cbcfdb9a5 100644
--- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/BinaryNode.java
+++ b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/BinaryNode.java
@@ -48,7 +48,7 @@
 /**
  * BinaryNode nodes represent two operand operations.
  */
-public class BinaryNode extends Expression implements Assignment {
+public final class BinaryNode extends Expression implements Assignment {
     /** Left hand side argument. */
     private final Expression lhs;
 
diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/PipelineNode.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/PipelineNode.java
deleted file mode 100644
index b15575ca95a..00000000000
--- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/PipelineNode.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.oracle.js.parser.ir;
-
-import com.oracle.js.parser.TokenType;
-
-public class PipelineNode extends BinaryNode{
-
-    private int level;
-
-    public PipelineNode(long token, Expression lhs, Expression rhs, int level) {
-        super(token, lhs, rhs);
-        this.level = level;
-    }
-
-    public static boolean isPipeline(final TokenType tokenType) {
-        return tokenType == TokenType.PIPELINE;
-    }
-}