Repository: effekt-lang/effekt (scala)

Issue:
Allow trailing commas in list literals
```scala
val foo = [ 
  1,
  2,
]
```
should be parseable and not cause a crash in the parser :)

The parser code is here:
https://github.com/effekt-lang/effekt/blob/a9827f5e76522a116802d356b3d8b5d129fa3b5b/effekt/shared/src/main/scala/effekt/RecursiveDescent.scala#L990-L996

... and it uses `many` which is a nice candidate for the change (maybe with `manyTrailing` to begin with?) ...
https://github.com/effekt-lang/effekt/blob/a9827f5e76522a116802d356b3d8b5d129fa3b5b/effekt/shared/src/main/scala/effekt/RecursiveDescent.scala#L1394-L1408

... then feel free to add a few tests for the new behaviour in [`RecursiveDescentTests.scala`](https://github.com/effekt-lang/effekt/blob/master/effekt/jvm/src/test/scala/effekt/RecursiveDescentTests.scala) :)

Pull request description:
Fixes #873

Patch:
diff --git a/effekt/shared/src/main/scala/effekt/RecursiveDescent.scala b/effekt/shared/src/main/scala/effekt/RecursiveDescent.scala
index 9db4032b3..54bf81924 100644
--- a/effekt/shared/src/main/scala/effekt/RecursiveDescent.scala
+++ b/effekt/shared/src/main/scala/effekt/RecursiveDescent.scala
@@ -993,7 +993,7 @@ class RecursiveDescent(positions: Positions, tokens: Seq[Token], source: Source)
   }
   def listLiteral(): Term =
     nonterminal:
-      many(expr, `[`, `,`, `]`).foldRight(NilTree) { ConsTree }
+      manyTrailing(expr, `[`, `,`, `]`).foldRight(NilTree) { ConsTree }
 
   private def NilTree: Term =
     Call(IdTarget(IdRef(List(), "Nil")), Nil, Nil, Nil)
@@ -1407,6 +1407,29 @@ class RecursiveDescent(positions: Positions, tokens: Seq[Token], source: Source)
       components.toList
     }
 
+  inline def manyTrailing[T](p: () => T, before: TokenKind, sep: TokenKind, after: TokenKind): List[T] =
+    consume(before)
+    if (peek(after)) {
+      consume(after)
+      Nil
+    } else if (peek(sep)) {
+      consume(sep)
+      consume(after)
+      Nil
+    } else {
+      val components: ListBuffer[T] = ListBuffer.empty
+      components += p()
+      while (peek(sep)) {
+        consume(sep)
+
+        if (!peek(after)) {
+          components += p()
+        }
+      }
+      consume(after)
+      components.toList
+    }
+
 
   // Positions
 


Test patch:
diff --git a/effekt/jvm/src/test/scala/effekt/RecursiveDescentTests.scala b/effekt/jvm/src/test/scala/effekt/RecursiveDescentTests.scala
index 5bfb2f798..44731886a 100644
--- a/effekt/jvm/src/test/scala/effekt/RecursiveDescentTests.scala
+++ b/effekt/jvm/src/test/scala/effekt/RecursiveDescentTests.scala
@@ -125,6 +125,12 @@ class RecursiveDescentTests extends munit.FunSuite {
     parseExpr("fun() { foo(()) }")
 
     parseExpr("10.seconds")
+
+    parseExpr("[1,2,3]")
+    parseExpr("[3,2,1,]")
+    parseExpr("[]")
+    parseExpr("[,]")
+    intercept[Throwable] { parseExpr("[,1]") }
   }
 
   test("Boxing") {