#!/usr/bin/env python from __future__ import print_function import sys import re import json from typing import Any, Dict, List def debug(obj): print(json.dumps(obj, indent=4)) def parse_file(fn): # type: (str) -> Dict[str, Any] text = open(fn).read() tags = re.findall('{+\s*(.*?)\s*}+', text) root = {} # type: Dict[str, Any] context = root stack = [] # type: List[Dict[str, Any]] def set_var(var, val): # type: (str, Any) -> None num_levels_up = len(re.findall('\.\.', var)) if num_levels_up: var = var.split('/')[-1] stack[-1 * num_levels_up][var] = val else: context[var] = val for tag in tags: if tag.startswith('! '): continue if tag == 'else': continue if tag[0] in '#^' and ' ' not in tag: var = tag[1:] set_var(var, True) stack.append(context) continue if tag.startswith('#if'): vars = tag.split()[1:] for var in vars: set_var(var, True) stack.append(context) continue if tag.startswith('/if'): context = stack.pop() continue if tag.startswith('#with '): var = tag.split()[1] new_context = {} # type: Dict[str, Any] context[var] = new_context stack.append(context) context = new_context continue if tag.startswith('/with'): context = stack.pop() continue if tag.startswith('#unless '): var = tag.split()[1] set_var(var, True) stack.append(context) continue if tag.startswith('/unless'): context = stack.pop() continue if tag.startswith('#each '): var = tag.split()[1] new_context = {} context[var] = [new_context] stack.append(context) context = new_context continue if tag.startswith('/each'): context = stack.pop() continue if tag.startswith('/'): context = stack.pop() continue set_var(tag, '') def clean_this(obj): # type: (Any) -> Any if isinstance(obj, list): return [clean_this(item) for item in obj] if isinstance(obj, dict): if len(obj) == 1 and 'this' in obj: return clean_this(obj['this']) return {k: clean_this(v) for k, v in obj.items()} return obj root = clean_this(root) return root if __name__ == '__main__': for fn in sys.argv[1:]: print('===', fn) root = parse_file(fn) debug(root) print()