backend.py
changeset 0 76005e62091d
child 14 d937e9d7c4fe
equal deleted inserted replaced
-1:000000000000 0:76005e62091d
       
     1 # 2.5.0 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             self.values[parm] = u(evalPython(value))
       
   236         else:
       
   237             self.values[parm] = u(evalPython(u(value)))
       
   238 
       
   239     def xml(self, callParms, callValues, hasContent, avoidTag = False):
       
   240         global pointers
       
   241         extraContent = u""
       
   242         if self.content:
       
   243             hasContent = True
       
   244         resultParms = self.values.copy()
       
   245         macros = self.macros.copy()
       
   246         toDelete = resultParms.keys()
       
   247         for key in toDelete:
       
   248             if key[0] == "*":
       
   249                 del resultParms[key]
       
   250         for key, value in callValues.iteritems():
       
   251             if key[0] == "%":
       
   252                 macros[key] = value
       
   253             else:
       
   254                 resultParms[key] = value
       
   255         i = 0
       
   256         for cp in callParms:
       
   257             if i < len(self.parms):
       
   258                 if self.parms[i][0] == "*":
       
   259                     cp = u(cp)
       
   260                     if "'" in cp:
       
   261                         pointers[self.parms[i][1:]] = u'"' + cp + u'"'
       
   262                     else:
       
   263                         pointers[self.parms[i][1:]] = u"'" + cp + u"'"
       
   264                 elif self.parms[i][0] == "%":
       
   265                     macros[self.parms[i]] = u(cp)
       
   266                 else:
       
   267                     resultParms[self.parms[i]] = cp
       
   268             else:
       
   269                 extraContent += u(cp)
       
   270                 hasContent = True
       
   271             i += 1
       
   272         result = u""
       
   273         for p, v in resultParms.iteritems():
       
   274             if p[0] == "'" or p[0] == '"':
       
   275                 p = eval(p)
       
   276             result += u" "+ p + u"=" + quoteattr(applyMacros(macros, u(v)))
       
   277         if hasContent:
       
   278             if avoidTag:
       
   279                 return True, strRepl(extraContent)
       
   280             else:
       
   281                 return True, u"<" + self.alias + result + u">" + strRepl(extraContent)
       
   282         else:
       
   283             if avoidTag:
       
   284                 return False, u""
       
   285             else:
       
   286                 return False, u"<" + self.alias + result + u"/>"
       
   287 
       
   288 def replaceContent(tree, subtree):
       
   289     n = 0
       
   290     while n < len(tree):
       
   291         obj = tree[n]
       
   292         if obj[0] == "func":
       
   293             l = obj[1]
       
   294             if l[0] == "content":
       
   295                 d = 1
       
   296                 if subtree:
       
   297                     for el in subtree:
       
   298                         tree.insert(n+d, el)
       
   299                         d += 1
       
   300                 del tree[n]
       
   301                 n += d
       
   302             else:
       
   303                 try:
       
   304                     if l[-1][0] == "content":
       
   305                         replaceContent(l[-1][1], subtree)
       
   306                 except: pass
       
   307         elif obj[0] == "funclist":
       
   308             replaceContent(obj[1], subtree)
       
   309         n += 1
       
   310     return tree
       
   311 
       
   312 def executeCmd(text):
       
   313     if type(text) is not unicode:
       
   314         text = codecs.decode(text, encoding)
       
   315     for (regex, pattern) in operator:
       
   316         match = re.search(regex, text)
       
   317         while match:
       
   318             cmd = pattern
       
   319             opt = match.groups()
       
   320             for i in range(len(opt)):
       
   321                 cmd = cmd.replace(u"%" + u(i+1), opt[i])
       
   322             text = text[:match.start()] + u"`" + cmd + u"`"+ text[match.end():]
       
   323             match = re.search(regex, text)
       
   324 
       
   325     result = u""
       
   326     m = re.search(bq, text)
       
   327     while text and m:
       
   328         cmd  = m.group(1)
       
   329         head = textOut(text[:m.start()])
       
   330         text = text[m.end():]
       
   331         try:
       
   332             r, rest = parseLine(cmd, _inner, [], True, comment)
       
   333             if rest: raise SyntaxError(cmd)
       
   334         except SyntaxError:
       
   335             if included:
       
   336                 raise SyntaxError(u"in " + included + u":" + u(line) + u": syntax error in executing command: " + cmd.strip())
       
   337             else:
       
   338                 raise SyntaxError(u"in " + u(line) + u": syntax error in executing command: " + cmd.strip())
       
   339         inner = _finish(r)
       
   340         result += head + inner
       
   341         m = re.search(bq, text)
       
   342     result += textOut(text)
       
   343 
       
   344     return result
       
   345 
       
   346 def codegen(obj):
       
   347     global in_ns, pointers, line, included
       
   348     ctype = obj[0]
       
   349 
       
   350     if type(obj) is code:
       
   351         return obj
       
   352 
       
   353     try:
       
   354         if ctype.line: line = ctype.line
       
   355     except: pass
       
   356 
       
   357     if ctype == "empty":
       
   358         return code(u"")
       
   359 
       
   360     if ctype == "in_ns":
       
   361         in_ns = obj[1][0]
       
   362         subtree = obj[1]
       
   363         for sel in subtree:
       
   364             codegen(sel)
       
   365         in_ns = u""
       
   366         return code(u"")
       
   367 
       
   368     elif ctype == "decl":
       
   369         name = u""
       
   370         for data in obj[1]:
       
   371             if type(data) is unicode or type(data) is str:
       
   372                 name = data
       
   373                 try:
       
   374                     yf = ymlFunc[name]
       
   375                     yf.alias
       
   376                 except:
       
   377                     ymlFunc[name] = YF(name)
       
   378                     yf = ymlFunc[name]
       
   379                     if in_ns:
       
   380                         yf.alias = in_ns + u":" + name
       
   381                         if not enable_tracing:
       
   382                             if in_ns == "xsl" and (name == "debug" or name=="assert" or name[:7]=="_trace_"):
       
   383                                 yf.alias = "-"
       
   384                                 yf.addParm("skip1")
       
   385                                 yf.addParm("skip2")
       
   386                                 break
       
   387             elif type(data) is tuple or type(data) is Symbol:
       
   388                 if data[0] == "base":
       
   389                     base = data[1][0]
       
   390                     try:
       
   391                         yf = ymlFunc[name] = ymlFunc[base].copy(name)
       
   392                     except KeyError:
       
   393                         if included:
       
   394                             raise KeyError(u"in " + included + u":" + u(line) + u": " + base + u" as base for " + name)
       
   395                         else:
       
   396                             raise KeyError(u"in " + u(line) + u": " + base + u" as base for " + name)
       
   397                 elif data[0] == "shape":
       
   398                     shape = ymlFunc[data[1]]
       
   399                     try:
       
   400                         yf = ymlFunc[name]
       
   401                         yf.patch(shape)
       
   402                     except KeyError:
       
   403                         if included:
       
   404                             raise KeyError(u"in " + included + u":" + u(line) + u": " + base + u" as shape for " + name)
       
   405                         else:
       
   406                             raise KeyError(u"in " + u(line) + u": " + base + u" as shape for " + name)
       
   407                 elif data[0] == "descend":
       
   408                     yf.addDescend(data[1])
       
   409                 elif data[0] == "declParm":
       
   410                     l = data[1]
       
   411                     parmName = l[0]
       
   412                     if len(l)==1:
       
   413                         yf.addParm(parmName)
       
   414                     else:
       
   415                         value = l[1]
       
   416                         if parmName[0] != "%":
       
   417                             yf.addValue(parmName, value)
       
   418                         if parmName[0] == "*":
       
   419                             yf.pointers[parmName[1:]] = value
       
   420                             yf.addParm(parmName)
       
   421                         elif parmName[0] == "%":
       
   422                             if type(value) is unicode or type(value) is str:
       
   423                                 yf.macros[parmName] = u(evalPython(value))
       
   424                             else:
       
   425                                 yf.macros[parmName] = u(evalPython(u(value)))
       
   426                             yf.addParm(parmName)
       
   427                 elif data[0] == "alias":
       
   428                     if in_ns:
       
   429                         yf.alias = in_ns + u":" + data[1][0]
       
   430                     else:
       
   431                         yf.alias = data[1][0]
       
   432                 elif data[0] == "content":
       
   433                     yf.content = data[1]
       
   434 
       
   435         return code(u"")
       
   436 
       
   437     elif ctype == "funclist":
       
   438         result = u""
       
   439         for f in obj[1]:
       
   440             result += codegen(f)
       
   441         return code(result)
       
   442 
       
   443     elif ctype == "parentheses":
       
   444         if len(obj[1]):
       
   445             return codegen(('func', ['_parentheses', ('content', [obj[1][0]])]))
       
   446         else:
       
   447             return u""
       
   448 
       
   449     elif ctype == "fparm":
       
   450         if len(obj[1]):
       
   451             return codegen(('func', ['_parm', ('content', [obj[1][0]])]))
       
   452         else:
       
   453             return u""
       
   454 
       
   455     elif ctype == "generic":
       
   456         return codegen(('func', ['_generic', ('content', [obj[1][0]])]))
       
   457 
       
   458     elif ctype == "xbase":
       
   459         return codegen(('func', ['_base', ('content', [obj[1][0]])]))
       
   460 
       
   461     elif ctype == "func":
       
   462         avoidTag = False
       
   463         name = obj[1][0]
       
   464 
       
   465         if name == "decl":
       
   466             if ymlFunc[name] == "#error":
       
   467                 if included:
       
   468                     raise SyntaxError(u"in " + included + u":" + u(line) + u": syntax error in decl statement")
       
   469                 else:
       
   470                     raise SyntaxError(u"in " + u(line) + u": syntax error in decl statement")
       
   471         if name == "define" or name == "operator":
       
   472             if ymlFunc[name] == "#error":
       
   473                 if included:
       
   474                     raise SyntaxError(u"in " + included + u":" + u(line) + u": syntax error in define statement")
       
   475                 else:
       
   476                     raise SyntaxError(u"in " + u(line) + u": syntax error in define statement")
       
   477 
       
   478         if name[0] == "&":
       
   479             avoidTag = True
       
   480             name = name[1:]
       
   481         hasContent = False
       
   482 
       
   483         if len(name) > 2:
       
   484             if name[0:2] == "**":
       
   485                 return code(eval('u'+pointer(name[1:])))
       
   486 
       
   487         if name[0] == "*":
       
   488             name = eval(pointer(name))
       
   489             if name[0] == "&":
       
   490                 avoidTag = True
       
   491                 name = name[1:]
       
   492 
       
   493         try:
       
   494             ymlFunc[name]
       
   495         except:
       
   496             try:
       
   497                 ymlFunc["_"]
       
   498                 return codegen(('func', ['_', ('content', [('funclist', [obj])])]))
       
   499             except:
       
   500                 ymlFunc[name] = YF(name)
       
   501         
       
   502         if ymlFunc[name].alias == "-": avoidTag = True
       
   503 
       
   504         to_add = []
       
   505         if len(ymlFunc[name].descends):
       
   506             if obj[1][-1][0] != 'content':
       
   507                 if included:
       
   508                     raise KeyError(u"in " + included + u":" + u(line) + u": " + name + u" has descending attributes, but no descendants are following")
       
   509                 else:
       
   510                     raise KeyError(u"in " + u(line) + u": " + name + u" has descending attributes, but no descendants are following")
       
   511 
       
   512             def first_func(obj):
       
   513                 if type(obj) is tuple or type(obj) is Symbol:
       
   514                     if obj[0] == 'func':
       
   515                         return obj
       
   516                     elif obj[0] == 'funclist':
       
   517                         return first_func(obj[1])
       
   518                     elif obj[0] == 'content':
       
   519                         return first_func(obj[1])
       
   520                     else:
       
   521                         return None
       
   522                 elif type(obj) == list:
       
   523                     for e in obj:
       
   524                         f = first_func(e)
       
   525                         if f: return f
       
   526                     return None
       
   527 
       
   528             def copy_without_first_func(o, found = False):
       
   529                 c = []
       
   530                 for obj in o:
       
   531                     if found:
       
   532                         c.append(obj)
       
   533                     else:
       
   534                         if obj[0] == 'func':
       
   535                             if obj[1][-1][0] == 'content':
       
   536                                 c.extend( obj[1][-1][1] )
       
   537                             found = True
       
   538                         else:
       
   539                             c.append( ( obj[0], copy_without_first_func(obj[1], False ) ) )
       
   540                 return c
       
   541 
       
   542             def get_parms(obj):
       
   543                 result = []
       
   544                 for e in obj[1]:
       
   545                     if type(e) is tuple or type(e) is Symbol:
       
   546                         if e[0] == "parm":
       
   547                             result.append( e )
       
   548                 return result
       
   549 
       
   550             try:
       
   551                 add_params = get_parms(obj)
       
   552                 for e in obj[1][-1][1]:
       
   553                     c = e[1]
       
   554                     for dname in ymlFunc[name].descends:
       
   555                         f, c = first_func(c), copy_without_first_func(c)
       
   556                         if dname[0] == "*":
       
   557                             pointers[dname[1:]] = "'" + f[1][0] + "'"
       
   558                         else:
       
   559                             add_params.append( ('parm', [dname, u"'" + f[1][0] + u"'"]) )
       
   560                         try:
       
   561                             add_params.extend( get_parms(f) )
       
   562                         except: pass
       
   563 
       
   564                     new_things = [ e[1][0] ]
       
   565                     new_things.extend( add_params )
       
   566                     new_things.append( ('content', c) )
       
   567                     
       
   568                     to_add.append( ('func', new_things ) )
       
   569             except:
       
   570                 if included:
       
   571                     raise KeyError(u"in " + included + u":" + u(line) + u": " + name + u" has descending attributes, and too less descendants are following")
       
   572                 else:
       
   573                     raise KeyError(u"in " + u(line) + u": " + name + u" has descending attributes, and too less descendants are following")
       
   574 
       
   575         if not to_add:
       
   576             to_add = ( obj, )
       
   577 
       
   578         complete = u""
       
   579 
       
   580         for obj in to_add:
       
   581             subtree = None
       
   582             try:
       
   583                 if obj[1][-1][0] == "content":
       
   584                     subtree = obj[1][-1][1]
       
   585             except: pass
       
   586      
       
   587             if ymlFunc[name].content:
       
   588                 hasContent = True
       
   589                 treetemplate = deepcopy(ymlFunc[name].content)
       
   590                 subtree = replaceContent(treetemplate, subtree)
       
   591 
       
   592             if subtree:
       
   593                 hasContent = True
       
   594 
       
   595             hasContent, result = ymlFunc[name](obj[1], hasContent, avoidTag)
       
   596 
       
   597             if subtree:
       
   598                 for sel in subtree:
       
   599                     result += codegen(sel)
       
   600 
       
   601             if hasContent and not(avoidTag):
       
   602                 result += u"</" + ymlFunc[name].alias + u">"
       
   603 
       
   604             complete += result
       
   605 
       
   606         return code(complete)
       
   607 
       
   608     elif ctype == "textsection":
       
   609         result = u''
       
   610         ll = obj[1].splitlines()
       
   611         space = len(ll[-1]) - 2
       
   612         for l in ll[1:-1]:
       
   613             m = re.match(bqq, l)
       
   614             if m:
       
   615                 cmd = m.group(1)
       
   616                 try:
       
   617                     r, x = parseLine(cmd, _inner, [], True, comment)
       
   618                     if x: raise SyntaxError(cmd)
       
   619                     result += _finish(r)
       
   620                 except SyntaxError:
       
   621                     if included:
       
   622                         raise SyntaxError(u"in " + included + u":" + u(line) + u": syntax error in executing command: " + cmd.strip())
       
   623                     else:
       
   624                         raise SyntaxError(u"in " + u(line) + u": syntax error in executing command: " + cmd.strip())
       
   625             else:
       
   626                 result += codegen(Symbol(u'lineQuote', u'| ' + l[space:]))
       
   627         return code(result)
       
   628 
       
   629     elif ctype == "lineQuote" or ctype == "quote":
       
   630         m, text, base, inds = None, u"", 0, 0
       
   631 
       
   632         if ctype == "lineQuote":
       
   633             text = obj[1]
       
   634             m = lq.match(text)
       
   635             if m:
       
   636                 inds = len(m.group(1))
       
   637                 text = m.group(2)[1:]
       
   638             else: inds = 0
       
   639         elif ctype == "quote":
       
   640             inds = -1
       
   641             text = obj[1][0]
       
   642             m = sq.match(text)
       
   643             if m:
       
   644                 if m.group(1):
       
   645                     inds = int(m.group(1))
       
   646                 text = m.group(2)[1:]
       
   647             else:
       
   648                 if type(text) is unicode or type(text) is str:
       
   649                     text = u(evalPython(text))
       
   650 
       
   651         ind = u""
       
   652         if inds > -1:
       
   653             try:
       
   654                 cmd = evalPython(u"indent(" + u(inds) + u")")
       
   655                 result, rest = parseLine(u(cmd), _inner, [], True, comment)
       
   656                 if rest:
       
   657                     raise SyntaxError()
       
   658                 ind = _finish(result)
       
   659             except: pass
       
   660         
       
   661         if ctype == "lineQuote": text += u"\n"
       
   662 
       
   663         hasTextFunc = False
       
   664         try:
       
   665             ymlFunc["text"]
       
   666             hasTextFunc = True
       
   667         except: pass
       
   668 
       
   669         text = executeCmd(text)
       
   670         return code(ind + text) 
       
   671 
       
   672     elif ctype == "tagQuote":
       
   673         m = tq.match(obj[1])
       
   674         if m.group(1) == "<":
       
   675             return code(u"<" + m.group(2))
       
   676         else:
       
   677             return code(m.group(2))
       
   678 
       
   679     elif ctype == "operator":
       
   680         operator.append((re.compile(evalPython(obj[1][0])), obj[1][1]))
       
   681         return code(u"")
       
   682 
       
   683     elif ctype == "constant":
       
   684         name = obj[1][0]
       
   685         if name[0] == "*":
       
   686             name = name[1:]
       
   687         value = obj[1][1]
       
   688         pointers[name] = value
       
   689         return code(u"")
       
   690 
       
   691     elif ctype == "include":
       
   692         reverse = False
       
   693         ktext, kxml = False, False
       
   694         for arg in obj[1]:
       
   695             if type(arg) is tuple or type(arg) is Symbol:
       
   696                 if arg[0] == "reverse":
       
   697                     reverse = True
       
   698                 elif arg[0] == "ktext":
       
   699                     ktext = True
       
   700                 elif arg[0] == "kxml":
       
   701                     kxml = True
       
   702             elif type(arg) is unicode or type(arg) is str:
       
   703                 filemask = arg
       
   704 
       
   705         if filemask[0] == '/' or filemask[0] == '.':
       
   706             files = glob(filemask)
       
   707         else:
       
   708             files = []
       
   709             for directory in includePath:
       
   710                 path = os.path.join(directory, filemask)
       
   711                 files.extend(glob(path))
       
   712 
       
   713         if reverse:
       
   714             files = files[-1::-1]
       
   715 
       
   716         if not(files):
       
   717             if included:
       
   718                 raise IOError(u"in " + included + ":" + u(line) + u": include file(s) '" + filemask + u"' not found")
       
   719             else:
       
   720                 raise IOError(u"in " + u(line) + u": include file(s) '" + filemask + u"' not found")
       
   721 
       
   722         includeFile = fileinput.input(files, mode="rU", openhook=fileinput.hook_encoded(encoding))
       
   723         _included = included
       
   724         if ktext or kxml:
       
   725             text = u""
       
   726             for line in includeFile:
       
   727                 included = includeFile.filename()
       
   728                 if kxml:
       
   729                     if (not line[:6] == '<?xml ') and (not line[:6] == '<?XML '):
       
   730                         text += line
       
   731                 else:
       
   732                     text += executeCmd(line)
       
   733             included = _included
       
   734             return code(text)
       
   735         else:
       
   736             result = parse(ymlCStyle(), includeFile, True, comment)
       
   737             included = u(filemask)
       
   738             x = _finish(result)
       
   739             included = _included
       
   740             return code(x)
       
   741 
       
   742     elif ctype == "pyExp":
       
   743         exp = obj[1][0]
       
   744         cmd = evalPython(exp)
       
   745         result, rest = parseLine(u(cmd), _inner, [], True, comment)
       
   746         if rest:
       
   747             raise SyntaxError(cmd)
       
   748         return code(_finish(result))
       
   749 
       
   750     elif ctype == "pythonCall":
       
   751         parms = []
       
   752         data = obj[1]
       
   753         for p in data:
       
   754             if type(p) is unicode or type(p) is str:
       
   755                 name = p
       
   756             elif type(p) is tuple or type(p) is Symbol:
       
   757                 ptype = p[0]
       
   758                 if ptype == "parm":
       
   759                     if p[1][0][0] == "*":
       
   760                         parms.append(pointer(p[1][0]))
       
   761                     else:
       
   762                         parms.append(p[1][0])
       
   763         if len(parms) == 0:
       
   764             exp = name + u"()"
       
   765         elif len(parms) == 1:
       
   766             exp = name + u"(" + u(parms[0]) + u")"
       
   767         else:
       
   768             exp = name + u(tuple(parms))
       
   769         cmd = evalPython(exp)
       
   770         result, rest = parseLine(u(cmd), _inner, [], True, comment)
       
   771         if rest:
       
   772             raise SyntaxError()
       
   773         return code(_finish(result))
       
   774 
       
   775     else:
       
   776         return code(u"")
       
   777 
       
   778 def _finish(tree):
       
   779     result = u""
       
   780     python = u""
       
   781 
       
   782     for el in tree:
       
   783         if el[0] == "python":
       
   784             if el[1][0][:2] == "!!":
       
   785                 python += el[1][0][2:-2]
       
   786             else:
       
   787                 python += el[1][0][1:] + u"\n"
       
   788             continue
       
   789         else:
       
   790             if python:
       
   791                 execPython(python)
       
   792                 python = u""
       
   793 
       
   794         try:
       
   795             result += codegen(el)
       
   796         except RuntimeError:
       
   797             if included:
       
   798                 raise RuntimeError(u"in " + included + u":" + u(line))
       
   799             else:
       
   800                 raise RuntimeError(u"in " + u(line))
       
   801 
       
   802     if python:
       
   803         execPython(python)
       
   804 
       
   805     return result
       
   806 
       
   807 def finish(tree):
       
   808     global first
       
   809     first = True
       
   810     return _finish(tree)
       
   811 
       
   812 ymlFunc["_parentheses"] = YF("parms")
       
   813 ymlFunc["_parm"] = YF("parm")
       
   814 ymlFunc["_generic"] = YF("generic")
       
   815 ymlFunc["_base"] = YF("base")