yml2/backend.py
changeset 58 a218553807ab
parent 57 2f4ad3800a3f
child 60 b19d0a86651b
equal deleted inserted replaced
57:2f4ad3800a3f 58:a218553807ab
     1 # 2.5.10 backend
     1 # 2.6.1 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 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 = [ key for key in 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
   494                 name = name[1:]
   494                 name = name[1:]
   495 
   495 
   496         try:
   496         try:
   497             ymlFunc[name]
   497             ymlFunc[name]
   498         except:
   498         except KeyError:
   499             try:
   499             try:
   500                 ymlFunc["_"]
   500                 if ymlFunc["_"].alias != "-":
   501                 return codegen(('func', ['_', ('content', [('funclist', [obj])])]))
   501                     return codegen(('func', ['_', ('content', [('funclist', [obj])])]))
   502             except:
   502                 else:
       
   503                     ymlFunc[name] = copy(ymlFunc["_"])
       
   504                     ymlFunc[name].alias = name.replace("_", "-")
       
   505                     return codegen(obj)
       
   506             except KeyError:
   503                 ymlFunc[name] = YF(name)
   507                 ymlFunc[name] = YF(name)
   504         
   508         
   505         if ymlFunc[name].alias == "-": avoidTag = True
   509         if ymlFunc[name].alias == "-": avoidTag = True
   506 
   510 
   507         to_add = []
   511         to_add = []
   508         if len(ymlFunc[name].descends):
   512         if len(ymlFunc[name].descends):
   509             if obj[1][-1][0] != 'content':
   513             if obj[1][-1][0] != 'content':
   510                 if included:
   514                 if included:
   511                     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")
   512                 else:
   516                 else:
   513                     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")
   514 
   518 
   515             def first_func(obj):
   519             def first_func(obj):
   516                 if type(obj) is tuple or type(obj) is Symbol:
   520                 if type(obj) is tuple or type(obj) is Symbol:
   517                     if obj[0] == 'func':
   521                     if obj[0] == 'func':
   518                         return obj
   522                         return obj
   557                     for dname in ymlFunc[name].descends:
   561                     for dname in ymlFunc[name].descends:
   558                         f, c = first_func(c), copy_without_first_func(c)
   562                         f, c = first_func(c), copy_without_first_func(c)
   559                         if dname[0] == "*":
   563                         if dname[0] == "*":
   560                             pointers[dname[1:]] = "'" + f[1][0] + "'"
   564                             pointers[dname[1:]] = "'" + f[1][0] + "'"
   561                         else:
   565                         else:
   562                             add_params.append( ('parm', [dname, u"'" + f[1][0] + u"'"]) )
   566                             add_params.append( ('parm', [dname, "'" + f[1][0] + "'"]) )
   563                         try:
   567                         try:
   564                             add_params.extend( get_parms(f) )
   568                             add_params.extend( get_parms(f) )
   565                         except: pass
   569                         except: pass
   566 
   570 
   567                     new_things = [ e[1][0] ]
   571                     new_things = [ e[1][0] ]
   569                     new_things.append( ('content', c) )
   573                     new_things.append( ('content', c) )
   570                     
   574                     
   571                     to_add.append( ('func', new_things ) )
   575                     to_add.append( ('func', new_things ) )
   572             except:
   576             except:
   573                 if included:
   577                 if included:
   574                     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")
   575                 else:
   579                 else:
   576                     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")
   577 
   581 
   578         if not to_add:
   582         if not to_add:
   579             to_add = ( obj, )
   583             to_add = ( obj, )
   580 
   584 
   581         complete = u""
   585         complete = ""
   582 
   586 
   583         for obj in to_add:
   587         for obj in to_add:
   584             subtree = None
   588             subtree = None
   585             try:
   589             try:
   586                 if obj[1][-1][0] == "content":
   590                 if obj[1][-1][0] == "content":
   600             if subtree:
   604             if subtree:
   601                 for sel in subtree:
   605                 for sel in subtree:
   602                     result += codegen(sel)
   606                     result += codegen(sel)
   603 
   607 
   604             if hasContent and not(avoidTag):
   608             if hasContent and not(avoidTag):
   605                 result += u"</" + ymlFunc[name].alias + u">"
   609                 result += "</" + ymlFunc[name].alias + ">"
   606 
   610 
   607             complete += result
   611             complete += result
   608 
   612 
   609         return code(complete)
   613         return code(complete)
   610 
   614 
   611     elif ctype == "textsection":
   615     elif ctype == "textsection":
   612         result = u''
   616         result = ''
   613         ll = obj[1].splitlines()
   617         ll = obj[1].splitlines()
   614         space = len(ll[-1]) - 2
   618         space = len(ll[-1]) - 2
   615         for l in ll[1:-1]:
   619         for l in ll[1:-1]:
   616             m = re.match(bqq, l)
   620             m = re.match(bqq, l)
   617             if m:
   621             if m:
   620                     r, x = parseLine(cmd, _inner, [], True, comment)
   624                     r, x = parseLine(cmd, _inner, [], True, comment)
   621                     if x: raise SyntaxError(cmd)
   625                     if x: raise SyntaxError(cmd)
   622                     result += _finish(r)
   626                     result += _finish(r)
   623                 except SyntaxError:
   627                 except SyntaxError:
   624                     if included:
   628                     if included:
   625                         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())
   626                     else:
   630                     else:
   627                         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())
   628             else:
   632             else:
   629                 result += codegen(Symbol(u'lineQuote', u'| ' + l[space:]))
   633                 result += codegen(Symbol('lineQuote', '| ' + l[space:]))
   630         return code(result)
   634         return code(result)
   631 
   635 
   632     elif ctype == "textsectionu":
   636     elif ctype == "textsectionu":
   633         result = u''
   637         result = ''
   634         ll = obj[1].splitlines()
   638         ll = obj[1].splitlines()
   635         space = len(ll[-1]) - 2
   639         space = len(ll[-1]) - 2
   636         for l in ll[1:-1]:
   640         for l in ll[1:-1]:
   637             m = re.match(bqq, l)
   641             m = re.match(bqq, l)
   638             if m:
   642             if m:
   641                     r, x = parseLine(cmd, _inner, [], True, comment)
   645                     r, x = parseLine(cmd, _inner, [], True, comment)
   642                     if x: raise SyntaxError(cmd)
   646                     if x: raise SyntaxError(cmd)
   643                     result += _finish(r)
   647                     result += _finish(r)
   644                 except SyntaxError:
   648                 except SyntaxError:
   645                     if included:
   649                     if included:
   646                         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())
   647                     else:
   651                     else:
   648                         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())
   649             else:
   653             else:
   650                 if result != u'': result += u' '
   654                 if result != '': result += ' '
   651                 result += codegen(Symbol(u'quote', [u'> ' + l[space:]]))
   655                 result += codegen(Symbol('quote', ['> ' + l[space:]]))
   652         return code(result)
   656         return code(result)
   653 
   657 
   654     elif ctype == "lineQuote" or ctype == "quote":
   658     elif ctype == "lineQuote" or ctype == "quote":
   655         m, text, base, inds = None, u"", 0, 0
   659         m, text, base, inds = None, "", 0, 0
   656 
   660 
   657         if ctype == "lineQuote":
   661         if ctype == "lineQuote":
   658             text = obj[1]
   662             text = obj[1]
   659             m = lq.match(text)
   663             m = lq.match(text)
   660             if m:
   664             if m:
   668             if m:
   672             if m:
   669                 if m.group(1):
   673                 if m.group(1):
   670                     inds = int(m.group(1))
   674                     inds = int(m.group(1))
   671                 text = m.group(2)[1:]
   675                 text = m.group(2)[1:]
   672             else:
   676             else:
   673                 if type(text) is unicode or type(text) is str:
   677                 if type(text) is str:
   674                     text = u(evalPython(text))
   678                     text = u(evalPython(text))
   675 
   679 
   676         ind = u""
   680         ind = ""
   677         if inds > -1:
   681         if inds > -1:
   678             try:
   682             try:
   679                 cmd = evalPython(u"indent(" + u(inds) + u")")
   683                 cmd = evalPython("indent(" + u(inds) + ")")
   680                 result, rest = parseLine(u(cmd), _inner, [], True, comment)
   684                 result, rest = parseLine(u(cmd), _inner, [], True, comment)
   681                 if rest:
   685                 if rest:
   682                     raise SyntaxError()
   686                     raise SyntaxError()
   683                 ind = _finish(result)
   687                 ind = _finish(result)
   684             except: pass
   688             except: pass
   685         
   689         
   686         if ctype == "lineQuote": text += u"\n"
   690         if ctype == "lineQuote": text += "\n"
   687 
   691 
   688         hasTextFunc = False
   692         hasTextFunc = False
   689         try:
   693         try:
   690             ymlFunc["text"]
   694             ymlFunc["text"]
   691             hasTextFunc = True
   695             hasTextFunc = True
   695         return code(ind + text) 
   699         return code(ind + text) 
   696 
   700 
   697     elif ctype == "tagQuote":
   701     elif ctype == "tagQuote":
   698         m = tq.match(obj[1])
   702         m = tq.match(obj[1])
   699         if m.group(1) == "<":
   703         if m.group(1) == "<":
   700             return code(u"<" + m.group(2))
   704             return code("<" + m.group(2))
   701         else:
   705         else:
   702             return code(m.group(2))
   706             return code(m.group(2))
   703 
   707 
   704     elif ctype == "operator":
   708     elif ctype == "operator":
   705         operator.append((re.compile(evalPython(obj[1][0])), obj[1][1]))
   709         operator.append((re.compile(evalPython(obj[1][0])), obj[1][1]))
   706         return code(u"")
   710         return code("")
   707 
   711 
   708     elif ctype == "constant":
   712     elif ctype == "constant":
   709         name = obj[1][0]
   713         name = obj[1][0]
   710         if name[0] == "*":
   714         if name[0] == "*":
   711             name = name[1:]
   715             name = name[1:]
   712         value = obj[1][1]
   716         value = obj[1][1]
   713         pointers[name] = value
   717         pointers[name] = value
   714         return code(u"")
   718         return code("")
   715 
   719 
   716     elif ctype == "include":
   720     elif ctype == "include":
   717         reverse = False
   721         reverse = False
   718         ktext, kxml = False, False
   722         ktext, kxml = False, False
   719         for arg in obj[1]:
   723         for arg in obj[1]:
   722                     reverse = True
   726                     reverse = True
   723                 elif arg[0] == "ktext":
   727                 elif arg[0] == "ktext":
   724                     ktext = True
   728                     ktext = True
   725                 elif arg[0] == "kxml":
   729                 elif arg[0] == "kxml":
   726                     kxml = True
   730                     kxml = True
   727             elif type(arg) is unicode or type(arg) is str:
   731             elif type(arg) is str:
   728                 filemask = arg
   732                 filemask = arg
   729 
   733 
   730         if filemask[0] == '/' or filemask[0] == '.':
   734         if filemask[0] == '/' or filemask[0] == '.':
   731             files = sorted(glob(filemask))
   735             files = sorted(glob(filemask))
   732         else:
   736         else:
   738         if files and reverse:
   742         if files and reverse:
   739             files = files[-1::-1]
   743             files = files[-1::-1]
   740 
   744 
   741         if not(files):
   745         if not(files):
   742             if included:
   746             if included:
   743                 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")
   744             else:
   748             else:
   745                 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")
   746 
   750 
   747         includeFile = fileinput.input(files, mode="rU", openhook=fileinput.hook_encoded(encoding))
   751         includeFile = fileinput.input(files, mode="rU", openhook=fileinput.hook_encoded(encoding))
   748         _included = included
   752         _included = included
   749         if ktext or kxml:
   753         if ktext or kxml:
   750             text = u""
   754             text = ""
   751             for line in includeFile:
   755             for line in includeFile:
   752                 included = includeFile.filename()
   756                 included = includeFile.filename()
   753                 if kxml:
   757                 if kxml:
   754                     if (not line[:6] == '<?xml ') and (not line[:6] == '<?XML '):
   758                     if (not line[:6] == '<?xml ') and (not line[:6] == '<?XML '):
   755                         text += line
   759                         text += line
   774 
   778 
   775     elif ctype == "pythonCall":
   779     elif ctype == "pythonCall":
   776         parms = []
   780         parms = []
   777         data = obj[1]
   781         data = obj[1]
   778         for p in data:
   782         for p in data:
   779             if type(p) is unicode or type(p) is str:
   783             if type(p) is str:
   780                 name = p
   784                 name = p
   781             elif type(p) is tuple or type(p) is Symbol:
   785             elif type(p) is tuple or type(p) is Symbol:
   782                 ptype = p[0]
   786                 ptype = p[0]
   783                 if ptype == "parm":
   787                 if ptype == "parm":
   784                     if p[1][0][0] == "*":
   788                     if p[1][0][0] == "*":
   785                         parms.append(pointer(p[1][0]))
   789                         parms.append(pointer(p[1][0]))
   786                     else:
   790                     else:
   787                         parms.append(p[1][0])
   791                         parms.append(p[1][0])
   788         if len(parms) == 0:
   792         if len(parms) == 0:
   789             exp = name + u"()"
   793             exp = name + "()"
   790         elif len(parms) == 1:
   794         elif len(parms) == 1:
   791             exp = name + u"(" + u(parms[0]) + u")"
   795             exp = name + "(" + u(parms[0]) + ")"
   792         else:
   796         else:
   793             exp = name + u(tuple(parms))
   797             exp = name + u(tuple(parms))
   794         cmd = evalPython(exp)
   798         cmd = evalPython(exp)
   795         result, rest = parseLine(u(cmd), _inner, [], True, comment)
   799         result, rest = parseLine(u(cmd), _inner, [], True, comment)
   796         if rest:
   800         if rest:
   797             raise SyntaxError()
   801             raise SyntaxError()
   798         return code(_finish(result))
   802         return code(_finish(result))
   799 
   803 
   800     else:
   804     else:
   801         return code(u"")
   805         return code("")
   802 
   806 
   803 def _finish(tree):
   807 def _finish(tree):
   804     result = u""
   808     result = ""
   805     python = u""
   809     python = ""
   806 
   810 
   807     for el in tree:
   811     for el in tree:
   808         if el[0] == "python":
   812         if el[0] == "python":
   809             if el[1][0][:2] == "!!":
   813             if el[1][0][:2] == "!!":
   810                 python += el[1][0][2:-2]
   814                 python += el[1][0][2:-2]
   811             else:
   815             else:
   812                 python += el[1][0][1:] + u"\n"
   816                 python += el[1][0][1:] + "\n"
   813             continue
   817             continue
   814         else:
   818         else:
   815             if python:
   819             if python:
   816                 execPython(python)
   820                 execPython(python)
   817                 python = u""
   821                 python = ""
   818 
   822 
   819         try:
   823         try:
   820             result += codegen(el)
   824             result += codegen(el)
   821         except RuntimeError:
   825         except RuntimeError:
   822             if included:
   826             if included:
   823                 raise RuntimeError(u"in " + included + u":" + u(line))
   827                 raise RuntimeError("in " + included + ":" + u(line))
   824             else:
   828             else:
   825                 raise RuntimeError(u"in " + u(line))
   829                 raise RuntimeError("in " + u(line))
   826 
   830 
   827     if python:
   831     if python:
   828         execPython(python)
   832         execPython(python)
   829 
   833 
   830     return result
   834     return result