diff options
Diffstat (limited to 'src/smp/macro_processor.py')
-rw-r--r-- | src/smp/macro_processor.py | 76 |
1 files changed, 46 insertions, 30 deletions
diff --git a/src/smp/macro_processor.py b/src/smp/macro_processor.py index e85fbe9..8fa9d91 100644 --- a/src/smp/macro_processor.py +++ b/src/smp/macro_processor.py @@ -41,6 +41,8 @@ class MacroProcessor: warnings: list[Any] """ Global environment for python execution """ py_global_env: dict + py_local_env_alt: dict + py_local_env_current: dict special_macros: dict[str, tuple[Any, Any]] @@ -49,32 +51,40 @@ class MacroProcessor: self.macro_invocations = list() self.warnings = list() self.py_global_env = dict() - self._define_builtins(prefix=prefix) - - def _define_builtins(self, prefix=""): - self.macros[f"{prefix}define"] = smp.builtins.smp_builtin_define - self.macros[f"{prefix}undefine"] = smp.builtins.smp_builtin_undefine - self.macros[f"{prefix}define_array"] = smp.builtins.smp_builtin_define_array - self.macros[f"{prefix}ifdef"] = smp.builtins.smp_builtin_ifdef - self.macros[f"{prefix}ifndef"] = smp.builtins.smp_builtin_ifndef - self.macros[f"{prefix}ifeq"] = smp.builtins.smp_builtin_ifeq - self.macros[f"{prefix}ifneq"] = smp.builtins.smp_builtin_ifneq - self.macros[f"{prefix}include"] = smp.builtins.smp_builtin_include - self.macros[f"{prefix}include_verbatim"] = ( - smp.builtins.smp_builtin_include_verbatim - ) - self.macros[f"{prefix}shell"] = smp.builtins.smp_builtin_shell - self.macros[f"{prefix}dumpenv"] = smp.builtins.smp_builtin_dumpenv - self.macros[f"{prefix}eval"] = smp.builtins.smp_builtin_eval - self.macros[f"{prefix}array_push"] = smp.builtins.smp_builtin_array_push - self.macros[f"{prefix}array_each"] = smp.builtins.smp_builtin_array_each - self.macros[f"{prefix}array_size"] = smp.builtins.smp_builtin_array_size - self.macros[f"{prefix}explode"] = smp.builtins.smp_builtin_explode - self.macros[f"{prefix}format_time"] = smp.builtins.smp_builtin_format_time - self.macros[f"{prefix}html_from_markdown"] = ( - smp.builtins.smp_builtin_html_from_markdown - ) - self.macros[f"{prefix}wodl"] = smp.builtins.smp_builtin_wodl + self.py_local_env_alt = dict() + self.py_local_env_current = self.macros + self.indent_level = "" + + self._define_builtins(self.macros, prefix=prefix) + self._define_builtins(self.py_local_env_alt, prefix=prefix) + + def _define_builtins(self, env, prefix=""): + env[f"{prefix}macro_processor"] = self + env[f"{prefix}define"] = smp.builtins.smp_builtin_define + env[f"{prefix}undefine"] = smp.builtins.smp_builtin_undefine + env[f"{prefix}define_array"] = smp.builtins.smp_builtin_define_array + env[f"{prefix}ifdef"] = smp.builtins.smp_builtin_ifdef + env[f"{prefix}ifndef"] = smp.builtins.smp_builtin_ifndef + env[f"{prefix}ifeq"] = smp.builtins.smp_builtin_ifeq + env[f"{prefix}ifneq"] = smp.builtins.smp_builtin_ifneq + env[f"{prefix}include"] = smp.builtins.smp_builtin_include + env[f"{prefix}include_verbatim"] = smp.builtins.smp_builtin_include_verbatim + env[f"{prefix}shell"] = smp.builtins.smp_builtin_shell + env[f"{prefix}dumpenv"] = smp.builtins.smp_builtin_dumpenv + env[f"{prefix}eval"] = smp.builtins.smp_builtin_eval + env[f"{prefix}array_push"] = smp.builtins.smp_builtin_array_push + env[f"{prefix}array_each"] = smp.builtins.smp_builtin_array_each + env[f"{prefix}array_size"] = smp.builtins.smp_builtin_array_size + env[f"{prefix}explode"] = smp.builtins.smp_builtin_explode + env[f"{prefix}format_time"] = smp.builtins.smp_builtin_format_time + env[f"{prefix}html_from_markdown"] = smp.builtins.smp_builtin_html_from_markdown + env[f"{prefix}wodl"] = smp.builtins.smp_builtin_wodl + + def define_macro_string(self, macro_name, macro_value): + self.define_macro(macro_name, str(macro_value)) + + def define_macro(self, macro_name, macro_value): + self.macros[macro_name] = macro_value def expand_macro(self, macro_name: str, args: list[str] = list()) -> str: # Ignore trailing underscore in macro name, the parser will pop a space in front if @@ -104,14 +114,18 @@ class MacroProcessor: if callable(macro): signature = inspect.signature(macro) - macro_args = [] + macro_args: list[Any] = [] if ( "macro_processor" in signature.parameters or "smp" in signature.parameters ): macro_args.append(self) macro_args.extend(args) - return str(macro(*macro_args)) + try: + return str(macro(*macro_args)) + except Exception as e: + s = f"{macro_name}({','.join([repr(x) for x in macro_args])})" + raise Exception(s) if isinstance(macro, str): expanded = macro for i, arg in enumerate(args): @@ -143,8 +157,11 @@ class MacroProcessor: skip_next_line_ending = False + line_begin = True + # We should keep track of filename, linenumber, and character number on line here # So we can give sensible error messages + # Probably add to python stack trace? quote_level = 0 parens_level = 0 @@ -153,7 +170,6 @@ class MacroProcessor: while i < len(input): c = input[i] peek = None if i + 1 >= len(input) else input[i + 1] - # import sys # print(f"[{i:4}] {repr(c):4} -> {repr(peek):4} [{state}] = {repr(output)}", file=sys.stderr) @@ -264,7 +280,7 @@ class MacroProcessor: try: f = StringIO() with redirect_stdout(f): - exec(py_expr, self.py_global_env, self.macros) + exec(py_expr, self.py_global_env, self.py_local_env_current) s = f.getvalue() if s != "": output += s |