Browse Source

simple preprocesor

pixelbath 3 weeks ago
parent
commit
c41cd0a1b1
3 changed files with 144 additions and 0 deletions
  1. 5 0
      pre-testinclude.lua
  2. 47 0
      pre-tests.lua
  3. 92 0
      pre.py

+ 5 - 0
pre-testinclude.lua

@@ -0,0 +1,5 @@
+function included_function()
+    return "I'm a function in another file!"
+end
+
+local included_var = "this is technically local but #include don't care about that"

+ 47 - 0
pre-tests.lua

@@ -0,0 +1,47 @@
+-- title:   A TIC-80 Game
+-- author:  pixelbath
+-- desc:    short description
+-- site:    website link
+-- license: MIT License (change this to your license of choice)
+-- version: 0.1
+-- script:  lua
+
+#include "pre-testinclude.lua"
+
+local t=0
+
+-- oh hey I gots a var
+
+-- you also shouldn't see this comment
+local var = 3
+
+var_bigger = var + 3
+var +=1
+var += 2
+var+=3
+
+var-=22203948
+
+
+function just_a_function(inputstring)
+    return "just_a_function was called"
+end
+
+just_a_function("foooooo")
+included_function()
+
+
+#define FOO "foo"
+#define BAR 23
+
+#define FUNCTION_SHIT function shit() return "shit" end
+
+function nothing_here()
+    return nil
+end
+
+local test_definestring = FOO + "bar"
+local test_defineint = 12 + BAR
+
+FUNCTION_SHIT
+

+ 92 - 0
pre.py

@@ -0,0 +1,92 @@
+# today we're gonna write a preprocessor for TIC-80 shit
+# support: #include, #define, overloaded ops (+=, -=, *=, /=)
+# license: MIT
+import os
+import re
+from typing import Dict, Set
+
+class LuaPreprocessor:
+    def __init__(self):
+        self.defines: Dict[str, str] = {}
+        self.included_files: Set[str] = set()
+    
+    def process_file(self, filename: str) -> str:
+        if filename in self.included_files:
+            raise RecursionError(f"Circular reference detected: {filename}")
+        
+        self.included_files.add(filename)
+        
+        try:
+            with open(filename, 'r') as f:
+                content = f.read()
+        except FileNotFoundError:
+            raise FileNotFoundError(f"Include file not found: {filename}")
+        
+        base_dir = os.path.dirname(os.path.abspath(filename))
+        # Process lines
+        lines = content.split('\n')
+        processed_lines = []
+        
+        for line in lines:
+            # Strip comments except TIC metadata
+            tic_comment = re.match(r'-- \S+:\s+.+', line)
+            if not tic_comment:
+                if '--' in line:
+                    line = line[:line.index('--')]
+                
+            # Handle #defines and store for later macro replacement
+            define_match = re.match(r'^\s*#define\s+(\w+)\s+(.+)$', line)
+            if define_match:
+                macro_name, macro_value = define_match.groups()
+                self.defines[macro_name] = macro_value.strip()
+                continue
+                
+            # Handle #includes
+            include_match = re.match(r'^\s*#include\s+"([^"]+)"$', line)
+            if include_match:
+                include_path = include_match.group(1)
+                abs_path = os.path.join(base_dir, include_path)
+                processed_lines.append(self.process_file(abs_path))
+                continue
+            
+            # Do the later macro replacement
+            for macro_name, macro_value in self.defines.items():
+                line = re.sub(r'\b' + macro_name + r'\b', macro_value, line)
+            
+            # Handle overload operators that don't exist in Lua
+            operator_match = re.match(r'(\S+)\s?(\+|-)=\s?(\S+)', line)
+            if operator_match:
+                op_var, op_type, op_inc = operator_match.groups()
+                replace_str = op_var + "=" + op_var + op_type + op_inc
+                processed_lines.append(line.replace(operator_match[0], replace_str))
+                continue
+
+            if line.strip() == "":
+                continue
+
+            processed_lines.append(line)
+            
+        return '\n'.join(processed_lines)
+
+def preprocess_lua(source_file: str) -> str:
+    """
+    Parse a C-style Lua file #define and #include directives into an actual Lua file that doesn't barf.
+    Also parses basic assigment operators, (+=, -=, *=, /=)
+    
+    Args:
+        source_file (str): Path to the root Lua file
+        
+    Returns:
+        str: Parsed Lua 
+        
+    Raises:
+        FileNotFoundError: If source file or included file is not found
+        RecursionError: If you're dumb and make a circular reference
+    """
+    preprocessor = LuaPreprocessor()
+    return preprocessor.process_file(source_file)
+
+lambda: os.system('cls')
+parseoutput = preprocess_lua("pre-tests.lua")
+print("Output:\n%s" % parseoutput)
+