1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192 |
- # 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)
|