Changeset 5

Show
Ignore:
Timestamp:
12/08/04 11:06:34 (4 years ago)
Author:
steve
Message:

refactored into evaluator trees

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/airspeed.py

    r3 r5  
    22 
    33import re 
     4import cStringIO as StringIO 
    45 
    56class TemplateSyntaxError(Exception): pass 
     
    6061 
    6162 
     63class BlockEvaluator: 
     64    def __init__(self): 
     65        self.children = [] 
     66        self.delegate = None 
     67 
     68    def evaluate(self, output_stream, expression_lookup): 
     69        for child in self.children: 
     70            child.evaluate(output_stream, expression_lookup) 
     71 
     72    def add_evaluator(self, evaluator): 
     73        self.children.append(evaluator) 
     74        if hasattr(evaluator, 'add_evaluator'): 
     75            self.delegate = evaluator 
     76 
     77    def delegate_token(self, token_type, token_value): 
     78        if self.delegate: 
     79            if self.delegate.feed(token_type, token_value): 
     80                return True 
     81            else: self.delegate = None 
     82        return False 
     83 
     84    def feed(self, token_type, token_value): 
     85        if self.delegate_token(token_type, token_value): 
     86            return True 
     87        if token_type == Tokeniser.END: return False 
     88        elif token_type == Tokeniser.PLAIN: self.add_evaluator(PlainTextEvaluator(token_value)) 
     89        elif token_type == Tokeniser.PLACEHOLDER: self.add_evaluator(PlaceholderEvaluator(token_value)) 
     90        elif token_type == Tokeniser.FOREACH: self.add_evaluator(ForeachEvaluator(token_value)) 
     91        elif token_type == Tokeniser.IF: self.add_evaluator(IfEvaluator(token_value)) 
     92        else: raise TemplateSyntaxError("illegal token in block: %s, %s" % (token_type, token_value)) 
     93        return True 
     94 
     95 
     96class PlainTextEvaluator: 
     97    def __init__(self, text): 
     98        self.text = text 
     99 
     100    def evaluate(self, output_stream, expression_lookup): 
     101        output_stream.write(self.text) 
     102 
     103 
     104class PlaceholderEvaluator: 
     105    def __init__(self, token_value): 
     106        self.expression, self.silent, self.original_text = token_value 
     107 
     108    def evaluate(self, output_stream, expression_lookup): 
     109        value = expression_lookup(self.expression) 
     110        if value is None: 
     111            if self.silent: expression_value = '' 
     112            else: expression_value = self.original_text 
     113        else: 
     114            expression_value = str(value) 
     115        output_stream.write(expression_value) 
     116 
     117 
     118class IfEvaluator(BlockEvaluator): 
     119    def __init__(self, token_value): 
     120        BlockEvaluator.__init__(self) 
     121        self.condition_expression = token_value 
     122 
     123    def evaluate(self, output_stream, expression_lookup): 
     124        value = expression_lookup(self.condition_expression) 
     125        if value: 
     126            BlockEvaluator.evaluate(self, output_stream, expression_lookup) 
     127 
     128 
     129class ForeachEvaluator(BlockEvaluator): 
     130    def __init__(self, token_value): 
     131        BlockEvaluator.__init__(self) 
     132        self.expression, self.iter_var = token_value 
     133 
     134    def evaluate(self, output_stream, expression_lookup): 
     135        values = expression_lookup(self.expression) 
     136        for value in values: 
     137            BlockEvaluator.evaluate(self, output_stream, expression_lookup) 
     138 
     139 
    62140class Parser: 
    63  
    64141    def __init__(self): 
    65142        self.data = {} 
     
    67144    def merge(self, content): 
    68145        output = [] 
    69         filter_output_at_nesting_level = [False] 
    70         tokens = list(Tokeniser().tokenise(str(content))) 
    71         tokens.reverse() 
    72         while tokens: 
    73             token_type, token_value = tokens.pop() 
    74             filter_at_this_level = filter_output_at_nesting_level[-1] 
    75             if token_type == Tokeniser.PLAIN: 
    76                 if not filter_at_this_level: output.append(token_value) 
    77                 continue 
    78             if token_type == Tokeniser.PLACEHOLDER: 
    79                 expression, silent, original_text = token_value 
    80                 value = self.find(expression) 
    81                 if value is None: 
    82                     if silent: expression_value = '' 
    83                     else: expression_value = original_text 
    84                 else: 
    85                     expression_value = str(value) 
    86                 if not filter_at_this_level: output.append(expression_value) 
    87                 continue 
    88             if token_type == Tokeniser.IF: 
    89                 value = self.find(token_value) 
    90                 filter_my_content = filter_at_this_level or not bool(value) 
    91                 filter_output_at_nesting_level.append(filter_my_content) 
    92                 continue 
    93             if token_type == Tokeniser.FOREACH: 
    94                 expression, iter_var = token_value 
    95                 filter_output_at_nesting_level.append(filter_at_this_level) 
    96                 token_type, token_value = tokens.pop() 
    97                 values = self.find(expression) 
    98                 if token_type == Tokeniser.PLAIN: 
    99                     for item in values: 
    100                         if not filter_at_this_level: output.append(token_value) 
    101                 continue 
    102             if token_type == Tokeniser.END: 
    103                 if len(filter_output_at_nesting_level) == 1: 
    104                     raise TemplateSyntaxError("#end without beginning of block") 
    105                 del filter_output_at_nesting_level[-1] 
    106                 continue 
    107             raise TemplateSyntaxError("invalid token: %s" % text[:40]) 
    108  
    109         if len(filter_output_at_nesting_level) > 1: 
    110             raise TemplateSyntaxError("Unclosed block") 
    111         return ''.join(output) 
    112  
     146        evaluator = BlockEvaluator() 
     147        for token_type, token_value in Tokeniser().tokenise(str(content)): 
     148            evaluator.feed(token_type, token_value) 
     149        output = StringIO.StringIO() 
     150        evaluator.evaluate(output, self.find) 
     151        return output.getvalue() 
    113152 
    114153    def find(self, expression): 
    115154        o = self.data 
    116155        for part in expression.split('.'): 
    117             if part.endswith('()'): 
     156            if part.endswith('()'):  ## FIXME 
    118157                part = part[:-2] 
    119158                try: o = getattr(o, part) 
     
    142181 
    143182 
     183