From ca03c8fe4c60e8a364545311341688ebbe63dbe2 Mon Sep 17 00:00:00 2001
From: PEDERSEN Ny Aina <ny-aina.a.pedersen@inria.fr>
Date: Thu, 19 May 2022 13:54:12 +0200
Subject: [PATCH] Add documentation for the metadata syntax

---
 lib/level/level.py | 27 ++++++++++---------
 lib/level/utils.py | 66 +++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 79 insertions(+), 14 deletions(-)

diff --git a/lib/level/level.py b/lib/level/level.py
index ba61fb46..bef4756f 100644
--- a/lib/level/level.py
+++ b/lib/level/level.py
@@ -121,21 +121,21 @@ class AbstractLevel(ABC):
         else: # Unknown direction
             return '?'
 
-    def update_vars(self):
+    def update_global_variables(self):
         """
-        Update the variables.
+        Update the global variables.
 
         :return: The list of the variables that have changed.
         """
-        global_variables = self.tracker.get_global_variables(
-                                            as_raw_python_objects=True)
+        globs = self.tracker.get_global_variables(
+                            as_raw_python_objects=True)
 
         updated_vars = []
-        for var in self.vars.keys():
-            if var in global_variables:
-                if self.vars[var] != global_variables[var].value:
-                    self.vars[var] = global_variables[var].value
-                    updated_vars.append(var)
+        for var_name, var in globs.items():
+            if (var_name not in self.vars
+                or var.value != self.vars[var_name]):
+                    self.vars[var_name] = var.value
+                    updated_vars.append(var_name)
 
         return updated_vars
 
@@ -226,7 +226,8 @@ class LevelText(AbstractLevel):
         # Adding the target
         exit_x = self.vars['exit_x']
         exit_y = self.vars['exit_y']
-        middle_lines[exit_y][exit_x+1] = "@"
+        if exit_x and exit_y: # FIXME fetch the exits
+            middle_lines[exit_y][exit_x+1] = "@"
 
         # Adding the player
         player_x = self.vars['player_x']
@@ -265,7 +266,7 @@ class LevelText(AbstractLevel):
 
         while self.tracker.get_pause_reason().type != PauseReasonType.EXITED:
             self.show_next_line()
-            self.update_vars()
+            self.update_global_variables()
             self.show_map()
             self.print_wowm_msg()
             cmd = self.read_cmd()
@@ -422,7 +423,7 @@ class LevelCurses(AbstractLevel):
 
             while self.tracker.get_pause_reason().type != PauseReasonType.EXITED:
                 self.show_next_line()
-                self.update_vars()
+                self.update_global_variables()
 
                 self.show_map(stdscr, pad)
                 self.print_wowm_msg(stdscr)
@@ -478,7 +479,7 @@ class LevelArcade(AbstractLevel):
 
         while self.tracker.get_pause_reason().type != PauseReasonType.EXITED:
             self.show_next_line()
-            self.update_vars()
+            self.update_global_variables()
             self.update_map()
 #           self.print_wowm_msg() # TODO implement this
             cmd = self.read_cmd()
diff --git a/lib/level/utils.py b/lib/level/utils.py
index a6ed8fbe..7bf82b8c 100755
--- a/lib/level/utils.py
+++ b/lib/level/utils.py
@@ -1,6 +1,64 @@
 #!/usr/bin/env python3
 
-"""Conversion and parsing utils."""
+"""
+Conversion and parsing utils.
+
+# C commment parsing.
+
+C like block comments (/* ... */) or inline comments (// ...) that
+starts with the tag @AGDB are recognized.
+
+Key are case insensitive.
+Keys that are not defined here will still
+be added to the dictionnary of metadata (as strings).
+
+- Mandatory strings:
+    - program_name (name of the binary that will be loaded)
+    e.g: // @AGDB program_name: main
+    - map_width
+    e.g: // @AGDB map_height: 8
+    - map_height
+    - player_x
+    - player_y
+    - player_direction
+
+- Mandatory lists:
+    - available_commands (list of available gdb commands)
+    e.g: // @AGDB available_commands: next step edit
+
+- Non-mandatory strings:
+    - level_name
+    e.g: // @AGDB TAG tag1 tag2
+    - level_number
+    - hintXXX (XXX to be filled)
+    - bug
+
+- Non-mandatory lists:
+    - tag
+    e.g: // @AGDB TAG tag1 tag2
+    - tags
+    e.g: // @AGDB TAGS tag1 tag2
+
+- WOWM (wise old women/men) syntax. xxx represents the WOWM's identifier.
+    - message condition:
+        WOWMxxx: message_conditions COND
+        e.g: - // @AGDB WOWMxxx: message_conditions  player_x == 5 and player_y
+             - // @AGDB WOWMxxx: message_conditions  near
+    - visibility condition:
+        WOWMxxx: visibility_conditions COND
+        e.g: - // @AGB WOWMxxx: visibility_conditions  player_x == 5 and player_y
+             - // @AGB WOWMxxx: visibility_conditions  near
+    - messages:
+        WOWMxxx: message MESSAGE
+        e.g: /* @AGDB
+              * WOWMxxx: message First line here
+              * WOWMxxx: message Second line here
+              * WOWMxxx: message and so on...
+              */
+    - position
+        WOWMxxx: position X_pos Y_pos
+        e.g: - // @AGDB WOWMxxx: position 8 5
+"""
 
 import re
 import json
@@ -198,6 +256,12 @@ def generate_dict(file):
         else:
             metadata[head] = tail
 
+    # Adding default values.
+    # I do it at the end because the type checker screams when
+    # I overwrite a None value to someting else
+    metadata["vars"] = defaultdict(lambda: None, metadata["vars"])
+    metadata["wowms"] = defaultdict(lambda: None, metadata["wowms"])
+
     return defaultdict(lambda: None, metadata)
 
 
-- 
GitLab