backend.py
changeset 31 d3dddb80d1f5
parent 29 6a8a7951d8e6
child 32 2b7b48758eaa
equal deleted inserted replaced
30:a1ecf17c60eb 31:d3dddb80d1f5
     1 # 2.5.10 backend
     1 # 2.6.0 backend
     2 
     2 
     3 # written by VB.
     3 # written by VB.
     4 
     4 
     5 import re, codecs
     5 import re, codecs
     6 import fileinput
     6 import fileinput
     7 import sys, traceback, exceptions, os
     7 import sys, traceback, os
     8 from xml.sax.saxutils import escape, quoteattr
     8 from xml.sax.saxutils import escape, quoteattr
     9 from copy import copy, deepcopy
     9 from copy import copy, deepcopy
    10 from glob import glob
    10 from glob import glob
    11 from pyPEG import code, parse, parseLine, u, Symbol
    11 from pyPEG import code, parse, parseLine, u, Symbol
    12 from yml2 import ymlCStyle, comment, _inner
    12 from yml2 import ymlCStyle, comment, _inner
    13 
    13 
    14 ymlFunc, pointers, pythonFunc = {}, {}, {}
    14 ymlFunc, pointers, pythonFunc = {}, {}, {}
    15 in_ns = u""
    15 in_ns = ""
    16 operator = []
    16 operator = []
    17 included = u""
    17 included = ""
    18 includePath = []
    18 includePath = []
    19 emitlinenumbers = False
    19 emitlinenumbers = False
    20 encoding = "utf-8"
    20 encoding = "utf-8"
    21 
    21 
    22 first = True
    22 first = True
    27 ymlFunc["operator"] = "#error"
    27 ymlFunc["operator"] = "#error"
    28 
    28 
    29 def clearAll():
    29 def clearAll():
    30     global ymlFunc, pointers, pythonFunc, in_ns, operator, included
    30     global ymlFunc, pointers, pythonFunc, in_ns, operator, included
    31     ymlFunc, pointers, pythonFunc = {}, {}, {}
    31     ymlFunc, pointers, pythonFunc = {}, {}, {}
    32     in_ns = u""
    32     in_ns = ""
    33     operator = []
    33     operator = []
    34     included = u""
    34     included = ""
    35 
    35 
    36 lq = re.compile(r"\|(\>*)(.*)")
    36 lq = re.compile(r"\|(\>*)(.*)")
    37 sq = re.compile(r"(\d*)\>(.*)")
    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)
    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*(.*)")
    39 tq = re.compile(r"(\]|\<)\s*(.*)")
    46 def pointer(name):
    46 def pointer(name):
    47     try:
    47     try:
    48         return u(pointers[name[1:]])
    48         return u(pointers[name[1:]])
    49     except:
    49     except:
    50         if name == "*_trace_info":
    50         if name == "*_trace_info":
    51             return u'""'
    51             return '""'
    52         if included:
    52         if included:
    53             raise LookupError(u"in " + included + u":" + u(line) + u": pointer " + name)
    53             raise LookupError("in " + included + ":" + u(line) + ": pointer " + name)
    54         else:
    54         else:
    55             raise LookupError(u"in " + u(line) + u": pointer " + name)
    55             raise LookupError("in " + u(line) + ": pointer " + name)
    56 
    56 
    57 def evalPython(expr):
    57 def evalPython(expr):
    58     try:
    58     try:
    59         result = eval(u(expr), pythonFunc)
    59         result = eval(u(expr), pythonFunc)
    60         if type(result) is str:
    60         if type(result) is bytes:
    61             return codecs.decode(result, encoding)
    61             return codecs.decode(result, encoding)
    62         else:
    62         else:
    63             return result
    63             return result
    64     except:
    64     except:
    65         name, parm, tb = sys.exc_info()
    65         name, parm, tb = sys.exc_info()
    66         msg = u"in python expression: " + u(parm)
    66         msg = "in python expression: " + u(parm)
    67         if name is exceptions.SyntaxError:
    67         if name is SyntaxError:
    68             tbl = traceback.format_exception(name, parm, tb)
    68             tbl = traceback.format_exception(name, parm, tb)
    69             msg += u"\n" + tbl[-3] + tbl[-2]
    69             msg += "\n" + tbl[-3] + tbl[-2]
    70         else:
    70         else:
    71             msg += u": " + expr + u"\n"
    71             msg += ": " + expr + "\n"
    72         if included:
    72         if included:
    73             raise name(u"in " + included + u":" + u(line) + u": " + msg)
    73             raise name("in " + included + ":" + u(line) + ": " + msg)
    74         else:
    74         else:
    75             raise name(u"in " + u(line) + u": " + msg)
    75             raise name("in " + u(line) + ": " + msg)
    76     
    76     
    77 def execPython(script):
    77 def execPython(script):
    78     try:
    78     try:
    79         if type(script) is unicode:
    79         if type(script) is str:
    80             exec script in pythonFunc
    80             exec(script, pythonFunc)
    81         else:
    81         else:
    82             exec codecs.decode(script, encoding) in pythonFunc
    82             exec(codecs.decode(script, encoding), pythonFunc)
    83     except:
    83     except:
    84         name, parm, tb = sys.exc_info()
    84         name, parm, tb = sys.exc_info()
    85         msg = u"in python script: " + u(parm)
    85         msg = "in python script: " + u(parm)
    86         if name is exceptions.SyntaxError:
    86         if name is SyntaxError:
    87             tbl = traceback.format_exception(name, parm, tb)
    87             tbl = traceback.format_exception(name, parm, tb)
    88             msg += u"\n" + tbl[-3] + tbl[-2]
    88             msg += "\n" + tbl[-3] + tbl[-2]
    89         else:
    89         else:
    90             msg += u": " + expr + u"\n"
    90             msg += ": " + expr + "\n"
    91         if included:
    91         if included:
    92             raise name(u"in " + included + u":" + u(line) + u": " + msg)
    92             raise name("in " + included + ":" + u(line) + ": " + msg)
    93         else:
    93         else:
    94             raise name(u"in " + u(line) + u": " + msg)
    94             raise name("in " + u(line) + ": " + msg)
    95 
    95 
    96 def textOut(text):
    96 def textOut(text):
    97     if not text:
    97     if not text:
    98         return u""
    98         return ""
    99     if type(text) is not unicode:
    99     if type(text) is not str:
   100         text = codecs.decode(text, encoding)
   100         text = codecs.decode(text, encoding)
   101     text = text.replace(r'\"', r'\\"')
   101     text = text.replace(r'\"', r'\\"')
   102     text = u'u"""' + text.replace('"', r'\"') + u'"""'
   102     text = '"""' + text.replace('"', r'\"') + '"""'
   103     try:
   103     try:
   104         textFunc = ymlFunc["text"]
   104         textFunc = ymlFunc["text"]
   105         parms = ['text', ('parm', [text])]
   105         parms = ['text', ('parm', [text])]
   106         c, result = textFunc(parms)
   106         c, result = textFunc(parms)
   107         if c:
   107         if c:
   108             if type(textFunc.alias) is unicode:
   108             if type(textFunc.alias) is str:
   109                 result += u"</" + textFunc.alias + u">"
   109                 result += "</" + textFunc.alias + ">"
   110             else:
   110             else:
   111                 result += u"</" + codecs.decode(textFunc.alias, encoding) + u">"
   111                 result += "</" + codecs.decode(textFunc.alias, encoding) + ">"
   112         return result
   112         return result
   113     except:
   113     except:
   114         return escape(eval(text))
   114         return escape(eval(text))
   115 
   115 
   116 def strRepl(text):
   116 def strRepl(text):
   117     if not text:
   117     if not text:
   118         return u""
   118         return ""
   119     if type(text) is not unicode:
   119     if type(text) is not str:
   120         text = codecs.decode(text, encoding)
   120         text = codecs.decode(text, encoding)
   121     text = text.replace(r'\"', r'\\"')
   121     text = text.replace(r'\"', r'\\"')
   122     text = u'u"""' + text.replace('"', r'\"') + u'"""'
   122     text = '"""' + text.replace('"', r'\"') + '"""'
   123     if type(text) is unicode:
   123     if type(text) is str:
   124         return escape(eval(text))
   124         return escape(eval(text))
   125 
   125 
   126 def applyMacros(macros, text):
   126 def applyMacros(macros, text):
   127     result = text
   127     result = text
   128     for key, value in macros.iteritems():
   128     for key, value in macros.items():
   129         result = result.replace(key, value)
   129         result = result.replace(key, value)
   130     return result
   130     return result
   131 
   131 
   132 class YF:
   132 class YF:
   133     def __init__(self, name):
   133     def __init__(self, name):
   137         self.values = {}
   137         self.values = {}
   138         self.content = None
   138         self.content = None
   139         self.pointers = {}
   139         self.pointers = {}
   140         self.macros = {}
   140         self.macros = {}
   141         if in_ns:
   141         if in_ns:
   142             self.alias = in_ns + u":" + name.replace("_", "-")
   142             self.alias = in_ns + ":" + name.replace("_", "-")
   143         else:
   143         else:
   144             self.alias = name.replace("_", "-")
   144             self.alias = name.replace("_", "-")
   145         pythonFunc["yml_" + name] = self
   145         pythonFunc["yml_" + name] = self
   146         if emitlinenumbers:
   146         if emitlinenumbers:
   147             self.values["yml:declared"] = u(line)
   147             self.values["yml:declared"] = u(line)
   203                             vals[parm] = u(val)
   203                             vals[parm] = u(val)
   204                 elif data[0] == "content":
   204                 elif data[0] == "content":
   205                     hasContent = True
   205                     hasContent = True
   206 
   206 
   207         if enable_tracing:
   207         if enable_tracing:
   208             text = u(parms) + u", " + u(vals)
   208             text = u(parms) + ", " + u(vals)
   209             pointers["_trace_info"] = u'"' + u(line) + u": " + u(self.name) + u" " + text.replace(u'"', u'#') + u'"'
   209             pointers["_trace_info"] = '"' + u(line) + ": " + u(self.name) + " " + text.replace('"', '#') + '"'
   210 
   210 
   211         if emitlinenumbers:
   211         if emitlinenumbers:
   212             global first
   212             global first
   213             if first:
   213             if first:
   214                 vals["xmlns:yml"] = u"http://fdik.org/yml"
   214                 vals["xmlns:yml"] = "http://fdik.org/yml"
   215                 first = False
   215                 first = False
   216             vals["yml:called"] = u(line)
   216             vals["yml:called"] = u(line)
   217         return self.xml(parms, vals, hasContent, avoidTag)
   217         return self.xml(parms, vals, hasContent, avoidTag)
   218 
   218 
   219     def addParm(self, parm):
   219     def addParm(self, parm):
   229             self.descends.append(desc[1:])
   229             self.descends.append(desc[1:])
   230         else:
   230         else:
   231             self.descends.append(desc)
   231             self.descends.append(desc)
   232 
   232 
   233     def addValue(self, parm, value):
   233     def addValue(self, parm, value):
   234         if type(value) is str or type(value) is unicode:
   234         if type(value) is str or type(value) is str:
   235             if value[0] != "'" and value[0] != '"':
   235             if value[0] != "'" and value[0] != '"':
   236                 self.values[parm] = u(value)
   236                 self.values[parm] = u(value)
   237             else:
   237             else:
   238                 self.values[parm] = u(evalPython(value))
   238                 self.values[parm] = u(evalPython(value))
   239         else:
   239         else:
   240             self.values[parm] = u(evalPython(u(value)))
   240             self.values[parm] = u(evalPython(u(value)))
   241 
   241 
   242     def xml(self, callParms, callValues, hasContent, avoidTag = False):
   242     def xml(self, callParms, callValues, hasContent, avoidTag = False):
   243         global pointers
   243         global pointers
   244         extraContent = u""
   244         extraContent = ""
   245         if self.content:
   245         if self.content:
   246             hasContent = True
   246             hasContent = True
   247         resultParms = self.values.copy()
   247         resultParms = self.values.copy()
   248         macros = self.macros.copy()
   248         macros = self.macros.copy()
   249         toDelete = resultParms.keys()
   249         toDelete = resultParms.keys()
   250         for key in toDelete:
   250         for key in toDelete:
   251             if key[0] == "*":
   251             if key[0] == "*":
   252                 del resultParms[key]
   252                 del resultParms[key]
   253         for key, value in callValues.iteritems():
   253         for key, value in callValues.items():
   254             if key[0] == "%":
   254             if key[0] == "%":
   255                 macros[key] = value
   255                 macros[key] = value
   256             else:
   256             else:
   257                 resultParms[key] = value
   257                 resultParms[key] = value
   258         i = 0
   258         i = 0
   259         for cp in callParms:
   259         for cp in callParms:
   260             if i < len(self.parms):
   260             if i < len(self.parms):
   261                 if self.parms[i][0] == "*":
   261                 if self.parms[i][0] == "*":
   262                     cp = u(cp)
   262                     cp = u(cp)
   263                     if "'" in cp:
   263                     if "'" in cp:
   264                         pointers[self.parms[i][1:]] = u'"' + cp + u'"'
   264                         pointers[self.parms[i][1:]] = '"' + cp + '"'
   265                     else:
   265                     else:
   266                         pointers[self.parms[i][1:]] = u"'" + cp + u"'"
   266                         pointers[self.parms[i][1:]] = "'" + cp + "'"
   267                 elif self.parms[i][0] == "%":
   267                 elif self.parms[i][0] == "%":
   268                     macros[self.parms[i]] = u(cp)
   268                     macros[self.parms[i]] = u(cp)
   269                 else:
   269                 else:
   270                     resultParms[self.parms[i]] = cp
   270                     resultParms[self.parms[i]] = cp
   271             else:
   271             else:
   272                 extraContent += u(cp)
   272                 extraContent += u(cp)
   273                 hasContent = True
   273                 hasContent = True
   274             i += 1
   274             i += 1
   275         result = u""
   275         result = ""
   276         for p, v in resultParms.iteritems():
   276         for p, v in resultParms.items():
   277             if p[0] == "'" or p[0] == '"':
   277             if p[0] == "'" or p[0] == '"':
   278                 p = eval(p)
   278                 p = eval(p)
   279             result += u" "+ p + u"=" + quoteattr(applyMacros(macros, u(v)))
   279             result += " "+ p + "=" + quoteattr(applyMacros(macros, u(v)))
   280         if hasContent:
   280         if hasContent:
   281             if avoidTag:
   281             if avoidTag:
   282                 return True, strRepl(extraContent)
   282                 return True, strRepl(extraContent)
   283             else:
   283             else:
   284                 return True, u"<" + self.alias + result + u">" + strRepl(extraContent)
   284                 return True, "<" + self.alias + result + ">" + strRepl(extraContent)
   285         else:
   285         else:
   286             if avoidTag:
   286             if avoidTag:
   287                 return False, u""
   287                 return False, ""
   288             else:
   288             else:
   289                 return False, u"<" + self.alias + result + u"/>"
   289                 return False, "<" + self.alias + result + "/>"
   290 
   290 
   291 def replaceContent(tree, subtree):
   291 def replaceContent(tree, subtree):
   292     n = 0
   292     n = 0
   293     while n < len(tree):
   293     while n < len(tree):
   294         obj = tree[n]
   294         obj = tree[n]
   311             replaceContent(obj[1], subtree)
   311             replaceContent(obj[1], subtree)
   312         n += 1
   312         n += 1
   313     return tree
   313     return tree
   314 
   314 
   315 def executeCmd(text):
   315 def executeCmd(text):
   316     if type(text) is not unicode:
   316     if type(text) is not str:
   317         text = codecs.decode(text, encoding)
   317         text = codecs.decode(text, encoding)
   318     for (regex, pattern) in operator:
   318     for (regex, pattern) in operator:
   319         match = re.search(regex, text)
   319         match = re.search(regex, text)
   320         while match:
   320         while match:
   321             cmd = pattern
   321             cmd = pattern
   322             opt = match.groups()
   322             opt = match.groups()
   323             for i in range(len(opt)):
   323             for i in range(len(opt)):
   324                 cmd = cmd.replace(u"%" + u(i+1), opt[i])
   324                 cmd = cmd.replace("%" + u(i+1), opt[i])
   325             text = text[:match.start()] + u"`" + cmd + u"`"+ text[match.end():]
   325             text = text[:match.start()] + "`" + cmd + "`"+ text[match.end():]
   326             match = re.search(regex, text)
   326             match = re.search(regex, text)
   327 
   327 
   328     result = u""
   328     result = ""
   329     m = re.search(bq, text)
   329     m = re.search(bq, text)
   330     while text and m:
   330     while text and m:
   331         cmd  = m.group(1)
   331         cmd  = m.group(1)
   332         head = textOut(text[:m.start()])
   332         head = textOut(text[:m.start()])
   333         text = text[m.end():]
   333         text = text[m.end():]
   334         try:
   334         try:
   335             r, rest = parseLine(cmd, _inner, [], True, comment)
   335             r, rest = parseLine(cmd, _inner, [], True, comment)
   336             if rest: raise SyntaxError(cmd)
   336             if rest: raise SyntaxError(cmd)
   337         except SyntaxError:
   337         except SyntaxError:
   338             if included:
   338             if included:
   339                 raise SyntaxError(u"in " + included + u":" + u(line) + u": syntax error in executing command: " + cmd.strip())
   339                 raise SyntaxError("in " + included + ":" + u(line) + ": syntax error in executing command: " + cmd.strip())
   340             else:
   340             else:
   341                 raise SyntaxError(u"in " + u(line) + u": syntax error in executing command: " + cmd.strip())
   341                 raise SyntaxError("in " + u(line) + ": syntax error in executing command: " + cmd.strip())
   342         inner = _finish(r)
   342         inner = _finish(r)
   343         result += head + inner
   343         result += head + inner
   344         m = re.search(bq, text)
   344         m = re.search(bq, text)
   345     result += textOut(text)
   345     result += textOut(text)
   346 
   346 
   356     try:
   356     try:
   357         if ctype.line: line = ctype.line
   357         if ctype.line: line = ctype.line
   358     except: pass
   358     except: pass
   359 
   359 
   360     if ctype == "empty":
   360     if ctype == "empty":
   361         return code(u"")
   361         return code("")
   362 
   362 
   363     if ctype == "in_ns":
   363     if ctype == "in_ns":
   364         in_ns = obj[1][0]
   364         in_ns = obj[1][0]
   365         subtree = obj[1]
   365         subtree = obj[1]
   366         for sel in subtree:
   366         for sel in subtree:
   367             codegen(sel)
   367             codegen(sel)
   368         in_ns = u""
   368         in_ns = ""
   369         return code(u"")
   369         return code("")
   370 
   370 
   371     elif ctype == "decl":
   371     elif ctype == "decl":
   372         name = u""
   372         name = ""
   373         for data in obj[1]:
   373         for data in obj[1]:
   374             if type(data) is unicode or type(data) is str:
   374             if type(data) is str:
   375                 name = data
   375                 name = data
   376                 try:
   376                 try:
   377                     yf = ymlFunc[name]
   377                     yf = ymlFunc[name]
   378                     yf.alias
   378                     yf.alias
   379                 except:
   379                 except:
   380                     ymlFunc[name] = YF(name)
   380                     ymlFunc[name] = YF(name)
   381                     yf = ymlFunc[name]
   381                     yf = ymlFunc[name]
   382                     if in_ns:
   382                     if in_ns:
   383                         yf.alias = in_ns + u":" + name
   383                         yf.alias = in_ns + ":" + name
   384                         if not enable_tracing:
   384                         if not enable_tracing:
   385                             if in_ns == "xsl" and (name == "debug" or name=="assert" or name[:7]=="_trace_"):
   385                             if in_ns == "xsl" and (name == "debug" or name=="assert" or name[:7]=="_trace_"):
   386                                 yf.alias = "-"
   386                                 yf.alias = "-"
   387                                 yf.addParm("skip1")
   387                                 yf.addParm("skip1")
   388                                 yf.addParm("skip2")
   388                                 yf.addParm("skip2")
   392                     base = data[1][0]
   392                     base = data[1][0]
   393                     try:
   393                     try:
   394                         yf = ymlFunc[name] = ymlFunc[base].copy(name)
   394                         yf = ymlFunc[name] = ymlFunc[base].copy(name)
   395                     except KeyError:
   395                     except KeyError:
   396                         if included:
   396                         if included:
   397                             raise KeyError(u"in " + included + u":" + u(line) + u": " + base + u" as base for " + name)
   397                             raise KeyError("in " + included + ":" + u(line) + ": " + base + " as base for " + name)
   398                         else:
   398                         else:
   399                             raise KeyError(u"in " + u(line) + u": " + base + u" as base for " + name)
   399                             raise KeyError("in " + u(line) + ": " + base + " as base for " + name)
   400                 elif data[0] == "shape":
   400                 elif data[0] == "shape":
   401                     shape = ymlFunc[data[1]]
   401                     shape = ymlFunc[data[1]]
   402                     try:
   402                     try:
   403                         yf = ymlFunc[name]
   403                         yf = ymlFunc[name]
   404                         yf.patch(shape)
   404                         yf.patch(shape)
   405                     except KeyError:
   405                     except KeyError:
   406                         if included:
   406                         if included:
   407                             raise KeyError(u"in " + included + u":" + u(line) + u": " + base + u" as shape for " + name)
   407                             raise KeyError("in " + included + ":" + u(line) + ": " + base + " as shape for " + name)
   408                         else:
   408                         else:
   409                             raise KeyError(u"in " + u(line) + u": " + base + u" as shape for " + name)
   409                             raise KeyError("in " + u(line) + ": " + base + " as shape for " + name)
   410                 elif data[0] == "descend":
   410                 elif data[0] == "descend":
   411                     yf.addDescend(data[1])
   411                     yf.addDescend(data[1])
   412                 elif data[0] == "declParm":
   412                 elif data[0] == "declParm":
   413                     l = data[1]
   413                     l = data[1]
   414                     parmName = l[0]
   414                     parmName = l[0]
   420                             yf.addValue(parmName, value)
   420                             yf.addValue(parmName, value)
   421                         if parmName[0] == "*":
   421                         if parmName[0] == "*":
   422                             yf.pointers[parmName[1:]] = value
   422                             yf.pointers[parmName[1:]] = value
   423                             yf.addParm(parmName)
   423                             yf.addParm(parmName)
   424                         elif parmName[0] == "%":
   424                         elif parmName[0] == "%":
   425                             if type(value) is unicode or type(value) is str:
   425                             if type(value) is str:
   426                                 yf.macros[parmName] = u(evalPython(value))
   426                                 yf.macros[parmName] = u(evalPython(value))
   427                             else:
   427                             else:
   428                                 yf.macros[parmName] = u(evalPython(u(value)))
   428                                 yf.macros[parmName] = u(evalPython(u(value)))
   429                             yf.addParm(parmName)
   429                             yf.addParm(parmName)
   430                 elif data[0] == "alias":
   430                 elif data[0] == "alias":
   431                     if in_ns:
   431                     if in_ns:
   432                         yf.alias = in_ns + u":" + data[1][0]
   432                         yf.alias = in_ns + ":" + data[1][0]
   433                     else:
   433                     else:
   434                         yf.alias = data[1][0]
   434                         yf.alias = data[1][0]
   435                 elif data[0] == "content":
   435                 elif data[0] == "content":
   436                     yf.content = data[1]
   436                     yf.content = data[1]
   437 
   437 
   438         return code(u"")
   438         return code("")
   439 
   439 
   440     elif ctype == "funclist":
   440     elif ctype == "funclist":
   441         result = u""
   441         result = ""
   442         for f in obj[1]:
   442         for f in obj[1]:
   443             result += codegen(f)
   443             result += codegen(f)
   444         return code(result)
   444         return code(result)
   445 
   445 
   446     elif ctype == "parentheses":
   446     elif ctype == "parentheses":
   447         if len(obj[1]):
   447         if len(obj[1]):
   448             return codegen(('func', ['_parentheses', ('content', [obj[1][0]])]))
   448             return codegen(('func', ['_parentheses', ('content', [obj[1][0]])]))
   449         else:
   449         else:
   450             return u""
   450             return ""
   451 
   451 
   452     elif ctype == "fparm":
   452     elif ctype == "fparm":
   453         if len(obj[1]):
   453         if len(obj[1]):
   454             return codegen(('func', ['_parm', ('content', [obj[1][0]])]))
   454             return codegen(('func', ['_parm', ('content', [obj[1][0]])]))
   455         else:
   455         else:
   456             return u""
   456             return ""
   457 
   457 
   458     elif ctype == "generic":
   458     elif ctype == "generic":
   459         return codegen(('func', ['_generic', ('content', [obj[1][0]])]))
   459         return codegen(('func', ['_generic', ('content', [obj[1][0]])]))
   460 
   460 
   461     elif ctype == "xbase":
   461     elif ctype == "xbase":
   466         name = obj[1][0]
   466         name = obj[1][0]
   467 
   467 
   468         if name == "decl":
   468         if name == "decl":
   469             if ymlFunc[name] == "#error":
   469             if ymlFunc[name] == "#error":
   470                 if included:
   470                 if included:
   471                     raise SyntaxError(u"in " + included + u":" + u(line) + u": syntax error in decl statement")
   471                     raise SyntaxError("in " + included + ":" + u(line) + ": syntax error in decl statement")
   472                 else:
   472                 else:
   473                     raise SyntaxError(u"in " + u(line) + u": syntax error in decl statement")
   473                     raise SyntaxError("in " + u(line) + ": syntax error in decl statement")
   474         if name == "define" or name == "operator":
   474         if name == "define" or name == "operator":
   475             if ymlFunc[name] == "#error":
   475             if ymlFunc[name] == "#error":
   476                 if included:
   476                 if included:
   477                     raise SyntaxError(u"in " + included + u":" + u(line) + u": syntax error in define statement")
   477                     raise SyntaxError("in " + included + ":" + u(line) + ": syntax error in define statement")
   478                 else:
   478                 else:
   479                     raise SyntaxError(u"in " + u(line) + u": syntax error in define statement")
   479                     raise SyntaxError("in " + u(line) + ": syntax error in define statement")
   480 
   480 
   481         if name[0] == "&":
   481         if name[0] == "&":
   482             avoidTag = True
   482             avoidTag = True
   483             name = name[1:]
   483             name = name[1:]
   484         hasContent = False
   484         hasContent = False
   485 
   485 
   486         if len(name) > 2:
   486         if len(name) > 2:
   487             if name[0:2] == "**":
   487             if name[0:2] == "**":
   488                 return code(eval('u'+pointer(name[1:])))
   488                 return code(eval(''+pointer(name[1:])))
   489 
   489 
   490         if name[0] == "*":
   490         if name[0] == "*":
   491             name = eval(pointer(name))
   491             name = eval(pointer(name))
   492             if name[0] == "&":
   492             if name[0] == "&":
   493                 avoidTag = True
   493                 avoidTag = True
   495 
   495 
   496         try:
   496         try:
   497             ymlFunc[name]
   497             ymlFunc[name]
   498         except KeyError:
   498         except KeyError:
   499             try:
   499             try:
   500                 if ymlFunc["_"].alias != u"-":
   500                 if ymlFunc["_"].alias != "-":
   501                     return codegen(('func', ['_', ('content', [('funclist', [obj])])]))
   501                     return codegen(('func', ['_', ('content', [('funclist', [obj])])]))
   502                 else:
   502                 else:
   503                     ymlFunc[name] = copy(ymlFunc["_"])
   503                     ymlFunc[name] = copy(ymlFunc["_"])
   504                     ymlFunc[name].alias = name.replace("_", "-")
   504                     ymlFunc[name].alias = name.replace("_", "-")
   505                     return codegen(obj)
   505                     return codegen(obj)
   510 
   510 
   511         to_add = []
   511         to_add = []
   512         if len(ymlFunc[name].descends):
   512         if len(ymlFunc[name].descends):
   513             if obj[1][-1][0] != 'content':
   513             if obj[1][-1][0] != 'content':
   514                 if included:
   514                 if included:
   515                     raise KeyError(u"in " + included + u":" + u(line) + u": " + name + u" has descending attributes, but no descendants are following")
   515                     raise KeyError("in " + included + ":" + u(line) + ": " + name + " has descending attributes, but no descendants are following")
   516                 else:
   516                 else:
   517                     raise KeyError(u"in " + u(line) + u": " + name + u" has descending attributes, but no descendants are following")
   517                     raise KeyError("in " + u(line) + ": " + name + " has descending attributes, but no descendants are following")
   518 
   518 
   519             def first_func(obj):
   519             def first_func(obj):
   520                 if type(obj) is tuple or type(obj) is Symbol:
   520                 if type(obj) is tuple or type(obj) is Symbol:
   521                     if obj[0] == 'func':
   521                     if obj[0] == 'func':
   522                         return obj
   522                         return obj
   561                     for dname in ymlFunc[name].descends:
   561                     for dname in ymlFunc[name].descends:
   562                         f, c = first_func(c), copy_without_first_func(c)
   562                         f, c = first_func(c), copy_without_first_func(c)
   563                         if dname[0] == "*":
   563                         if dname[0] == "*":
   564                             pointers[dname[1:]] = "'" + f[1][0] + "'"
   564                             pointers[dname[1:]] = "'" + f[1][0] + "'"
   565                         else:
   565                         else:
   566                             add_params.append( ('parm', [dname, u"'" + f[1][0] + u"'"]) )
   566                             add_params.append( ('parm', [dname, "'" + f[1][0] + "'"]) )
   567                         try:
   567                         try:
   568                             add_params.extend( get_parms(f) )
   568                             add_params.extend( get_parms(f) )
   569                         except: pass
   569                         except: pass
   570 
   570 
   571                     new_things = [ e[1][0] ]
   571                     new_things = [ e[1][0] ]
   573                     new_things.append( ('content', c) )
   573                     new_things.append( ('content', c) )
   574                     
   574                     
   575                     to_add.append( ('func', new_things ) )
   575                     to_add.append( ('func', new_things ) )
   576             except:
   576             except:
   577                 if included:
   577                 if included:
   578                     raise KeyError(u"in " + included + u":" + u(line) + u": " + name + u" has descending attributes, and too less descendants are following")
   578                     raise KeyError("in " + included + ":" + u(line) + ": " + name + " has descending attributes, and too less descendants are following")
   579                 else:
   579                 else:
   580                     raise KeyError(u"in " + u(line) + u": " + name + u" has descending attributes, and too less descendants are following")
   580                     raise KeyError("in " + u(line) + ": " + name + " has descending attributes, and too less descendants are following")
   581 
   581 
   582         if not to_add:
   582         if not to_add:
   583             to_add = ( obj, )
   583             to_add = ( obj, )
   584 
   584 
   585         complete = u""
   585         complete = ""
   586 
   586 
   587         for obj in to_add:
   587         for obj in to_add:
   588             subtree = None
   588             subtree = None
   589             try:
   589             try:
   590                 if obj[1][-1][0] == "content":
   590                 if obj[1][-1][0] == "content":
   604             if subtree:
   604             if subtree:
   605                 for sel in subtree:
   605                 for sel in subtree:
   606                     result += codegen(sel)
   606                     result += codegen(sel)
   607 
   607 
   608             if hasContent and not(avoidTag):
   608             if hasContent and not(avoidTag):
   609                 result += u"</" + ymlFunc[name].alias + u">"
   609                 result += "</" + ymlFunc[name].alias + ">"
   610 
   610 
   611             complete += result
   611             complete += result
   612 
   612 
   613         return code(complete)
   613         return code(complete)
   614 
   614 
   615     elif ctype == "textsection":
   615     elif ctype == "textsection":
   616         result = u''
   616         result = ''
   617         ll = obj[1].splitlines()
   617         ll = obj[1].splitlines()
   618         space = len(ll[-1]) - 2
   618         space = len(ll[-1]) - 2
   619         for l in ll[1:-1]:
   619         for l in ll[1:-1]:
   620             m = re.match(bqq, l)
   620             m = re.match(bqq, l)
   621             if m:
   621             if m:
   624                     r, x = parseLine(cmd, _inner, [], True, comment)
   624                     r, x = parseLine(cmd, _inner, [], True, comment)
   625                     if x: raise SyntaxError(cmd)
   625                     if x: raise SyntaxError(cmd)
   626                     result += _finish(r)
   626                     result += _finish(r)
   627                 except SyntaxError:
   627                 except SyntaxError:
   628                     if included:
   628                     if included:
   629                         raise SyntaxError(u"in " + included + u":" + u(line) + u": syntax error in executing command: " + cmd.strip())
   629                         raise SyntaxError("in " + included + ":" + u(line) + ": syntax error in executing command: " + cmd.strip())
   630                     else:
   630                     else:
   631                         raise SyntaxError(u"in " + u(line) + u": syntax error in executing command: " + cmd.strip())
   631                         raise SyntaxError("in " + u(line) + ": syntax error in executing command: " + cmd.strip())
   632             else:
   632             else:
   633                 result += codegen(Symbol(u'lineQuote', u'| ' + l[space:]))
   633                 result += codegen(Symbol('lineQuote', '| ' + l[space:]))
   634         return code(result)
   634         return code(result)
   635 
   635 
   636     elif ctype == "textsectionu":
   636     elif ctype == "textsection":
   637         result = u''
   637         result = ''
   638         ll = obj[1].splitlines()
   638         ll = obj[1].splitlines()
   639         space = len(ll[-1]) - 2
   639         space = len(ll[-1]) - 2
   640         for l in ll[1:-1]:
   640         for l in ll[1:-1]:
   641             m = re.match(bqq, l)
   641             m = re.match(bqq, l)
   642             if m:
   642             if m:
   645                     r, x = parseLine(cmd, _inner, [], True, comment)
   645                     r, x = parseLine(cmd, _inner, [], True, comment)
   646                     if x: raise SyntaxError(cmd)
   646                     if x: raise SyntaxError(cmd)
   647                     result += _finish(r)
   647                     result += _finish(r)
   648                 except SyntaxError:
   648                 except SyntaxError:
   649                     if included:
   649                     if included:
   650                         raise SyntaxError(u"in " + included + u":" + u(line) + u": syntax error in executing command: " + cmd.strip())
   650                         raise SyntaxError("in " + included + ":" + u(line) + ": syntax error in executing command: " + cmd.strip())
   651                     else:
   651                     else:
   652                         raise SyntaxError(u"in " + u(line) + u": syntax error in executing command: " + cmd.strip())
   652                         raise SyntaxError("in " + u(line) + ": syntax error in executing command: " + cmd.strip())
   653             else:
   653             else:
   654                 if result != u'': result += u' '
   654                 if result != '': result += ' '
   655                 result += codegen(Symbol(u'quote', [u'> ' + l[space:]]))
   655                 result += codegen(Symbol('quote', ['> ' + l[space:]]))
   656         return code(result)
   656         return code(result)
   657 
   657 
   658     elif ctype == "lineQuote" or ctype == "quote":
   658     elif ctype == "lineQuote" or ctype == "quote":
   659         m, text, base, inds = None, u"", 0, 0
   659         m, text, base, inds = None, "", 0, 0
   660 
   660 
   661         if ctype == "lineQuote":
   661         if ctype == "lineQuote":
   662             text = obj[1]
   662             text = obj[1]
   663             m = lq.match(text)
   663             m = lq.match(text)
   664             if m:
   664             if m:
   672             if m:
   672             if m:
   673                 if m.group(1):
   673                 if m.group(1):
   674                     inds = int(m.group(1))
   674                     inds = int(m.group(1))
   675                 text = m.group(2)[1:]
   675                 text = m.group(2)[1:]
   676             else:
   676             else:
   677                 if type(text) is unicode or type(text) is str:
   677                 if type(text) is str:
   678                     text = u(evalPython(text))
   678                     text = u(evalPython(text))
   679 
   679 
   680         ind = u""
   680         ind = ""
   681         if inds > -1:
   681         if inds > -1:
   682             try:
   682             try:
   683                 cmd = evalPython(u"indent(" + u(inds) + u")")
   683                 cmd = evalPython("indent(" + u(inds) + ")")
   684                 result, rest = parseLine(u(cmd), _inner, [], True, comment)
   684                 result, rest = parseLine(u(cmd), _inner, [], True, comment)
   685                 if rest:
   685                 if rest:
   686                     raise SyntaxError()
   686                     raise SyntaxError()
   687                 ind = _finish(result)
   687                 ind = _finish(result)
   688             except: pass
   688             except: pass
   689         
   689         
   690         if ctype == "lineQuote": text += u"\n"
   690         if ctype == "lineQuote": text += "\n"
   691 
   691 
   692         hasTextFunc = False
   692         hasTextFunc = False
   693         try:
   693         try:
   694             ymlFunc["text"]
   694             ymlFunc["text"]
   695             hasTextFunc = True
   695             hasTextFunc = True
   699         return code(ind + text) 
   699         return code(ind + text) 
   700 
   700 
   701     elif ctype == "tagQuote":
   701     elif ctype == "tagQuote":
   702         m = tq.match(obj[1])
   702         m = tq.match(obj[1])
   703         if m.group(1) == "<":
   703         if m.group(1) == "<":
   704             return code(u"<" + m.group(2))
   704             return code("<" + m.group(2))
   705         else:
   705         else:
   706             return code(m.group(2))
   706             return code(m.group(2))
   707 
   707 
   708     elif ctype == "operator":
   708     elif ctype == "operator":
   709         operator.append((re.compile(evalPython(obj[1][0])), obj[1][1]))
   709         operator.append((re.compile(evalPython(obj[1][0])), obj[1][1]))
   710         return code(u"")
   710         return code("")
   711 
   711 
   712     elif ctype == "constant":
   712     elif ctype == "constant":
   713         name = obj[1][0]
   713         name = obj[1][0]
   714         if name[0] == "*":
   714         if name[0] == "*":
   715             name = name[1:]
   715             name = name[1:]
   716         value = obj[1][1]
   716         value = obj[1][1]
   717         pointers[name] = value
   717         pointers[name] = value
   718         return code(u"")
   718         return code("")
   719 
   719 
   720     elif ctype == "include":
   720     elif ctype == "include":
   721         reverse = False
   721         reverse = False
   722         ktext, kxml = False, False
   722         ktext, kxml = False, False
   723         for arg in obj[1]:
   723         for arg in obj[1]:
   726                     reverse = True
   726                     reverse = True
   727                 elif arg[0] == "ktext":
   727                 elif arg[0] == "ktext":
   728                     ktext = True
   728                     ktext = True
   729                 elif arg[0] == "kxml":
   729                 elif arg[0] == "kxml":
   730                     kxml = True
   730                     kxml = True
   731             elif type(arg) is unicode or type(arg) is str:
   731             elif type(arg) is str:
   732                 filemask = arg
   732                 filemask = arg
   733 
   733 
   734         if filemask[0] == '/' or filemask[0] == '.':
   734         if filemask[0] == '/' or filemask[0] == '.':
   735             files = sorted(glob(filemask))
   735             files = sorted(glob(filemask))
   736         else:
   736         else:
   742         if files and reverse:
   742         if files and reverse:
   743             files = files[-1::-1]
   743             files = files[-1::-1]
   744 
   744 
   745         if not(files):
   745         if not(files):
   746             if included:
   746             if included:
   747                 raise IOError(u"in " + included + ":" + u(line) + u": include file(s) '" + filemask + u"' not found")
   747                 raise IOError("in " + included + ":" + u(line) + ": include file(s) '" + filemask + "' not found")
   748             else:
   748             else:
   749                 raise IOError(u"in " + u(line) + u": include file(s) '" + filemask + u"' not found")
   749                 raise IOError("in " + u(line) + ": include file(s) '" + filemask + "' not found")
   750 
   750 
   751         includeFile = fileinput.input(files, mode="rU", openhook=fileinput.hook_encoded(encoding))
   751         includeFile = fileinput.input(files, mode="rU", openhook=fileinput.hook_encoded(encoding))
   752         _included = included
   752         _included = included
   753         if ktext or kxml:
   753         if ktext or kxml:
   754             text = u""
   754             text = ""
   755             for line in includeFile:
   755             for line in includeFile:
   756                 included = includeFile.filename()
   756                 included = includeFile.filename()
   757                 if kxml:
   757                 if kxml:
   758                     if (not line[:6] == '<?xml ') and (not line[:6] == '<?XML '):
   758                     if (not line[:6] == '<?xml ') and (not line[:6] == '<?XML '):
   759                         text += line
   759                         text += line
   778 
   778 
   779     elif ctype == "pythonCall":
   779     elif ctype == "pythonCall":
   780         parms = []
   780         parms = []
   781         data = obj[1]
   781         data = obj[1]
   782         for p in data:
   782         for p in data:
   783             if type(p) is unicode or type(p) is str:
   783             if type(p) is str:
   784                 name = p
   784                 name = p
   785             elif type(p) is tuple or type(p) is Symbol:
   785             elif type(p) is tuple or type(p) is Symbol:
   786                 ptype = p[0]
   786                 ptype = p[0]
   787                 if ptype == "parm":
   787                 if ptype == "parm":
   788                     if p[1][0][0] == "*":
   788                     if p[1][0][0] == "*":
   789                         parms.append(pointer(p[1][0]))
   789                         parms.append(pointer(p[1][0]))
   790                     else:
   790                     else:
   791                         parms.append(p[1][0])
   791                         parms.append(p[1][0])
   792         if len(parms) == 0:
   792         if len(parms) == 0:
   793             exp = name + u"()"
   793             exp = name + "()"
   794         elif len(parms) == 1:
   794         elif len(parms) == 1:
   795             exp = name + u"(" + u(parms[0]) + u")"
   795             exp = name + "(" + u(parms[0]) + ")"
   796         else:
   796         else:
   797             exp = name + u(tuple(parms))
   797             exp = name + u(tuple(parms))
   798         cmd = evalPython(exp)
   798         cmd = evalPython(exp)
   799         result, rest = parseLine(u(cmd), _inner, [], True, comment)
   799         result, rest = parseLine(u(cmd), _inner, [], True, comment)
   800         if rest:
   800         if rest:
   801             raise SyntaxError()
   801             raise SyntaxError()
   802         return code(_finish(result))
   802         return code(_finish(result))
   803 
   803 
   804     else:
   804     else:
   805         return code(u"")
   805         return code("")
   806 
   806 
   807 def _finish(tree):
   807 def _finish(tree):
   808     result = u""
   808     result = ""
   809     python = u""
   809     python = ""
   810 
   810 
   811     for el in tree:
   811     for el in tree:
   812         if el[0] == "python":
   812         if el[0] == "python":
   813             if el[1][0][:2] == "!!":
   813             if el[1][0][:2] == "!!":
   814                 python += el[1][0][2:-2]
   814                 python += el[1][0][2:-2]
   815             else:
   815             else:
   816                 python += el[1][0][1:] + u"\n"
   816                 python += el[1][0][1:] + "\n"
   817             continue
   817             continue
   818         else:
   818         else:
   819             if python:
   819             if python:
   820                 execPython(python)
   820                 execPython(python)
   821                 python = u""
   821                 python = ""
   822 
   822 
   823         try:
   823         try:
   824             result += codegen(el)
   824             result += codegen(el)
   825         except RuntimeError:
   825         except RuntimeError:
   826             if included:
   826             if included:
   827                 raise RuntimeError(u"in " + included + u":" + u(line))
   827                 raise RuntimeError("in " + included + ":" + u(line))
   828             else:
   828             else:
   829                 raise RuntimeError(u"in " + u(line))
   829                 raise RuntimeError("in " + u(line))
   830 
   830 
   831     if python:
   831     if python:
   832         execPython(python)
   832         execPython(python)
   833 
   833 
   834     return result
   834     return result