From d69d793beae0f5b9c340d199eed414fb2ab71817 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= <hugo@lysator.liu.se>
Date: Tue, 19 Sep 2023 16:49:56 +0200
Subject: [PATCH] Handles `unless {} else {}`

---
 muppet/puppet/ast.py           | 11 ++++++++---
 muppet/puppet/format/parser.py |  7 +++++--
 tests/test_parse_elsif.py      | 13 +++++++++++++
 3 files changed, 26 insertions(+), 5 deletions(-)

diff --git a/muppet/puppet/ast.py b/muppet/puppet/ast.py
index a8baa1a..028751d 100644
--- a/muppet/puppet/ast.py
+++ b/muppet/puppet/ast.py
@@ -213,6 +213,7 @@ class PuppetUnless(Puppet):
 
     condition: Puppet
     consequent: list[Puppet]
+    alternative: list[Puppet] = field(default_factory=list)
 
 
 @dataclass
@@ -679,10 +680,14 @@ def build_ast(form: Any) -> Puppet:
 
             return PuppetIfChain(clauses)
 
+        case ['unless', {'test': test, 'then': forms, 'else': else_}]:
+            return PuppetUnless(build_ast(test),
+                                [build_ast(x) for x in forms],
+                                [build_ast(x) for x in else_])
+
         case ['unless', {'test': test, 'then': forms}]:
-            return PuppetUnless(build_ast(test), [build_ast(x) for x in forms])
-        case ['unless', {'test': test}]:
-            return PuppetUnless(build_ast(test), [])
+            return PuppetUnless(build_ast(test),
+                                [build_ast(x) for x in forms])
 
         case ['invoke', {'functor': func, 'args': args, 'block': block}]:
             return PuppetInvoke(build_ast(func),
diff --git a/muppet/puppet/format/parser.py b/muppet/puppet/format/parser.py
index ccb59f2..828e03b 100644
--- a/muppet/puppet/format/parser.py
+++ b/muppet/puppet/format/parser.py
@@ -634,8 +634,11 @@ class ParserFormatter(Serializer[ParseDirective]):
 
     @override
     def _puppet_unless(self, it: PuppetUnless) -> ParseDirective:
-        return (ws & 'unless' & ws & self.s(it.condition) & ws & '{' &
-                ws & self.s(it.consequent) & ws & '}')
+        parser = (ws & 'unless' & ws & self.s(it.condition) & ws & '{' &
+                  ws & self.s(it.consequent) & ws & '}')
+        parser &= optional(ws & 'else' & ws & '{' & ws & self.s(it.alternative) &
+                           ws & '}')
+        return parser
 
     @override
     def _puppet_var(self, it: PuppetVar) -> ParseDirective:
diff --git a/tests/test_parse_elsif.py b/tests/test_parse_elsif.py
index 1bcf43d..0226415 100644
--- a/tests/test_parse_elsif.py
+++ b/tests/test_parse_elsif.py
@@ -197,3 +197,16 @@ def test_collect_nested():
         }
     }
     """)
+
+
+def test_unless():
+    # Outer if to force unless to parse correctly
+    parse_string("""
+    if true {
+        unless 1 {
+            2
+        } else {
+            3
+        }
+    }
+    """)
-- 
GitLab