yml2/backend.py
changeset 52 b4a9a3122abb
child 57 2f4ad3800a3f
equal deleted inserted replaced
22:3a2bd70c01df 52:b4a9a3122abb
       
     1 # 2.5.8 backend
       
     2 
       
     3 # written by VB.
       
     4 
       
     5 import re, codecs
       
     6 import fileinput
       
     7 import sys, traceback, exceptions, os
       
     8 from xml.sax.saxutils import escape, quoteattr
       
     9 from copy import deepcopy
       
    10 from glob import glob
       
    11 from pyPEG import code, parse, parseLine, u, Symbol
       
    12 from yml2 import ymlCStyle, comment, _inner
       
    13 
       
    14 ymlFunc, pointers, pythonFunc = {}, {}, {}
       
    15 in_ns = u""
       
    16 operator = []
       
    17 included = u""
       
    18 includePath = []
       
    19 emitlinenumbers = False
       
    20 encoding = "utf-8"
       
    21 
       
    22 first = True
       
    23 enable_tracing = False
       
    24 
       
    25 ymlFunc["decl"] = "#error"
       
    26 ymlFunc["define"] = "#error"
       
    27 ymlFunc["operator"] = "#error"
       
    28 
       
    29 def clearAll():
       
    30     global ymlFunc, pointers, pythonFunc, in_ns, operator, included
       
    31     ymlFunc, pointers, pythonFunc = {}, {}, {}
       
    32     in_ns = u""
       
    33     operator = []
       
    34     included = u""
       
    35 
       
    36 lq = re.compile(r"\|(\>*)(.*)")
       
    37 sq = re.compile(r"(\d*)\>(.*)")
       
    38 ts = re.compile(r'(\|\|(?P<inds>\>*)\s*\n(?P<text1>.*?)\n(?P<base>\s*)\|\|)|("""(?P<text2>.*?)""")|(\>\>(?P<text3>.*?)\>\>)', re.S)
       
    39 tq = re.compile(r"(\]|\<)\s*(.*)")
       
    40 bq = re.compile(r"\`(.*?)\`", re.S)
       
    41 bqq = re.compile(r"\s*\`\`(.*)")
       
    42 all = re.compile(r".*", re.S)
       
    43 
       
    44 line = 1
       
    45 
       
    46 def pointer(name):
       
    47     try:
       
    48         return u(pointers[name[1:]])
       
    49     except:
       
    50         if name == "*_trace_info":
       
    51             return u'""'
       
    52         if included:
       
    53             raise LookupError(u"in " + included + u":" + u(line) + u": pointer " + name)
       
    54         else:
       
    55             raise LookupError(u"in " + u(line) + u": pointer " + name)
       
    56 
       
    57 def evalPython(expr):
       
    58     try:
       
    59         result = eval(u(expr), pythonFunc)
       
    60         if type(result) is str:
       
    61             return codecs.decode(result, encoding)
       
    62         else:
       
    63             return result
       
    64     except:
       
    65         name, parm, tb = sys.exc_info()
       
    66         msg = u"in python expression: " + u(parm)
       
    67         if name is exceptions.SyntaxError:
       
    68             tbl = traceback.format_exception(name, parm, tb)
       
    69             msg += u"\n" + tbl[-3] + tbl[-2]
       
    70         else:
       
    71             msg += u": " + expr + u"\n"
       
    72         if included:
       
    73             raise name(u"in " + included + u":" + u(line) + u": " + msg)
       
    74         else:
       
    75             raise name(u"in " + u(line) + u": " + msg)
       
    76     
       
    77 def execPython(script):
       
    78     try:
       
    79         if type(script) is unicode:
       
    80             exec script in pythonFunc
       
    81         else:
       
    82             exec codecs.decode(script, encoding) in pythonFunc
       
    83     except:
       
    84         name, parm, tb = sys.exc_info()
       
    85         msg = u"in python script: " + u(parm)
       
    86         if name is exceptions.SyntaxError:
       
    87             tbl = traceback.format_exception(name, parm, tb)
       
    88             msg += u"\n" + tbl[-3] + tbl[-2]
       
    89         else:
       
    90             msg += u": " + expr + u"\n"
       
    91         if included:
       
    92             raise name(u"in " + included + u":" + u(line) + u": " + msg)
       
    93         else:
       
    94             raise name(u"in " + u(line) + u": " + msg)
       
    95 
       
    96 def textOut(text):
       
    97     if not text:
       
    98         return u""
       
    99     if type(text) is not unicode:
       
   100         text = codecs.decode(text, encoding)
       
   101     text = text.replace(r'\"', r'\\"')
       
   102     text = u'u"""' + text.replace('"', r'\"') + u'"""'
       
   103     try:
       
   104         textFunc = ymlFunc["text"]
       
   105         parms = ['text', ('parm', [text])]
       
   106         c, result = textFunc(parms)
       
   107         if c:
       
   108             if type(textFunc.alias) is unicode:
       
   109                 result += u"</" + textFunc.alias + u">"
       
   110             else:
       
   111                 result += u"</" + codecs.decode(textFunc.alias, encoding) + u">"
       
   112         return result
       
   113     except:
       
   114         return escape(eval(text))
       
   115 
       
   116 def strRepl(text):
       
   117     if not text:
       
   118         return u""
       
   119     if type(text) is not unicode:
       
   120         text = codecs.decode(text, encoding)
       
   121     text = text.replace(r'\"', r'\\"')
       
   122     text = u'u"""' + text.replace('"', r'\"') + u'"""'
       
   123     if type(text) is unicode:
       
   124         return escape(eval(text))
       
   125 
       
   126 def applyMacros(macros, text):
       
   127     result = text
       
   128     for key, value in macros.iteritems():
       
   129         result = result.replace(key, value)
       
   130     return result
       
   131 
       
   132 class YF:
       
   133     def __init__(self, name):
       
   134         self.name = name
       
   135         self.parms = []
       
   136         self.descends = []
       
   137         self.values = {}
       
   138         self.content = None
       
   139         self.pointers = {}
       
   140         self.macros = {}
       
   141         if in_ns:
       
   142             self.alias = in_ns + u":" + name.replace("_", "-")
       
   143         else:
       
   144             self.alias = name.replace("_", "-")
       
   145         pythonFunc["yml_" + name] = self
       
   146         if emitlinenumbers:
       
   147             self.values["yml:declared"] = u(line)
       
   148 
       
   149     def copy(self, newName):
       
   150         yf = YF(newName)
       
   151         yf.parms.extend(self.parms)
       
   152         yf.descends.extend(self.descends)
       
   153         yf.values = self.values.copy()
       
   154         yf.content = self.content
       
   155         yf.pointers = self.pointers.copy()
       
   156         yf.macros = self.macros.copy()
       
   157         yf.alias = self.alias
       
   158         return yf
       
   159 
       
   160     def patch(self, second):
       
   161         self.parms.extend(second.parms)
       
   162         self.descends.extend(second.descends)
       
   163         self.values.update(second.values)
       
   164         if second.content:
       
   165             self.content = second.content
       
   166         self.pointers.update(second.pointers)
       
   167         self.macros.update(second.macros)
       
   168 
       
   169     def __call__(self, called_with, hasContent = False, avoidTag = False):
       
   170         global pointers
       
   171         parms = []
       
   172         vals = {}
       
   173         if self.pointers:
       
   174             pointers.update(self.pointers)
       
   175    
       
   176         for data in called_with:
       
   177             if type(data) is tuple or type(data) is Symbol:
       
   178                 if data[0] == "parm":
       
   179                     l = data[1]
       
   180                     parm = l[0]
       
   181                     if parm[0] == "*":
       
   182                         parm = pointer(parm)
       
   183                     if len(l) == 1:
       
   184                         if type(parm) is tuple or type(parm) is Symbol:
       
   185                             if parm[0] == "pyExp":
       
   186                                 val = evalPython(parm[1][0])
       
   187                                 parms.append(val)
       
   188                         else:
       
   189                             parms.append(evalPython((parm)))
       
   190                     else:
       
   191                         if type(parm) is tuple or type(parm) is Symbol:
       
   192                             if parm[0] == "pyExp":
       
   193                                 parm = evalPython(parm[1][0])
       
   194                         val = l[1]
       
   195                         if type(val) is tuple or type(val) is Symbol:
       
   196                             if val[0] == "pyExp":
       
   197                                 val = evalPython(val[1][0])
       
   198                         if val[0] == "*":
       
   199                             val = pointer(val)
       
   200                         if u(val)[0] == '"' or u(val)[0] == "'":
       
   201                             vals[parm] = evalPython(u(val))
       
   202                         else:
       
   203                             vals[parm] = u(val)
       
   204                 elif data[0] == "content":
       
   205                     hasContent = True
       
   206 
       
   207         if enable_tracing:
       
   208             text = u(parms) + u", " + u(vals)
       
   209             pointers["_trace_info"] = u'"' + u(line) + u": " + u(self.name) + u" " + text.replace(u'"', u'#') + u'"'
       
   210 
       
   211         if emitlinenumbers:
       
   212             global first
       
   213             if first:
       
   214                 vals["xmlns:yml"] = u"http://fdik.org/yml"
       
   215                 first = False
       
   216             vals["yml:called"] = u(line)
       
   217         return self.xml(parms, vals, hasContent, avoidTag)
       
   218 
       
   219     def addParm(self, parm):
       
   220         if parm[0] == "%":
       
   221             for i in range(len(self.parms)):
       
   222                 if self.parms[i][0] != "%":
       
   223                     self.parms.insert(i, parm)
       
   224                     return
       
   225         self.parms.append(parm)
       
   226 
       
   227     def addDescend(self, desc):
       
   228         if desc[0] == "+" or desc[0] == "@":
       
   229             self.descends.append(desc[1:])
       
   230         else:
       
   231             self.descends.append(desc)
       
   232 
       
   233     def addValue(self, parm, value):
       
   234         if type(value) is str or type(value) is unicode:
       
   235             if value[0] != "'" and value[0] != '"':
       
   236                 self.values[parm] = u(value)
       
   237             else:
       
   238                 self.values[parm] = u(evalPython(value))
       
   239         else:
       
   240             self.values[parm] = u(evalPython(u(value)))
       
   241 
       
   242     def xml(self, callParms, callValues, hasContent, avoidTag = False):
       
   243         global pointers
       
   244         extraContent = u""
       
   245         if self.content:
       
   246             hasContent = True
       
   247         resultParms = self.values.copy()
       
   248         macros = self.macros.copy()
       
   249         toDelete = resultParms.keys()
       
   250         for key in toDelete:
       
   251             if key[0] == "*":
       
   252                 del resultParms[key]
       
   253         for key, value in callValues.iteritems():
       
   254             if key[0] == "%":
       
   255                 macros[key] = value
       
   256             else:
       
   257                 resultParms[key] = value
       
   258         i = 0
       
   259         for cp in callParms:
       
   260             if i < len(self.parms):
       
   261                 if self.parms[i][0] == "*":
       
   262                     cp = u(cp)
       
   263                     if "'" in cp:
       
   264                         pointers[self.parms[i][1:]] = u'"' + cp + u'"'
       
   265                     else:
       
   266                         pointers[self.parms[i][1:]] = u"'" + cp + u"'"
       
   267                 elif self.parms[i][0] == "%":
       
   268                     macros[self.parms[i]] = u(cp)
       
   269                 else:
       
   270                     resultParms[self.parms[i]] = cp
       
   271             else:
       
   272                 extraContent += u(cp)
       
   273                 hasContent = True
       
   274             i += 1
       
   275         result = u""
       
   276         for p, v in resultParms.iteritems():
       
   277             if p[0] == "'" or p[0] == '"':
       
   278                 p = eval(p)
       
   279             result += u" "+ p + u"=" + quoteattr(applyMacros(macros, u(v)))
       
   280         if hasContent:
       
   281             if avoidTag:
       
   282                 return True, strRepl(extraContent)
       
   283             else:
       
   284                 return True, u"<" + self.alias + result + u">" + strRepl(extraContent)
       
   285         else:
       
   286             if avoidTag:
       
   287                 return False, u""
       
   288             else:
       
   289                 return False, u"<" + self.alias + result + u"/>"
       
   290 
       
   291 def replaceContent(tree, subtree):
       
   292     n = 0
       
   293     while n < len(tree):
       
   294         obj = tree[n]
       
   295         if obj[0] == "func":
       
   296             l = obj[1]
       
   297             if l[0] == "content":
       
   298                 d = 1
       
   299                 if subtree:
       
   300                     for el in subtree:
       
   301                         tree.insert(n+d, el)
       
   302                         d += 1
       
   303                 del tree[n]
       
   304                 n += d
       
   305             else:
       
   306                 try:
       
   307                     if l[-1][0] == "content":
       
   308                         replaceContent(l[-1][1], subtree)
       
   309                 except: pass
       
   310         elif obj[0] == "funclist":
       
   311             replaceContent(obj[1], subtree)
       
   312         n += 1
       
   313     return tree
       
   314 
       
   315 def executeCmd(text):
       
   316     if type(text) is not unicode:
       
   317         text = codecs.decode(text, encoding)
       
   318     for (regex, pattern) in operator:
       
   319         match = re.search(regex, text)
       
   320         while match:
       
   321             cmd = pattern
       
   322             opt = match.groups()
       
   323             for i in range(len(opt)):
       
   324                 cmd = cmd.replace(u"%" + u(i+1), opt[i])
       
   325             text = text[:match.start()] + u"`" + cmd + u"`"+ text[match.end():]
       
   326             match = re.search(regex, text)
       
   327 
       
   328     result = u""
       
   329     m = re.search(bq, text)
       
   330     while text and m:
       
   331         cmd  = m.group(1)
       
   332         head = textOut(text[:m.start()])
       
   333         text = text[m.end():]
       
   334         try:
       
   335             r, rest = parseLine(cmd, _inner, [], True, comment)
       
   336             if rest: raise SyntaxError(cmd)
       
   337         except SyntaxError:
       
   338             if included:
       
   339                 raise SyntaxError(u"in " + included + u":" + u(line) + u": syntax error in executing command: " + cmd.strip())
       
   340             else:
       
   341                 raise SyntaxError(u"in " + u(line) + u": syntax error in executing command: " + cmd.strip())
       
   342         inner = _finish(r)
       
   343         result += head + inner
       
   344         m = re.search(bq, text)
       
   345     result += textOut(text)
       
   346 
       
   347     return result
       
   348 
       
   349 def codegen(obj):
       
   350     global in_ns, pointers, line, included
       
   351     ctype = obj[0]
       
   352 
       
   353     if type(obj) is code:
       
   354         return obj
       
   355 
       
   356     try:
       
   357         if ctype.line: line = ctype.line
       
   358     except: pass
       
   359 
       
   360     if ctype == "empty":
       
   361         return code(u"")
       
   362 
       
   363     if ctype == "in_ns":
       
   364         in_ns = obj[1][0]
       
   365         subtree = obj[1]
       
   366         for sel in subtree:
       
   367             codegen(sel)
       
   368         in_ns = u""
       
   369         return code(u"")
       
   370 
       
   371     elif ctype == "decl":
       
   372         name = u""
       
   373         for data in obj[1]:
       
   374             if type(data) is unicode or type(data) is str:
       
   375                 name = data
       
   376                 try:
       
   377                     yf = ymlFunc[name]
       
   378                     yf.alias
       
   379                 except:
       
   380                     ymlFunc[name] = YF(name)
       
   381                     yf = ymlFunc[name]
       
   382                     if in_ns:
       
   383                         yf.alias = in_ns + u":" + name
       
   384                         if not enable_tracing:
       
   385                             if in_ns == "xsl" and (name == "debug" or name=="assert" or name[:7]=="_trace_"):
       
   386                                 yf.alias = "-"
       
   387                                 yf.addParm("skip1")
       
   388                                 yf.addParm("skip2")
       
   389                                 break
       
   390             elif type(data) is tuple or type(data) is Symbol:
       
   391                 if data[0] == "base":
       
   392                     base = data[1][0]
       
   393                     try:
       
   394                         yf = ymlFunc[name] = ymlFunc[base].copy(name)
       
   395                     except KeyError:
       
   396                         if included:
       
   397                             raise KeyError(u"in " + included + u":" + u(line) + u": " + base + u" as base for " + name)
       
   398                         else:
       
   399                             raise KeyError(u"in " + u(line) + u": " + base + u" as base for " + name)
       
   400                 elif data[0] == "shape":
       
   401                     shape = ymlFunc[data[1]]
       
   402                     try:
       
   403                         yf = ymlFunc[name]
       
   404                         yf.patch(shape)
       
   405                     except KeyError:
       
   406                         if included:
       
   407                             raise KeyError(u"in " + included + u":" + u(line) + u": " + base + u" as shape for " + name)
       
   408                         else:
       
   409                             raise KeyError(u"in " + u(line) + u": " + base + u" as shape for " + name)
       
   410                 elif data[0] == "descend":
       
   411                     yf.addDescend(data[1])
       
   412                 elif data[0] == "declParm":
       
   413                     l = data[1]
       
   414                     parmName = l[0]
       
   415                     if len(l)==1:
       
   416                         yf.addParm(parmName)
       
   417                     else:
       
   418                         value = l[1]
       
   419                         if parmName[0] != "%":
       
   420                             yf.addValue(parmName, value)
       
   421                         if parmName[0] == "*":
       
   422                             yf.pointers[parmName[1:]] = value
       
   423                             yf.addParm(parmName)
       
   424                         elif parmName[0] == "%":
       
   425                             if type(value) is unicode or type(value) is str:
       
   426                                 yf.macros[parmName] = u(evalPython(value))
       
   427                             else:
       
   428                                 yf.macros[parmName] = u(evalPython(u(value)))
       
   429                             yf.addParm(parmName)
       
   430                 elif data[0] == "alias":
       
   431                     if in_ns:
       
   432                         yf.alias = in_ns + u":" + data[1][0]
       
   433                     else:
       
   434                         yf.alias = data[1][0]
       
   435                 elif data[0] == "content":
       
   436                     yf.content = data[1]
       
   437 
       
   438         return code(u"")
       
   439 
       
   440     elif ctype == "funclist":
       
   441         result = u""
       
   442         for f in obj[1]:
       
   443             result += codegen(f)
       
   444         return code(result)
       
   445 
       
   446     elif ctype == "parentheses":
       
   447         if len(obj[1]):
       
   448             return codegen(('func', ['_parentheses', ('content', [obj[1][0]])]))
       
   449         else:
       
   450             return u""
       
   451 
       
   452     elif ctype == "fparm":
       
   453         if len(obj[1]):
       
   454             return codegen(('func', ['_parm', ('content', [obj[1][0]])]))
       
   455         else:
       
   456             return u""
       
   457 
       
   458     elif ctype == "generic":
       
   459         return codegen(('func', ['_generic', ('content', [obj[1][0]])]))
       
   460 
       
   461     elif ctype == "xbase":
       
   462         return codegen(('func', ['_base', ('content', [obj[1][0]])]))
       
   463 
       
   464     elif ctype == "func":
       
   465         avoidTag = False
       
   466         name = obj[1][0]
       
   467 
       
   468         if name == "decl":
       
   469             if ymlFunc[name] == "#error":
       
   470                 if included:
       
   471                     raise SyntaxError(u"in " + included + u":" + u(line) + u": syntax error in decl statement")
       
   472                 else:
       
   473                     raise SyntaxError(u"in " + u(line) + u": syntax error in decl statement")
       
   474         if name == "define" or name == "operator":
       
   475             if ymlFunc[name] == "#error":
       
   476                 if included:
       
   477                     raise SyntaxError(u"in " + included + u":" + u(line) + u": syntax error in define statement")
       
   478                 else:
       
   479                     raise SyntaxError(u"in " + u(line) + u": syntax error in define statement")
       
   480 
       
   481         if name[0] == "&":
       
   482             avoidTag = True
       
   483             name = name[1:]
       
   484         hasContent = False
       
   485 
       
   486         if len(name) > 2:
       
   487             if name[0:2] == "**":
       
   488                 return code(eval('u'+pointer(name[1:])))
       
   489 
       
   490         if name[0] == "*":
       
   491             name = eval(pointer(name))
       
   492             if name[0] == "&":
       
   493                 avoidTag = True
       
   494                 name = name[1:]
       
   495 
       
   496         try:
       
   497             ymlFunc[name]
       
   498         except:
       
   499             try:
       
   500                 ymlFunc["_"]
       
   501                 return codegen(('func', ['_', ('content', [('funclist', [obj])])]))
       
   502             except:
       
   503                 ymlFunc[name] = YF(name)
       
   504         
       
   505         if ymlFunc[name].alias == "-": avoidTag = True
       
   506 
       
   507         to_add = []
       
   508         if len(ymlFunc[name].descends):
       
   509             if obj[1][-1][0] != 'content':
       
   510                 if included:
       
   511                     raise KeyError(u"in " + included + u":" + u(line) + u": " + name + u" has descending attributes, but no descendants are following")
       
   512                 else:
       
   513                     raise KeyError(u"in " + u(line) + u": " + name + u" has descending attributes, but no descendants are following")
       
   514 
       
   515             def first_func(obj):
       
   516                 if type(obj) is tuple or type(obj) is Symbol:
       
   517                     if obj[0] == 'func':
       
   518                         return obj
       
   519                     elif obj[0] == 'funclist':
       
   520                         return first_func(obj[1])
       
   521                     elif obj[0] == 'content':
       
   522                         return first_func(obj[1])
       
   523                     else:
       
   524                         return None
       
   525                 elif type(obj) == list:
       
   526                     for e in obj:
       
   527                         f = first_func(e)
       
   528                         if f: return f
       
   529                     return None
       
   530 
       
   531             def copy_without_first_func(o, found = False):
       
   532                 c = []
       
   533                 for obj in o:
       
   534                     if found:
       
   535                         c.append(obj)
       
   536                     else:
       
   537                         if obj[0] == 'func':
       
   538                             if obj[1][-1][0] == 'content':
       
   539                                 c.extend( obj[1][-1][1] )
       
   540                             found = True
       
   541                         else:
       
   542                             c.append( ( obj[0], copy_without_first_func(obj[1], False ) ) )
       
   543                 return c
       
   544 
       
   545             def get_parms(obj):
       
   546                 result = []
       
   547                 for e in obj[1]:
       
   548                     if type(e) is tuple or type(e) is Symbol:
       
   549                         if e[0] == "parm":
       
   550                             result.append( e )
       
   551                 return result
       
   552 
       
   553             try:
       
   554                 add_params = get_parms(obj)
       
   555                 for e in obj[1][-1][1]:
       
   556                     c = e[1]
       
   557                     for dname in ymlFunc[name].descends:
       
   558                         f, c = first_func(c), copy_without_first_func(c)
       
   559                         if dname[0] == "*":
       
   560                             pointers[dname[1:]] = "'" + f[1][0] + "'"
       
   561                         else:
       
   562                             add_params.append( ('parm', [dname, u"'" + f[1][0] + u"'"]) )
       
   563                         try:
       
   564                             add_params.extend( get_parms(f) )
       
   565                         except: pass
       
   566 
       
   567                     new_things = [ e[1][0] ]
       
   568                     new_things.extend( add_params )
       
   569                     new_things.append( ('content', c) )
       
   570                     
       
   571                     to_add.append( ('func', new_things ) )
       
   572             except:
       
   573                 if included:
       
   574                     raise KeyError(u"in " + included + u":" + u(line) + u": " + name + u" has descending attributes, and too less descendants are following")
       
   575                 else:
       
   576                     raise KeyError(u"in " + u(line) + u": " + name + u" has descending attributes, and too less descendants are following")
       
   577 
       
   578         if not to_add:
       
   579             to_add = ( obj, )
       
   580 
       
   581         complete = u""
       
   582 
       
   583         for obj in to_add:
       
   584             subtree = None
       
   585             try:
       
   586                 if obj[1][-1][0] == "content":
       
   587                     subtree = obj[1][-1][1]
       
   588             except: pass
       
   589      
       
   590             if ymlFunc[name].content:
       
   591                 hasContent = True
       
   592                 treetemplate = deepcopy(ymlFunc[name].content)
       
   593                 subtree = replaceContent(treetemplate, subtree)
       
   594 
       
   595             if subtree:
       
   596                 hasContent = True
       
   597 
       
   598             hasContent, result = ymlFunc[name](obj[1], hasContent, avoidTag)
       
   599 
       
   600             if subtree:
       
   601                 for sel in subtree:
       
   602                     result += codegen(sel)
       
   603 
       
   604             if hasContent and not(avoidTag):
       
   605                 result += u"</" + ymlFunc[name].alias + u">"
       
   606 
       
   607             complete += result
       
   608 
       
   609         return code(complete)
       
   610 
       
   611     elif ctype == "textsection":
       
   612         result = u''
       
   613         ll = obj[1].splitlines()
       
   614         space = len(ll[-1]) - 2
       
   615         for l in ll[1:-1]:
       
   616             m = re.match(bqq, l)
       
   617             if m:
       
   618                 cmd = m.group(1)
       
   619                 try:
       
   620                     r, x = parseLine(cmd, _inner, [], True, comment)
       
   621                     if x: raise SyntaxError(cmd)
       
   622                     result += _finish(r)
       
   623                 except SyntaxError:
       
   624                     if included:
       
   625                         raise SyntaxError(u"in " + included + u":" + u(line) + u": syntax error in executing command: " + cmd.strip())
       
   626                     else:
       
   627                         raise SyntaxError(u"in " + u(line) + u": syntax error in executing command: " + cmd.strip())
       
   628             else:
       
   629                 result += codegen(Symbol(u'lineQuote', u'| ' + l[space:]))
       
   630         return code(result)
       
   631 
       
   632     elif ctype == "textsectionu":
       
   633         result = u''
       
   634         ll = obj[1].splitlines()
       
   635         space = len(ll[-1]) - 2
       
   636         for l in ll[1:-1]:
       
   637             m = re.match(bqq, l)
       
   638             if m:
       
   639                 cmd = m.group(1)
       
   640                 try:
       
   641                     r, x = parseLine(cmd, _inner, [], True, comment)
       
   642                     if x: raise SyntaxError(cmd)
       
   643                     result += _finish(r)
       
   644                 except SyntaxError:
       
   645                     if included:
       
   646                         raise SyntaxError(u"in " + included + u":" + u(line) + u": syntax error in executing command: " + cmd.strip())
       
   647                     else:
       
   648                         raise SyntaxError(u"in " + u(line) + u": syntax error in executing command: " + cmd.strip())
       
   649             else:
       
   650                 if result != u'': result += u' '
       
   651                 result += codegen(Symbol(u'quote', [u'> ' + l[space:]]))
       
   652         return code(result)
       
   653 
       
   654     elif ctype == "lineQuote" or ctype == "quote":
       
   655         m, text, base, inds = None, u"", 0, 0
       
   656 
       
   657         if ctype == "lineQuote":
       
   658             text = obj[1]
       
   659             m = lq.match(text)
       
   660             if m:
       
   661                 inds = len(m.group(1))
       
   662                 text = m.group(2)[1:]
       
   663             else: inds = 0
       
   664         elif ctype == "quote":
       
   665             inds = -1
       
   666             text = obj[1][0]
       
   667             m = sq.match(text)
       
   668             if m:
       
   669                 if m.group(1):
       
   670                     inds = int(m.group(1))
       
   671                 text = m.group(2)[1:]
       
   672             else:
       
   673                 if type(text) is unicode or type(text) is str:
       
   674                     text = u(evalPython(text))
       
   675 
       
   676         ind = u""
       
   677         if inds > -1:
       
   678             try:
       
   679                 cmd = evalPython(u"indent(" + u(inds) + u")")
       
   680                 result, rest = parseLine(u(cmd), _inner, [], True, comment)
       
   681                 if rest:
       
   682                     raise SyntaxError()
       
   683                 ind = _finish(result)
       
   684             except: pass
       
   685         
       
   686         if ctype == "lineQuote": text += u"\n"
       
   687 
       
   688         hasTextFunc = False
       
   689         try:
       
   690             ymlFunc["text"]
       
   691             hasTextFunc = True
       
   692         except: pass
       
   693 
       
   694         text = executeCmd(text)
       
   695         return code(ind + text) 
       
   696 
       
   697     elif ctype == "tagQuote":
       
   698         m = tq.match(obj[1])
       
   699         if m.group(1) == "<":
       
   700             return code(u"<" + m.group(2))
       
   701         else:
       
   702             return code(m.group(2))
       
   703 
       
   704     elif ctype == "operator":
       
   705         operator.append((re.compile(evalPython(obj[1][0])), obj[1][1]))
       
   706         return code(u"")
       
   707 
       
   708     elif ctype == "constant":
       
   709         name = obj[1][0]
       
   710         if name[0] == "*":
       
   711             name = name[1:]
       
   712         value = obj[1][1]
       
   713         pointers[name] = value
       
   714         return code(u"")
       
   715 
       
   716     elif ctype == "include":
       
   717         reverse = False
       
   718         ktext, kxml = False, False
       
   719         for arg in obj[1]:
       
   720             if type(arg) is tuple or type(arg) is Symbol:
       
   721                 if arg[0] == "reverse":
       
   722                     reverse = True
       
   723                 elif arg[0] == "ktext":
       
   724                     ktext = True
       
   725                 elif arg[0] == "kxml":
       
   726                     kxml = True
       
   727             elif type(arg) is unicode or type(arg) is str:
       
   728                 filemask = arg
       
   729 
       
   730         if filemask[0] == '/' or filemask[0] == '.':
       
   731             files = sorted(glob(filemask))
       
   732         else:
       
   733             files = []
       
   734             for directory in includePath:
       
   735                 path = os.path.join(directory, filemask)
       
   736                 files.extend(sorted(glob(path)))
       
   737 
       
   738         if files and reverse:
       
   739             files = files[-1::-1]
       
   740 
       
   741         if not(files):
       
   742             if included:
       
   743                 raise IOError(u"in " + included + ":" + u(line) + u": include file(s) '" + filemask + u"' not found")
       
   744             else:
       
   745                 raise IOError(u"in " + u(line) + u": include file(s) '" + filemask + u"' not found")
       
   746 
       
   747         includeFile = fileinput.input(files, mode="rU", openhook=fileinput.hook_encoded(encoding))
       
   748         _included = included
       
   749         if ktext or kxml:
       
   750             text = u""
       
   751             for line in includeFile:
       
   752                 included = includeFile.filename()
       
   753                 if kxml:
       
   754                     if (not line[:6] == '<?xml ') and (not line[:6] == '<?XML '):
       
   755                         text += line
       
   756                 else:
       
   757                     text += executeCmd(line)
       
   758             included = _included
       
   759             return code(text)
       
   760         else:
       
   761             result = parse(ymlCStyle(), includeFile, True, comment)
       
   762             included = u(filemask)
       
   763             x = _finish(result)
       
   764             included = _included
       
   765             return code(x)
       
   766 
       
   767     elif ctype == "pyExp":
       
   768         exp = obj[1][0]
       
   769         cmd = evalPython(exp)
       
   770         result, rest = parseLine(u(cmd), _inner, [], True, comment)
       
   771         if rest:
       
   772             raise SyntaxError(cmd)
       
   773         return code(_finish(result))
       
   774 
       
   775     elif ctype == "pythonCall":
       
   776         parms = []
       
   777         data = obj[1]
       
   778         for p in data:
       
   779             if type(p) is unicode or type(p) is str:
       
   780                 name = p
       
   781             elif type(p) is tuple or type(p) is Symbol:
       
   782                 ptype = p[0]
       
   783                 if ptype == "parm":
       
   784                     if p[1][0][0] == "*":
       
   785                         parms.append(pointer(p[1][0]))
       
   786                     else:
       
   787                         parms.append(p[1][0])
       
   788         if len(parms) == 0:
       
   789             exp = name + u"()"
       
   790         elif len(parms) == 1:
       
   791             exp = name + u"(" + u(parms[0]) + u")"
       
   792         else:
       
   793             exp = name + u(tuple(parms))
       
   794         cmd = evalPython(exp)
       
   795         result, rest = parseLine(u(cmd), _inner, [], True, comment)
       
   796         if rest:
       
   797             raise SyntaxError()
       
   798         return code(_finish(result))
       
   799 
       
   800     else:
       
   801         return code(u"")
       
   802 
       
   803 def _finish(tree):
       
   804     result = u""
       
   805     python = u""
       
   806 
       
   807     for el in tree:
       
   808         if el[0] == "python":
       
   809             if el[1][0][:2] == "!!":
       
   810                 python += el[1][0][2:-2]
       
   811             else:
       
   812                 python += el[1][0][1:] + u"\n"
       
   813             continue
       
   814         else:
       
   815             if python:
       
   816                 execPython(python)
       
   817                 python = u""
       
   818 
       
   819         try:
       
   820             result += codegen(el)
       
   821         except RuntimeError:
       
   822             if included:
       
   823                 raise RuntimeError(u"in " + included + u":" + u(line))
       
   824             else:
       
   825                 raise RuntimeError(u"in " + u(line))
       
   826 
       
   827     if python:
       
   828         execPython(python)
       
   829 
       
   830     return result
       
   831 
       
   832 def finish(tree):
       
   833     global first
       
   834     first = True
       
   835     return _finish(tree)
       
   836 
       
   837 ymlFunc["_parentheses"] = YF("parms")
       
   838 ymlFunc["_parm"] = YF("parm")
       
   839 ymlFunc["_generic"] = YF("generic")
       
   840 ymlFunc["_base"] = YF("base")