yml2/backend.py
changeset 41 98a53c3282c3
child 65 d659b8c2ed22
child 72 e52ee17bca47
equal deleted inserted replaced
40:432ab62b2537 41:98a53c3282c3
       
     1 # 2.6.1 backend
       
     2 
       
     3 # written by VB.
       
     4 
       
     5 import re, codecs
       
     6 import fileinput
       
     7 import sys, traceback, os
       
     8 from xml.sax.saxutils import escape, quoteattr
       
     9 from copy import copy, deepcopy
       
    10 from glob import glob
       
    11 from .pyPEG import code, parse, parseLine, u, Symbol
       
    12 from . import ymlCStyle, comment, _inner
       
    13 
       
    14 ymlFunc, pointers, pythonFunc = {}, {}, {}
       
    15 in_ns = ""
       
    16 operator = []
       
    17 included = ""
       
    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 = ""
       
    33     operator = []
       
    34     included = ""
       
    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 '""'
       
    52         if included:
       
    53             raise LookupError("in " + included + ":" + u(line) + ": pointer " + name)
       
    54         else:
       
    55             raise LookupError("in " + u(line) + ": pointer " + name)
       
    56 
       
    57 def evalPython(expr):
       
    58     try:
       
    59         result = eval(u(expr), pythonFunc)
       
    60         if type(result) is bytes:
       
    61             return codecs.decode(result, encoding)
       
    62         else:
       
    63             return result
       
    64     except:
       
    65         name, parm, tb = sys.exc_info()
       
    66         msg = "in python expression: " + u(parm)
       
    67         if name is SyntaxError:
       
    68             tbl = traceback.format_exception(name, parm, tb)
       
    69             msg += "\n" + tbl[-3] + tbl[-2]
       
    70         else:
       
    71             msg += ": " + expr + "\n"
       
    72         if included:
       
    73             raise name("in " + included + ":" + u(line) + ": " + msg)
       
    74         else:
       
    75             raise name("in " + u(line) + ": " + msg)
       
    76     
       
    77 def execPython(script):
       
    78     try:
       
    79         if type(script) is str:
       
    80             exec(script, pythonFunc)
       
    81         else:
       
    82             exec(codecs.decode(script, encoding), pythonFunc)
       
    83     except:
       
    84         name, parm, tb = sys.exc_info()
       
    85         msg = "in python script: " + u(parm)
       
    86         if name is SyntaxError:
       
    87             tbl = traceback.format_exception(name, parm, tb)
       
    88             msg += "\n" + tbl[-3] + tbl[-2]
       
    89         else:
       
    90             msg += ": " + expr + "\n"
       
    91         if included:
       
    92             raise name("in " + included + ":" + u(line) + ": " + msg)
       
    93         else:
       
    94             raise name("in " + u(line) + ": " + msg)
       
    95 
       
    96 def textOut(text):
       
    97     if not text:
       
    98         return ""
       
    99     if type(text) is not str:
       
   100         text = codecs.decode(text, encoding)
       
   101     text = text.replace(r'\"', r'\\"')
       
   102     text = '"""' + text.replace('"', r'\"') + '"""'
       
   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 str:
       
   109                 result += "</" + textFunc.alias + ">"
       
   110             else:
       
   111                 result += "</" + codecs.decode(textFunc.alias, encoding) + ">"
       
   112         return result
       
   113     except:
       
   114         return escape(eval(text))
       
   115 
       
   116 def strRepl(text):
       
   117     if not text:
       
   118         return ""
       
   119     if type(text) is not str:
       
   120         text = codecs.decode(text, encoding)
       
   121     text = text.replace(r'\"', r'\\"')
       
   122     text = '"""' + text.replace('"', r'\"') + '"""'
       
   123     if type(text) is str:
       
   124         return escape(eval(text))
       
   125 
       
   126 def applyMacros(macros, text):
       
   127     result = text
       
   128     for key, value in macros.items():
       
   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 + ":" + 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(vals)
       
   209             pointers["_trace_info"] = '"' + u(line) + ": " + u(self.name) + " " + text.replace('"', '#') + '"'
       
   210 
       
   211         if emitlinenumbers:
       
   212             global first
       
   213             if first:
       
   214                 vals["xmlns:yml"] = "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 str:
       
   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 = ""
       
   245         if self.content:
       
   246             hasContent = True
       
   247         resultParms = self.values.copy()
       
   248         macros = self.macros.copy()
       
   249         toDelete = [ key for key in resultParms.keys() ]
       
   250         for key in toDelete:
       
   251             if key[0] == "*":
       
   252                 del resultParms[key]
       
   253         for key, value in callValues.items():
       
   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:]] = '"' + cp + '"'
       
   265                     else:
       
   266                         pointers[self.parms[i][1:]] = "'" + cp + "'"
       
   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 = ""
       
   276         for p, v in resultParms.items():
       
   277             if p[0] == "'" or p[0] == '"':
       
   278                 p = eval(p)
       
   279             result += " "+ p + "=" + quoteattr(applyMacros(macros, u(v)))
       
   280         if hasContent:
       
   281             if avoidTag:
       
   282                 return True, strRepl(extraContent)
       
   283             else:
       
   284                 return True, "<" + self.alias + result + ">" + strRepl(extraContent)
       
   285         else:
       
   286             if avoidTag:
       
   287                 return False, ""
       
   288             else:
       
   289                 return False, "<" + self.alias + result + "/>"
       
   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 str:
       
   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(i+1), opt[i])
       
   325             text = text[:match.start()] + "`" + cmd + "`"+ text[match.end():]
       
   326             match = re.search(regex, text)
       
   327 
       
   328     result = ""
       
   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("in " + included + ":" + u(line) + ": syntax error in executing command: " + cmd.strip())
       
   340             else:
       
   341                 raise SyntaxError("in " + u(line) + ": 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("")
       
   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 = ""
       
   369         return code("")
       
   370 
       
   371     elif ctype == "decl":
       
   372         name = ""
       
   373         for data in obj[1]:
       
   374             if 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 + ":" + 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("in " + included + ":" + u(line) + ": " + base + " as base for " + name)
       
   398                         else:
       
   399                             raise KeyError("in " + u(line) + ": " + base + " 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("in " + included + ":" + u(line) + ": " + base + " as shape for " + name)
       
   408                         else:
       
   409                             raise KeyError("in " + u(line) + ": " + base + " 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 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 + ":" + 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("")
       
   439 
       
   440     elif ctype == "funclist":
       
   441         result = ""
       
   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 ""
       
   451 
       
   452     elif ctype == "fparm":
       
   453         if len(obj[1]):
       
   454             return codegen(('func', ['_parm', ('content', [obj[1][0]])]))
       
   455         else:
       
   456             return ""
       
   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("in " + included + ":" + u(line) + ": syntax error in decl statement")
       
   472                 else:
       
   473                     raise SyntaxError("in " + u(line) + ": syntax error in decl statement")
       
   474         if name == "define" or name == "operator":
       
   475             if ymlFunc[name] == "#error":
       
   476                 if included:
       
   477                     raise SyntaxError("in " + included + ":" + u(line) + ": syntax error in define statement")
       
   478                 else:
       
   479                     raise SyntaxError("in " + u(line) + ": 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(''+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 KeyError:
       
   499             try:
       
   500                 if ymlFunc["_"].alias != "-":
       
   501                     return codegen(('func', ['_', ('content', [('funclist', [obj])])]))
       
   502                 else:
       
   503                     ymlFunc[name] = copy(ymlFunc["_"])
       
   504                     ymlFunc[name].alias = name.replace("_", "-")
       
   505                     return codegen(obj)
       
   506             except KeyError:
       
   507                 ymlFunc[name] = YF(name)
       
   508         
       
   509         if ymlFunc[name].alias == "-": avoidTag = True
       
   510 
       
   511         to_add = []
       
   512         if len(ymlFunc[name].descends):
       
   513             if obj[1][-1][0] != 'content':
       
   514                 if included:
       
   515                     raise KeyError("in " + included + ":" + u(line) + ": " + name + " has descending attributes, but no descendants are following")
       
   516                 else:
       
   517                     raise KeyError("in " + u(line) + ": " + name + " has descending attributes, but no descendants are following")
       
   518 
       
   519             def first_func(obj):
       
   520                 if type(obj) is tuple or type(obj) is Symbol:
       
   521                     if obj[0] == 'func':
       
   522                         return obj
       
   523                     elif obj[0] == 'funclist':
       
   524                         return first_func(obj[1])
       
   525                     elif obj[0] == 'content':
       
   526                         return first_func(obj[1])
       
   527                     else:
       
   528                         return None
       
   529                 elif type(obj) == list:
       
   530                     for e in obj:
       
   531                         f = first_func(e)
       
   532                         if f: return f
       
   533                     return None
       
   534 
       
   535             def copy_without_first_func(o, found = False):
       
   536                 c = []
       
   537                 for obj in o:
       
   538                     if found:
       
   539                         c.append(obj)
       
   540                     else:
       
   541                         if obj[0] == 'func':
       
   542                             if obj[1][-1][0] == 'content':
       
   543                                 c.extend( obj[1][-1][1] )
       
   544                             found = True
       
   545                         else:
       
   546                             c.append( ( obj[0], copy_without_first_func(obj[1], False ) ) )
       
   547                 return c
       
   548 
       
   549             def get_parms(obj):
       
   550                 result = []
       
   551                 for e in obj[1]:
       
   552                     if type(e) is tuple or type(e) is Symbol:
       
   553                         if e[0] == "parm":
       
   554                             result.append( e )
       
   555                 return result
       
   556 
       
   557             try:
       
   558                 add_params = get_parms(obj)
       
   559                 for e in obj[1][-1][1]:
       
   560                     c = e[1]
       
   561                     for dname in ymlFunc[name].descends:
       
   562                         f, c = first_func(c), copy_without_first_func(c)
       
   563                         if dname[0] == "*":
       
   564                             pointers[dname[1:]] = "'" + f[1][0] + "'"
       
   565                         else:
       
   566                             add_params.append( ('parm', [dname, "'" + f[1][0] + "'"]) )
       
   567                         try:
       
   568                             add_params.extend( get_parms(f) )
       
   569                         except: pass
       
   570 
       
   571                     new_things = [ e[1][0] ]
       
   572                     new_things.extend( add_params )
       
   573                     new_things.append( ('content', c) )
       
   574                     
       
   575                     to_add.append( ('func', new_things ) )
       
   576             except:
       
   577                 if included:
       
   578                     raise KeyError("in " + included + ":" + u(line) + ": " + name + " has descending attributes, and too less descendants are following")
       
   579                 else:
       
   580                     raise KeyError("in " + u(line) + ": " + name + " has descending attributes, and too less descendants are following")
       
   581 
       
   582         if not to_add:
       
   583             to_add = ( obj, )
       
   584 
       
   585         complete = ""
       
   586 
       
   587         for obj in to_add:
       
   588             subtree = None
       
   589             try:
       
   590                 if obj[1][-1][0] == "content":
       
   591                     subtree = obj[1][-1][1]
       
   592             except: pass
       
   593      
       
   594             if ymlFunc[name].content:
       
   595                 hasContent = True
       
   596                 treetemplate = deepcopy(ymlFunc[name].content)
       
   597                 subtree = replaceContent(treetemplate, subtree)
       
   598 
       
   599             if subtree:
       
   600                 hasContent = True
       
   601 
       
   602             hasContent, result = ymlFunc[name](obj[1], hasContent, avoidTag)
       
   603 
       
   604             if subtree:
       
   605                 for sel in subtree:
       
   606                     result += codegen(sel)
       
   607 
       
   608             if hasContent and not(avoidTag):
       
   609                 result += "</" + ymlFunc[name].alias + ">"
       
   610 
       
   611             complete += result
       
   612 
       
   613         return code(complete)
       
   614 
       
   615     elif ctype == "textsection":
       
   616         result = ''
       
   617         ll = obj[1].splitlines()
       
   618         space = len(ll[-1]) - 2
       
   619         for l in ll[1:-1]:
       
   620             m = re.match(bqq, l)
       
   621             if m:
       
   622                 cmd = m.group(1)
       
   623                 try:
       
   624                     r, x = parseLine(cmd, _inner, [], True, comment)
       
   625                     if x: raise SyntaxError(cmd)
       
   626                     result += _finish(r)
       
   627                 except SyntaxError:
       
   628                     if included:
       
   629                         raise SyntaxError("in " + included + ":" + u(line) + ": syntax error in executing command: " + cmd.strip())
       
   630                     else:
       
   631                         raise SyntaxError("in " + u(line) + ": syntax error in executing command: " + cmd.strip())
       
   632             else:
       
   633                 result += codegen(Symbol('lineQuote', '| ' + l[space:]))
       
   634         return code(result)
       
   635 
       
   636     elif ctype == "textsectionu":
       
   637         result = ''
       
   638         ll = obj[1].splitlines()
       
   639         space = len(ll[-1]) - 2
       
   640         for l in ll[1:-1]:
       
   641             m = re.match(bqq, l)
       
   642             if m:
       
   643                 cmd = m.group(1)
       
   644                 try:
       
   645                     r, x = parseLine(cmd, _inner, [], True, comment)
       
   646                     if x: raise SyntaxError(cmd)
       
   647                     result += _finish(r)
       
   648                 except SyntaxError:
       
   649                     if included:
       
   650                         raise SyntaxError("in " + included + ":" + u(line) + ": syntax error in executing command: " + cmd.strip())
       
   651                     else:
       
   652                         raise SyntaxError("in " + u(line) + ": syntax error in executing command: " + cmd.strip())
       
   653             else:
       
   654                 if result != '': result += ' '
       
   655                 result += codegen(Symbol('quote', ['> ' + l[space:]]))
       
   656         return code(result)
       
   657 
       
   658     elif ctype == "lineQuote" or ctype == "quote":
       
   659         m, text, base, inds = None, "", 0, 0
       
   660 
       
   661         if ctype == "lineQuote":
       
   662             text = obj[1]
       
   663             m = lq.match(text)
       
   664             if m:
       
   665                 inds = len(m.group(1))
       
   666                 text = m.group(2)[1:]
       
   667             else: inds = 0
       
   668         elif ctype == "quote":
       
   669             inds = -1
       
   670             text = obj[1][0]
       
   671             m = sq.match(text)
       
   672             if m:
       
   673                 if m.group(1):
       
   674                     inds = int(m.group(1))
       
   675                 text = m.group(2)[1:]
       
   676             else:
       
   677                 if type(text) is str:
       
   678                     text = u(evalPython(text))
       
   679 
       
   680         ind = ""
       
   681         if inds > -1:
       
   682             try:
       
   683                 cmd = evalPython("indent(" + u(inds) + ")")
       
   684                 result, rest = parseLine(u(cmd), _inner, [], True, comment)
       
   685                 if rest:
       
   686                     raise SyntaxError()
       
   687                 ind = _finish(result)
       
   688             except: pass
       
   689         
       
   690         if ctype == "lineQuote": text += "\n"
       
   691 
       
   692         hasTextFunc = False
       
   693         try:
       
   694             ymlFunc["text"]
       
   695             hasTextFunc = True
       
   696         except: pass
       
   697 
       
   698         text = executeCmd(text)
       
   699         return code(ind + text) 
       
   700 
       
   701     elif ctype == "tagQuote":
       
   702         m = tq.match(obj[1])
       
   703         if m.group(1) == "<":
       
   704             return code("<" + m.group(2))
       
   705         else:
       
   706             return code(m.group(2))
       
   707 
       
   708     elif ctype == "operator":
       
   709         operator.append((re.compile(evalPython(obj[1][0])), obj[1][1]))
       
   710         return code("")
       
   711 
       
   712     elif ctype == "constant":
       
   713         name = obj[1][0]
       
   714         if name[0] == "*":
       
   715             name = name[1:]
       
   716         value = obj[1][1]
       
   717         pointers[name] = value
       
   718         return code("")
       
   719 
       
   720     elif ctype == "include":
       
   721         reverse = False
       
   722         ktext, kxml = False, False
       
   723         for arg in obj[1]:
       
   724             if type(arg) is tuple or type(arg) is Symbol:
       
   725                 if arg[0] == "reverse":
       
   726                     reverse = True
       
   727                 elif arg[0] == "ktext":
       
   728                     ktext = True
       
   729                 elif arg[0] == "kxml":
       
   730                     kxml = True
       
   731             elif type(arg) is str:
       
   732                 filemask = arg
       
   733 
       
   734         if filemask[0] == '/' or filemask[0] == '.':
       
   735             files = sorted(glob(filemask))
       
   736         else:
       
   737             files = []
       
   738             for directory in includePath:
       
   739                 path = os.path.join(directory, filemask)
       
   740                 files.extend(sorted(glob(path)))
       
   741 
       
   742         if files and reverse:
       
   743             files = files[-1::-1]
       
   744 
       
   745         if not(files):
       
   746             if included:
       
   747                 raise IOError("in " + included + ":" + u(line) + ": include file(s) '" + filemask + "' not found")
       
   748             else:
       
   749                 raise IOError("in " + u(line) + ": include file(s) '" + filemask + "' not found")
       
   750 
       
   751         includeFile = fileinput.input(files, mode="rU", openhook=fileinput.hook_encoded(encoding))
       
   752         _included = included
       
   753         if ktext or kxml:
       
   754             text = ""
       
   755             for line in includeFile:
       
   756                 included = includeFile.filename()
       
   757                 if kxml:
       
   758                     if (not line[:6] == '<?xml ') and (not line[:6] == '<?XML '):
       
   759                         text += line
       
   760                 else:
       
   761                     text += executeCmd(line)
       
   762             included = _included
       
   763             return code(text)
       
   764         else:
       
   765             result = parse(ymlCStyle(), includeFile, True, comment)
       
   766             included = u(filemask)
       
   767             x = _finish(result)
       
   768             included = _included
       
   769             return code(x)
       
   770 
       
   771     elif ctype == "pyExp":
       
   772         exp = obj[1][0]
       
   773         cmd = evalPython(exp)
       
   774         result, rest = parseLine(u(cmd), _inner, [], True, comment)
       
   775         if rest:
       
   776             raise SyntaxError(cmd)
       
   777         return code(_finish(result))
       
   778 
       
   779     elif ctype == "pythonCall":
       
   780         parms = []
       
   781         data = obj[1]
       
   782         for p in data:
       
   783             if type(p) is str:
       
   784                 name = p
       
   785             elif type(p) is tuple or type(p) is Symbol:
       
   786                 ptype = p[0]
       
   787                 if ptype == "parm":
       
   788                     if p[1][0][0] == "*":
       
   789                         parms.append(pointer(p[1][0]))
       
   790                     else:
       
   791                         parms.append(p[1][0])
       
   792         if len(parms) == 0:
       
   793             exp = name + "()"
       
   794         elif len(parms) == 1:
       
   795             exp = name + "(" + u(parms[0]) + ")"
       
   796         else:
       
   797             exp = name + u(tuple(parms))
       
   798         cmd = evalPython(exp)
       
   799         result, rest = parseLine(u(cmd), _inner, [], True, comment)
       
   800         if rest:
       
   801             raise SyntaxError()
       
   802         return code(_finish(result))
       
   803 
       
   804     else:
       
   805         return code("")
       
   806 
       
   807 def _finish(tree):
       
   808     result = ""
       
   809     python = ""
       
   810 
       
   811     for el in tree:
       
   812         if el[0] == "python":
       
   813             if el[1][0][:2] == "!!":
       
   814                 python += el[1][0][2:-2]
       
   815             else:
       
   816                 python += el[1][0][1:] + "\n"
       
   817             continue
       
   818         else:
       
   819             if python:
       
   820                 execPython(python)
       
   821                 python = ""
       
   822 
       
   823         try:
       
   824             result += codegen(el)
       
   825         except RuntimeError:
       
   826             if included:
       
   827                 raise RuntimeError("in " + included + ":" + u(line))
       
   828             else:
       
   829                 raise RuntimeError("in " + u(line))
       
   830 
       
   831     if python:
       
   832         execPython(python)
       
   833 
       
   834     return result
       
   835 
       
   836 def finish(tree):
       
   837     global first
       
   838     first = True
       
   839     return _finish(tree)
       
   840 
       
   841 ymlFunc["_parentheses"] = YF("parms")
       
   842 ymlFunc["_parm"] = YF("parm")
       
   843 ymlFunc["_generic"] = YF("generic")
       
   844 ymlFunc["_base"] = YF("base")