"""

I have this idea about templates == grammars....

Let's try implementing it in a brute force way for now, forgetting all
we know about grammar compilation, etc...

Let's get started.   Import the module, and create your first Language:

   >>> import template
   >>> l = template.Language()

Create some classes and properties:

   >>> import loader
   >>> m = loader.load('test-data/books.asn')
   
Define two templates (grammar rules):

   >>> l.add(m.Book, ["book", m.title, ",", m.author, "endbook"])
   >>> l.add(m.Person, ["person", m.name, "endperson"])

See them again, in a grammar-like style:

   >>> import qname
   >>> map = qname.Map()
   >>> map.bind('', 'http://www.w3.org/2007/01/ss-example#')
   >>> print l.str(map)
   Book ::= "book" title "," author "endbook"
   Person ::= "person" name "endperson"
   <BLANKLINE>

Parse plaintext:

   >>> s="bookPython,personGuidoendpersonendbook"
   >>> l.parse(s, m.Book)

Output the Language in BNF   (variations)
    ...

Serialize an instance (tree)

Parse an instance (tree)

Show it being used for HTML generation

Show it being used for HTML scraping

****************

if/then/else
forall

  Loop(multi/set, subtemplate)

  Branch(property = constant_value, then, [else])

  Elements in the sequence are:
       strings
       regexps
       Properties
       Property-loop (forall)   -- properties which are collections
             -- how to handle commas, surroundings for each, etc

             "friends: ", forall(x, someprop, template), "."
                                              ^-- or class?
                               like -- some equivalent class?  it
                                       still has to match the slements
                            (someprop -- multi, list, or either?)
  
"""
__version__ = "$Revision: 1.3 $"
# $Id: template.py,v 1.3 2007-09-21 02:54:36 sandro Exp $

import objectmodel

class Error(RuntimeError):
   pass

class Language:
   """A Language is a set of templates.
   
   For us, we have a dictionary mapping class->list of templates,
   since that's the way we want to access them.

   """

   def __init__(self):
      self.templates = { }
      
   def add(self, cls, sequence, weight=1.0):
      t = Template(language=self, cls=cls, sequence=sequence, weight=weight)
      self.templates.setdefault(cls, []).append(t)
      self.templates[cls].sort()
      # weight-sort that array

   def str(self, map):
      result = ""
      # it would be nice to try a tsort, to find a nice order
      for tlist in sorted(self.templates.values()):
         for t in tlist:
            result += t.str(map) + "\n"
      return result

   def parse(self, text, cls):
       for t in self.templates[cls]:
           if self.match(self, text, t, 0):
               return

   def match(self, text, template, index):
       try:
           element = template.sequence[index]
       except IndexError:
           return True
       if isinstance(element, basestring):
           if text.startswith(element):
               l = len(element)
               return self.match(text[l:], template, index+1)
           return False
       if isinstance(element, objectmodel.Property):
          # look up the range
          # look for a template matching that class
          # and try a match on it....
          # @@@
          return False
       # loop structures   [ if not recursive ] 
           
       
class Template:

    #def __init__(self, language, cls, sequence=[], weight=1.0):
    #    self.__dict__.update(locals())

    def __init__(self, **kwargs):
        #super.__init__(self, **kwargs)
        self.cls = kwargs.get("cls", None)
        self.sequence = kwargs.get("sequence", [])
        self.weight = kwargs.get("weight", [1.0])

    def __cmp__(self, other):
       result = cmp(self.weight, other.weight)
       if result != 0:
          return result
       return  cmp(self.sequence, other.sequence)
    
    def match(self, domnode):
        # recursive list match...
        return self.match(domnode.firstChild, 0)

    def match(self, domnode, index):
        term = self.sequence[index]
        # @@@ if term....

    
    def str(self, map):
        result = map.qname(self.cls.name) + " ::= "
        for item in self.sequence:
            if isinstance(item, basestring):
                result += '"'+item+'"'
            else:
                result += map.qname(item.name)
            result += " "
        return result[0:-1]


if __name__ == "__main__":
    import doctest, sys
    doctest.testmod(sys.modules[__name__])


# $Log: template.py,v $
# Revision 1.3  2007-09-21 02:54:36  sandro
# rdfnodes.py
#
# Revision 1.2  2007/04/05 21:16:21  sandro
# finally a little progress on templates
#
# Revision 1.1  2007/01/22 06:09:08  sandro
# results of a long day hacking - kind of works
#


