Simple template language written in python
git clone git://git.janzachar.dev/stempl.git
0from dataclasses import dataclass, asdict1import parser23from context import Context4import subprocess, json5import page6from pathlib import Path789class Interpreter:10 def __init__(self, ast: parser.Node, ctx: Context):11 self.ast = ast12 self.ctx = ctx1314 def interpret(self, node = None):15 if node is None:16 node = self.ast1718 if isinstance(node, parser.Raw):19 return self.raw(node)2021 if isinstance(node, parser.Statement):22 return str(self.statement(node))2324 raise TypeError("Raw or Statement expected!")2526 def raw(self, node):27 out = node.text28 if node.right is not None:29 out += self.interpret(node.right)3031 return out3233 def statement(self, node):34 out = self.__getValue(node.child)3536 if node.right is not None:37 out += self.interpret(node.right)3839 return out4041 def conditional(self, node):42 condition = self.__getValue(node.condition)4344 if condition:45 return self.interpret(node.body)46 else:47 return self.interpret(node.alternative)4849 def iterative(self, node):50 ctx = Context(self.ctx)51 inter = Interpreter(node.body, ctx)52 sequence = self.__getValue(node.sequence)5354 out = ""55 for i in sequence:56 ctx[node.iterator.name] = i57 out += inter.interpret()5859 return out6061 def inclusion(self, node):62 path = self.__getValue(node.path)6364 if node.israw:65 with open(path) as fp:66 return fp.read()6768 if path.endswith(".py"):69 # ACHTUNG! SHIT CODE70 def default(o):71 if isinstance(o, Context):72 return None73 return o.data74 if isinstance(o, Path):75 return str(o)76 raise TypeError(f"Object of type {type(o).__name__} is not JSON serializable")7778 j = json.dumps(self.ctx.data, default=default)79 p = subprocess.run(80 ["python3", f"{self.ctx["site"]["src"]}/{path}", j],81 capture_output=True,82 text=True83 )84 print(p.stderr)85 return p.stdout8687 p = page.Page(path, self.ctx)88 return p.run()8990 def ident(self, node):91 return self.ctx[node.name]9293 def strConst(self, node):94 return node.data9596 def numConst(self, node):97 return node.data9899 def __getValue(self, node) -> Node:100 Map = {101 parser.Identifier: self.ident,102 parser.StrConst: self.strConst,103 parser.NumConst: self.numConst,104 parser.BinOp: self.binOp,105 parser.ConditionalStatement: self.conditional,106 parser.IterativeStatement: self.iterative,107 parser.InclusionStatement: self.inclusion108 }109110 if node.__class__ not in Map.keys():111 raise TypeError(f"Can't retrieve value from {node}")112113 return Map[node.__class__](node)114115 def binOp(self, node) -> Node:116 left = self.__getValue(node.left)117 right = self.__getValue(node.right)118119 if node.op in [120 "*", "/", "//", "%", "+", "-", "<<", ">>",121 "<", ">", "<=", ">=", "==", "!=", "&", "|"]:122 return eval("l" + node.op + "r", {"l": left, "r": right})123124 if node.op == "&&":125 return left and right126127 if node.op == "||":128 return left or right129130 raise TypeError(f"Invalid operator {node.op}")131132