DEV Community

Hercules Lemke Merscher
Hercules Lemke Merscher

Posted on • Originally published at bitmaybewise.substack.com

Tsonnet #41 - Call me maybe, but make it argless

Welcome to the Tsonnet series!

If you're not following along, check out how it all started in the first post of the series.

In the previous post, we wrapped up function support with named parameters at call sites:

Oops, I forgot function calls without arguments.

Classic. I left them home alone.

Kevin home alone

What must be validated

Here's what we need to handle:

local greet() = 'hello';
local make_obj() = { x: 1, y: 2 };
local apply(f) = f();
local obj = { m(): 7 };

{
  greet: greet(),
  obj: make_obj(),
  inline: (function() 42)(),
  applied: apply(function() 'world'),
  method_call: obj.m(),
}
Enter fullscreen mode Exit fullscreen mode

Parsing

The fix is very straightforward. The only change required is substituting separated_nonempty_list by separated_list:

diff --git a/lib/parser.mly b/lib/parser.mly
index 94f1a2f..781ec5d 100644
--- a/lib/parser.mly
+++ b/lib/parser.mly
@@ -102,7 +102,7 @@ obj_key:
 obj_field:
   | k = obj_key; COLON; e = assignable_expr { ObjectField (k, e) }
   | k = obj_key;
-    LEFT_PAREN; params = separated_nonempty_list(COMMA, fundef_param); RIGHT_PAREN;
+    LEFT_PAREN; params = separated_list(COMMA, fundef_param); RIGHT_PAREN;
     COLON; body = assignable_expr
     { ObjectField (
         k,
@@ -201,7 +201,7 @@ fundef_param:

 fundef:
   | fname = ID;
-    LEFT_PAREN; params = separated_nonempty_list(COMMA, fundef_param); RIGHT_PAREN;
+    LEFT_PAREN; params = separated_list(COMMA, fundef_param); RIGHT_PAREN;
     ASSIGN;
     body = fundef_body { { name = fname; params = params; body = body } }
   ;
@@ -218,7 +218,7 @@ funcall_arg:

 funcall:
   | fname = ID;
-    LEFT_PAREN; params = separated_nonempty_list(COMMA, funcall_arg); RIGHT_PAREN
+    LEFT_PAREN; params = separated_list(COMMA, funcall_arg); RIGHT_PAREN
     { FunctionCall
       (with_pos $startpos $endpos, {
         callee = Ident (with_pos $startpos(fname) $endpos(fname), fname);
@@ -226,16 +226,16 @@ funcall:
       })
     }
   | callee = scoped_expr;
-    LEFT_PAREN; params = separated_nonempty_list(COMMA, funcall_arg); RIGHT_PAREN
+    LEFT_PAREN; params = separated_list(COMMA, funcall_arg); RIGHT_PAREN
     { FunctionCall (with_pos $startpos $endpos, { callee = callee; args = params }) }
   | callee = obj_field_access;
-    LEFT_PAREN; params = separated_nonempty_list(COMMA, funcall_arg); RIGHT_PAREN
+    LEFT_PAREN; params = separated_list(COMMA, funcall_arg); RIGHT_PAREN
     { FunctionCall (with_pos $startpos $endpos, { callee = callee; args = params }) }
   ;

 closure:
   | FUNCTION;
-    LEFT_PAREN; params = separated_nonempty_list(COMMA, fundef_param); RIGHT_PAREN;
+    LEFT_PAREN; params = separated_list(COMMA, fundef_param); RIGHT_PAREN;
     body = assignable_expr {
       Closure (with_pos $startpos $endpos, { params = params; body = body })
     }
Enter fullscreen mode Exit fullscreen mode

Every place we parse parameter or argument lists gets the same treatment: function definitions, object method definitions, function calls, and closures. Swap nonempty out, and zero-argument calls stop crashing the parser.

How could I forget this one? XD

Testing

A new sample and a cram test entry:

diff --git a/test/cram/functions.t b/test/cram/functions.t
index 89cfd27..44f7d44 100644
--- a/test/cram/functions.t
+++ b/test/cram/functions.t
@@ -15,3 +15,12 @@

   $ tsonnet ../../samples/functions/method.jsonnet
   4
+
+  $ tsonnet ../../samples/functions/no_args.jsonnet
+  {
+    "applied": "world",
+    "greet": "hello",
+    "inline": 42,
+    "method_call": 7,
+    "obj": { "x": 1, "y": 2 }
+  }
Enter fullscreen mode Exit fullscreen mode

Zero arguments, zero drama.

Conclusion

Short one, but a necessary one. No-argument function calls were quietly broken, and the fix turned out to be a one-word change per grammar rule. Easy to overlook, easy to fix once you notice.

Next up: conditionals. The Jsonnet tutorial can't wait forever.

The entire diff can be seen here.


Thanks for reading Bit Maybe Wise! Left no-arg calls home alone. Subscribe so you don't miss when conditionals finally move in.

Photo from https://www.businessinsider.com/photos-show-inside-real-life-home-alone-house-chicago-illinois-2020-12

Top comments (0)