aboutsummaryrefslogtreecommitdiff
path: root/src/smp
diff options
context:
space:
mode:
Diffstat (limited to 'src/smp')
-rw-r--r--src/smp/__init__.py13
-rw-r--r--src/smp/builtins.py6
-rw-r--r--src/smp/macro_processor.py76
3 files changed, 58 insertions, 37 deletions
diff --git a/src/smp/__init__.py b/src/smp/__init__.py
index 63cecaf..22085ae 100644
--- a/src/smp/__init__.py
+++ b/src/smp/__init__.py
@@ -2,6 +2,11 @@ __version__ = "0.0.1"
import smp.macro_processor
import smp.builtins
+__all__ = [
+ "smp.macro_processor",
+ "smp.builtins",
+]
+
def repl():
print("=Skaldpress Macro Processor (REPL)")
@@ -15,8 +20,8 @@ def read_stdin():
import sys
data = sys.stdin.read()
- smp = macro_processor.MacroProcessor()
- res = smp.process_input(data)
+ macro_processor = smp.macro_processor.MacroProcessor()
+ res = macro_processor.process_input(data)
print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━", file=sys.stderr)
print(res)
@@ -39,7 +44,7 @@ def main():
with open(sys.argv[1], "r") as f:
file_content = f.read()
- smp = macro_processor.MacroProcessor()
- res = smp.process_input(file_content)
+ macro_processor = smp.macro_processor.MacroProcessor()
+ res = macro_processor.process_input(file_content)
print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━", file=sys.stderr)
print(res)
diff --git a/src/smp/builtins.py b/src/smp/builtins.py
index f463a24..9a27864 100644
--- a/src/smp/builtins.py
+++ b/src/smp/builtins.py
@@ -1,10 +1,10 @@
-import smp.exceptions
+# import smp.exceptions
import subprocess
import urllib.request
import urllib.error
import datetime
import markdown
-from gfm import AutolinkExtension, TaskListExtension
+from gfm import AutolinkExtension, TaskListExtension # type: ignore
def smp_builtin_define(macro_processor, macro_name, macro_value=None):
@@ -147,7 +147,7 @@ def smp_builtin_html_from_markdown(macro_processor, text, extensions=list()):
global LINK_CACHE
-LINK_CACHE = dict()
+LINK_CACHE: dict[str, tuple[bool, int, str]] = dict()
def smp_builtin_wodl(macro_processor, link, timeout_seconds=5):
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