1import os 2import sys 3 4from pyjade import Parser, Compiler as _Compiler 5from pyjade.runtime import attrs as _attrs 6from pyjade.utils import process 7ATTRS_FUNC = '__pyjade_attrs' 8ITER_FUNC = '__pyjade_iter' 9 10def attrs(attrs, terse=False): 11 return _attrs(attrs, terse, MakoUndefined) 12 13class Compiler(_Compiler): 14 useRuntime = True 15 def compile_top(self): 16 return '# -*- coding: utf-8 -*-\n<%%! from pyjade.runtime import attrs as %s, iteration as %s\nfrom mako.runtime import Undefined %%>' % (ATTRS_FUNC,ITER_FUNC) 17 18 def interpolate(self, text, escape=True): 19 return self._interpolate(text,lambda x:'${%s}'%x) 20 21 def visitCodeBlock(self,block): 22 if self.mixing > 0: 23 self.buffer('${caller.body() if caller else ""}') 24 else: 25 self.buffer('<%%block name="%s">'%block.name) 26 if block.mode=='append': self.buffer('${parent.%s()}'%block.name) 27 self.visitBlock(block) 28 if block.mode=='prepend': self.buffer('${parent.%s()}'%block.name) 29 self.buffer('</%block>') 30 31 def visitMixin(self,mixin): 32 self.mixing += 1 33 if not mixin.call: 34 self.buffer('<%%def name="%s(%s)">'%(mixin.name,mixin.args)) 35 self.visitBlock(mixin.block) 36 self.buffer('</%def>') 37 elif mixin.block: 38 self.buffer('<%%call expr="%s(%s)">'%(mixin.name,mixin.args)) 39 self.visitBlock(mixin.block) 40 self.buffer('</%call>') 41 else: 42 self.buffer('${%s(%s)}'%(mixin.name,mixin.args)) 43 self.mixing -= 1 44 45 def visitAssignment(self,assignment): 46 self.buffer('<%% %s = %s %%>'%(assignment.name,assignment.val)) 47 48 def visitExtends(self,node): 49 path = self.format_path(node.path) 50 self.buffer('<%%inherit file="%s"/>'%(path)) 51 52 def visitInclude(self,node): 53 path = self.format_path(node.path) 54 self.buffer('<%%include file="%s"/>'%(path)) 55 self.buffer('<%%namespace file="%s" import="*"/>'%(path)) 56 57 58 def visitConditional(self,conditional): 59 TYPE_CODE = { 60 'if': lambda x: 'if %s'%x, 61 'unless': lambda x: 'if not %s'%x, 62 'elif': lambda x: 'elif %s'%x, 63 'else': lambda x: 'else' 64 } 65 self.buf.append('\\\n%% %s:\n'%TYPE_CODE[conditional.type](conditional.sentence)) 66 if conditional.block: 67 self.visit(conditional.block) 68 for next in conditional.next: 69 self.visitConditional(next) 70 if conditional.type in ['if','unless']: self.buf.append('\\\n% endif\n') 71 72 73 def visitVar(self,var,escape=False): 74 return '${%s%s}'%(var,'| h' if escape else '| n') 75 76 def visitCode(self,code): 77 if code.buffer: 78 val = code.val.lstrip() 79 val = self.var_processor(val) 80 self.buf.append(self.visitVar(val, code.escape)) 81 else: 82 self.buf.append('<%% %s %%>'%code.val) 83 84 if code.block: 85 # if not code.buffer: self.buf.append('{') 86 self.visit(code.block) 87 # if not code.buffer: self.buf.append('}') 88 89 if not code.buffer: 90 codeTag = code.val.strip().split(' ',1)[0] 91 if codeTag in self.autocloseCode: 92 self.buf.append('</%%%s>'%codeTag) 93 94 def visitEach(self,each): 95 self.buf.append('\\\n%% for %s in %s(%s,%d):\n'%(','.join(each.keys),ITER_FUNC,each.obj,len(each.keys))) 96 self.visit(each.block) 97 self.buf.append('\\\n% endfor\n') 98 99 def attributes(self,attrs): 100 return "${%s(%s, undefined=Undefined) | n}"%(ATTRS_FUNC,attrs) 101 102 103 104def preprocessor(source): 105 return process(source,compiler=Compiler) 106