Index: genshi/template/inline.py
===================================================================
--- genshi/template/inline.py	(Revision 1127)
+++ genshi/template/inline.py	(Arbeitskopie)
@@ -79,6 +79,280 @@
     return '{%s}' % ', '.join(buf)
 
 
+# represents basically a symbol table
+class Context(object):
+
+    def __init__(self):
+        self.qnames = []
+        self.attributes = {}
+        self.expressions = []
+        self.macros = {}
+        self.paths = []
+        self.suites = []
+        self.variables = {}
+        self.last_event = None
+
+    def declare_attr(self, qname, value):
+        pass
+
+    def declare_expression(self, expr):
+        pass
+
+    def declare_macro(self, name, macro):
+        pass
+
+    def declare_path(self, path):
+        pass
+
+    def declare_qname(self, qname):
+        pass
+
+    def declare_suite(self, suite):
+        pass
+
+    def declare_variable(self, name, expr):
+        pass
+
+
+# Stream
+class StreamProcessor(object):
+
+    def __init__(self):
+        self.visitors = []
+        self.visitors.append(EndEventVisitor())
+        self.visitors.append(ExecEventVisitor())
+        self.visitors.append(IncludeEventVisitor())
+        self.visitors.append(StartEventVisitor())
+        self.visitors.append(SubstreamEventVisitor())
+
+    def process(self, stream, context):
+        for kind, data, pos in stream:
+            context.last_event = (kind, data, pos)
+            for visitor in visitors:
+                if visitor.can_visit(kind):
+                    visitor.visit(kind, data, pos, context)
+                    break
+
+
+# Stream Events
+class StreamEventVisitor(object):
+
+    #@abstractmethod
+    def can_visit(self, kind):
+        pass
+
+    #@abstractmethod
+    def visit(self, kind, data, pos, context):
+        pass
+
+
+class EndEventVisitor(StreamEventVisitor):
+
+    def can_visit(self, kind):
+        return kind is END
+
+    def visit(self, kind, data, pos, context):
+        pass
+
+
+class ExecEventVisitor(StreamEventVisitor):
+
+    def can_visit(self, kind):
+        return kind is EXEC
+
+    def visit(self, kind, data, pos, context):
+        pass
+
+
+class IncludeEventVisitor(StreamEventVisitor):
+
+    def can_visit(self, kind):
+        return kind is INCLUDE
+
+    def visit(self, kind, data, pos, context):
+        pass
+
+
+class StartEventVisitor(StreamEventVisitor):
+
+    def can_visit(self, kind):
+        return kind is START
+
+    def visit(self, kind, data, pos, context):
+        pass
+
+
+class SubstreamEventVisitor(StreamEventVisitor):
+
+    def __init__(self):
+        self.visitors = []
+        self.visitors.append(AttrsDirectiveVisitor())
+        self.visitors.append(ChooseDirectiveVisitor())
+        self.visitors.append(ContentDirectiveVisitor())
+        self.visitors.append(DefDirectiveVisitor())
+        self.visitors.append(ForDirectiveVisitor())
+        self.visitors.append(IfDirectiveVisitor())
+        self.visitors.append(MatchDirectiveVisitor())
+        self.visitors.append(OtherwiseDirectiveVisitor())
+        self.visitors.append(ReplaceDirectiveVisitor())
+        self.visitors.append(StripDirectiveVisitor())
+        self.visitors.append(WhenDirectiveVisitor())
+        self.visitors.append(WithDirectiveVisitor())
+
+    def can_visit(self, kind):
+        return kind is SUB
+
+    def visit(self, kind, data, pos, context):
+        directives, substream = data
+
+        for directive in directives:
+            for visitor in self.visitors:
+                if visitor.can_visit(directive):
+                    visitor.visit(directive, substream, context)
+                    break
+
+        # recursively process the substreams
+        processor = StreamProcessor()
+        processor.process(substream, context)
+
+
+# Directives
+
+class DirectiveVisitor(object):
+
+    #@abstractmethod
+    def can_vist(self, directive):
+        pass
+
+    #@abstractmethod
+    def visit(self, directive, substream, context):
+        pass
+
+
+class AttrsDirectiveVisitor(DirectiveVisitor):
+
+    def can_visit(self, kind):
+        return isinstance(directive, AttrsDirective)
+
+    def visit(self, directive, substream, context):
+        pass
+
+
+class ChooseDirectiveVisitor(DirectiveVisitor):
+
+    def can_visit(self, kind):
+        return isinstance(directive, ChooseDirective)
+
+    def visit(self, directive, substream, context):
+        pass
+
+
+class ContentDirectiveVisitor(DirectiveVisitor):
+
+    def can_visit(self, kind):
+        return isinstance(directive, ContentDirective)
+
+    def visit(self, directive, substream, context):
+        pass
+
+
+class DefDirectiveVisitor(DirectiveVisitor):
+
+    def can_visit(self, kind):
+        return isinstance(directive, DefDirective)
+
+    def visit(self, directive, substream, context):
+        pass
+
+
+class ForDirectiveVisitor(DirectiveVisitor):
+
+    def can_visit(self, kind):
+        return isinstance(directive, ForDirective)
+
+    def visit(self, directive, substream, context):
+        pass
+
+
+class IfDirectiveVisitor(DirectiveVisitor):
+
+    def can_visit(self, kind):
+        return isinstance(directive, IfDirective)
+
+    def visit(self, directive, substream, context):
+
+        if directive.expr:
+            context.declare_expression( directive.expr )
+
+
+class MatchDirectiveVisitor(DirectiveVisitor):
+
+    def can_visit(self, kind):
+        return isinstance(directive, MatchDirective)
+
+    def visit(self, directive, substream, context):
+
+        if directive.path:
+            context.declare_path( directive.path )
+
+
+class OtherwiseDirectiveVisitor(DirectiveVisitor):
+
+    def can_visit(self, kind):
+        return isinstance(directive, OtherwiseDirective)
+
+    def visit(self, directive, substream, context):
+        pass
+
+
+class ReplaceDirectiveVisitor(DirectiveVisitor):
+
+    def can_visit(self, kind):
+        return isinstance(directive, ReplaceDirective)
+
+    def visit(self, directive, substream, context):
+        pass
+
+
+class StripDirectiveVisitor(DirectiveVisitor):
+
+    def can_visit(self, kind):
+        return isinstance(directive, StripDirective)
+
+    def visit(self, directive, substream, context):
+        # FIXME problem here, strip strips the current element when true, 
+        # which is already accomplished by this,
+        # however, if strip resolves to false, then the original element
+        # in the stream must be preserved, which is currently not supported
+        # by this, unless context would provide something like last_event
+        pass
+
+
+class WhenDirectiveVisitor(DirectiveVisitor):
+
+    def can_visit(self, kind):
+        return isinstance(directive, WhenDirective)
+
+    def visit(self, directive, substream, context):
+
+        if directive.expr:
+            context.declare_expr(directive.expr)
+        else:
+            raise Error()
+
+
+class WithDirectiveVisitor(DirectiveVisitor):
+
+    def can_visit(self, kind):
+        return isinstance(directive, WithDirective)
+
+    def visit(self, directive, substream, context):
+
+        if directive.vars:
+            for var in directive.vars:
+                context.declare_variable(var)
+
+
 def inline(template):
     w = CodeWriter()
 
@@ -118,13 +392,16 @@
                 directives, substream = data
                 for directive in directives:
 
+                    # IfDirective, WhenDirective, OtherwiseDirective, ChooseDirective
                     if directive.expr:
                         yield 'E', directive.expr, directive.expr
 
+                    # WithDirective
                     elif hasattr(directive, 'vars'):
                         for _, expr in directive.vars:
                             yield 'E', expr, expr
 
+                    # MatchDirective
                     elif hasattr(directive, 'path') and directive.path:
                         yield 'P', directive.path, directive.path
 
@@ -274,6 +551,13 @@
     for line in _generate(template.stream):
         yield line
 
+    # THINK must also remove macro functions at end of compiled template?
+    # declared macros are generally visible on a global scope, therefore
+    # they should be kept in context
+    #if defs:
+    #    yield w()
+    #    yield w('pop()')
+    #    yield w()
 
 if __name__ == '__main__':
     import timeit
@@ -297,6 +581,8 @@
         <span py:replace="item + 1">NUM</span>
       </li>
     </ul>
+    <div id="foo">foo</div>
+    <div id="bar">bar</div>
  </body>
 </html>"""
 
Index: genshi/template/markup.py
===================================================================
--- genshi/template/markup.py	(Revision 1127)
+++ genshi/template/markup.py	(Arbeitskopie)
@@ -343,6 +343,14 @@
                         del match_templates[idx]
                         idx -= 1
 
+                    # Make the select() function available in the body of the
+                    # match template
+                    selected = [False]
+                    def select(path):
+                        selected[0] = True
+                        return content.select(path, namespaces, ctxt)
+                    vars = dict(select=select)
+
                     # Let the remaining match templates know about the event so
                     # they get a chance to update their internal state
                     for test in [mt[0] for mt in match_templates[idx + 1:]]:
@@ -362,14 +370,6 @@
                         content = list(content)
                     content = Stream(content)
 
-                    # Make the select() function available in the body of the
-                    # match template
-                    selected = [False]
-                    def select(path):
-                        selected[0] = True
-                        return content.select(path, namespaces, ctxt)
-                    vars = dict(select=select)
-
                     # Recursively process the output
                     template = _apply_directives(template, directives, ctxt,
                                                  vars)
