Repository: nanonyme/simplecpreprocessor

Issue:
Macro expansion produces produces wrong results
See for details https://github.com/nanonyme/simplecpreprocessor/commit/c3a1d4617fa0977bbc0f6bd0098b2d74219489bf

Discussion:

Patch:
diff --git a/simplecpreprocessor.py b/simplecpreprocessor.py
index d6d025b..53da5fb 100644
--- a/simplecpreprocessor.py
+++ b/simplecpreprocessor.py
@@ -104,6 +104,7 @@ IFDEF = "ifdef"
 IFNDEF = "ifndef"
 ELSE = "else"
 SKIP_FILE = object()
+TOKEN = re.compile(r"\b\w+\b")
 
 
 class Preprocessor(object):
@@ -228,27 +229,22 @@ class Preprocessor(object):
             self.process_define(define, old_line_num)
 
     def process_source_line(self, line, line_num):
-        matches = set()
-        line = self._recursive_transform(line, matches)
+        line = self._recursive_transform(line, set())
         return line + self.line_ending
 
-    def _recursive_transform(self, line, matches):
-        original_line = line
-        new_matches = set()
+    def _recursive_transform(self, line, seen):
 
         def transform_word(match):
             word = match.group(0)
-            if word in matches:
+            if word in seen:
                 return word
             else:
-                new_matches.add(word)
-                return self.defines.get(word, word)
-        line = re.sub(r"\b\w+\b", transform_word, line)
-        matches.update(new_matches)
-        if original_line == line:
-            return line
-        else:
-            return self._recursive_transform(line, matches)
+                local_seen = {word}
+                local_seen.update(seen)
+                word = self.defines.get(word, word)
+                return self._recursive_transform(word, local_seen)
+
+        return TOKEN.sub(transform_word, line)
 
     def skip_file(self, name):
         item = self.include_once.get(name)


Test patch:
diff --git a/test_simplecpreprocessor.py b/test_simplecpreprocessor.py
index 71ae36d..8a4f33b 100644
--- a/test_simplecpreprocessor.py
+++ b/test_simplecpreprocessor.py
@@ -97,6 +97,14 @@ class TestSimpleCPreprocessor(ProfilerMixin, unittest.TestCase):
         expected_list = ["(4 + (2 * x))\n", "(2 * (4 + y))\n"]
         self.run_case(f_obj, expected_list)
 
+    def test_define_indirect_self_reference_multiple(self):
+        f_obj = FakeFile("header.h", ["#define I 1\n",
+                                      "#define J I + 2\n",
+                                      "#define K I + J\n",
+                                      "I\n", "J\n", "K\n"])
+        expected_list = ["1\n", "1 + 2\n", "1 + 1 + 2\n"]
+        self.run_case(f_obj, expected_list)
+
     def test_partial_match(self):
         f_obj = FakeFile("header.h", [
             "#define FOO\n",