Repository: edgedb/edgedb

Issue:
Allow trailing comma for function parameters



Discussion:

Resolving patch:
diff --git a/edb/edgeql/parser/grammar/commondl.py b/edb/edgeql/parser/grammar/commondl.py
--- a/edb/edgeql/parser/grammar/commondl.py
+++ b/edb/edgeql/parser/grammar/commondl.py
@@ -216,11 +216,19 @@ class FuncDeclArgList(ListNonterm, element=FuncDeclArg,
     pass
 
 
+class FuncDeclArgs(Nonterm):
+    def reduce_FuncDeclArgList_COMMA(self, *kids):
+        self.val = kids[0].val
+
+    def reduce_FuncDeclArgList(self, *kids):
+        self.val = kids[0].val
+
+
 class CreateFunctionArgs(Nonterm):
     def reduce_LPAREN_RPAREN(self, *kids):
         self.val = []
 
-    def reduce_LPAREN_FuncDeclArgList_RPAREN(self, *kids):
+    def reduce_LPAREN_FuncDeclArgs_RPAREN(self, *kids):
         args = kids[1].val
 
         last_pos_default_arg = None
diff --git a/edb/edgeql/parser/grammar/expressions.py b/edb/edgeql/parser/grammar/expressions.py
--- a/edb/edgeql/parser/grammar/expressions.py
+++ b/edb/edgeql/parser/grammar/expressions.py
@@ -1278,6 +1278,9 @@ class FuncArgList(ListNonterm, element=FuncCallArg, separator=tokens.T_COMMA):
 
 
 class OptFuncArgList(Nonterm):
+    def reduce_FuncArgList_COMMA(self, *kids):
+        self.val = kids[0].val
+
     def reduce_FuncArgList(self, *kids):
         self.val = kids[0].val
 


Test patch:
diff --git a/tests/test_edgeql_syntax.py b/tests/test_edgeql_syntax.py
--- a/tests/test_edgeql_syntax.py
+++ b/tests/test_edgeql_syntax.py
@@ -2795,6 +2795,21 @@ def test_edgeql_syntax_function_08(self):
         SELECT count(1, $a := 1);
         """
 
+    def test_edgeql_syntax_function_09(self):
+        """
+        SELECT bar(User.name,);
+        SELECT baz(User.name, User.age,);
+        SELECT str_lower(string := User.name,);
+        SELECT baz(age := User.age, of := User.name, `select` := 1,);
+
+% OK %
+
+        SELECT bar(User.name);
+        SELECT baz(User.name, User.age);
+        SELECT str_lower(string := User.name);
+        SELECT baz(age := User.age, of := User.name, `select` := 1);
+        """
+
     def test_edgeql_syntax_tuple_01(self):
         """
         SELECT ('foo', 42).0;
@@ -3676,6 +3691,68 @@ def test_edgeql_syntax_ddl_function_48(self):
             std::int64 USING SQL FUNCTION 'aaa';
         """
 
+    def test_edgeql_syntax_ddl_function_49(self):
+        """
+        CREATE FUNCTION std::strlen(string: std::str,) -> std::int64
+            USING SQL FUNCTION 'strlen';
+
+% OK %
+
+        CREATE FUNCTION std::strlen(string: std::str) -> std::int64
+            USING SQL FUNCTION 'strlen';
+        """
+
+    def test_edgeql_syntax_ddl_function_50(self):
+        """
+        CREATE FUNCTION std::strlen(string: std::str = '1',)
+            -> std::int64
+            USING SQL FUNCTION 'strlen';
+
+% OK %
+
+        CREATE FUNCTION std::strlen(string: std::str = '1')
+            -> std::int64
+            USING SQL FUNCTION 'strlen';
+        """
+
+    def test_edgeql_syntax_ddl_function_51(self):
+        """
+        CREATE FUNCTION std::strlen(
+            a: std::str = '1',
+            VARIADIC b: std::str,
+        ) -> std::int64
+            USING SQL FUNCTION 'strlen';
+
+% OK %
+
+        CREATE FUNCTION std::strlen(
+            a: std::str = '1',
+            VARIADIC b: std::str
+        ) -> std::int64
+            USING SQL FUNCTION 'strlen';
+        """
+
+    def test_edgeql_syntax_ddl_function_52(self):
+        """
+        CREATE FUNCTION foo(
+            a: OPTIONAL std::str,
+            NAMED ONLY b: OPTIONAL std::str,
+            NAMED ONLY c: OPTIONAL std::str = '1',
+            NAMED ONLY d: OPTIONAL std::str,
+        ) ->
+            std::int64 USING SQL FUNCTION 'aaa';
+
+% OK %
+
+        CREATE FUNCTION foo(
+            a: OPTIONAL std::str,
+            NAMED ONLY b: OPTIONAL std::str,
+            NAMED ONLY c: OPTIONAL std::str = '1',
+            NAMED ONLY d: OPTIONAL std::str
+        ) ->
+            std::int64 USING SQL FUNCTION 'aaa';
+        """
+
     def test_edgeql_syntax_ddl_operator_01(self):
         """
         CREATE INFIX OPERATOR