yat.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 #
00003 # @brief YAT: YAml Template text processor
00004 # @date $Date: 2008-02-09 20:04:27 $
00005 # @author Norkai Ando <n-ando@aist.go.jp>
00006 #
00007 # Copyright (C) 2008 Noriaki Ando, All rights reserved.
00008 #
00009 # $Id: yat.py 775 2008-07-28 16:14:45Z n-ando $
00010 #
00011 
00012 #
00013 # Usage:
00014 #------------------------------------------------------------
00015 # import yaml
00016 # import yat
00017 #
00018 # dict   = yaml.load(open(filename, "r").read())
00019 # t      = yat.Template(template, "\[", "\]")
00020 # result = t.generate(dict)
00021 #------------------------------------------------------------
00022 #
00023 # 1. Simple directive:
00024 #    [dictionary_key]
00025 #
00026 #    Nested dictionaries can be expressed by dotted expression.
00027 #
00028 # example:
00029 # dict = {"a": "This is a",
00030 #         "b": {"1": "This is b.1",
00031 #               "2": "This is b.2"}
00032 #        }
00033 #
00034 # template:
00035 # [a]
00036 #
00037 # [b.1]
00038 #
00039 # [b.2]
00040 #
00041 # result:
00042 # This is a
00043 # This is b.1
00044 # This is b.2
00045 #
00046 #
00047 # 2. "for" directive:
00048 #    [for key in list] statement [endfor]
00049 #    [for-inv key in list] statement [endfor] (inverted)
00050 #
00051 #    Iterative evaluation for listed values is performed by "for" statement.
00052 #    In iteration at each evaluation, the value of the list is assigned to
00053 #    "key". The "key" also can be the nested dictionary directive.
00054 #
00055 # example:
00056 # dict = {"list": [0, 1, 2],
00057 #         "listed_dict": [
00058 #           {"name": "x", "value": "1.0"},
00059 #           {"name": "y", "value": "0.2"},
00060 #           {"name": "z", "value": "0.1"}]}
00061 #
00062 # template:
00063 # [for lst in list][lst], [endfor]
00064 # [for-inv lst in list][lst], [endfor]
00065 # [for lst in listed_dict]
00066 # [lst.name]: [lst.value]
00067 # 
00068 # [endfor]
00069 #
00070 # result:
00071 # 1, 2, 3,
00072 # 3, 2, 1
00073 # x: 1.0
00074 # y: 0.2
00075 # x: 0.1
00076 #
00077 #
00078 # 3. "if-index" directive:
00079 #    [for key in val]
00080 #    [if-index key is first|even|odd|last|NUMBER] statement1
00081 #    [elif-index key is first|even|odd|last|NUMBER] statement2
00082 #    [endif][endfor]
00083 #
00084 #    "if-index" is used to specify the index of the "for" iteration.
00085 #    The "key" string which is defined in the "for" statement is used as index.
00086 #    A number or predefined directives such as "first", "even", "odd" and
00087 #    "last" can be used to specify the index.
00088 #
00089 # example:
00090 # dict = {"list": [0,1,2,3,4,5,6,7,8,9,10]}
00091 #
00092 # template:
00093 # [for key in list]
00094 # [if-index key is 3] [key] is hoge!!
00095 # [elif-index key is 6] [key] is foo!!
00096 # [elif-index key is 9] [key] is bar!!
00097 # [elif-index key is first] [key] is first
00098 # [elif-index key is last] Omoro-------!!!!
00099 # [elif-index key is odd] [key] is odd number
00100 # [elif-index key is even] [key] is even number
00101 # [endif]
00102 # [endfor]
00103 #
00104 # result:
00105 #  0 is first
00106 #  1 is odd number
00107 #  2 is even number
00108 #  3 is hoge!!
00109 #  4 is even number
00110 #  5 is odd number
00111 #  6 is foo!!
00112 #  7 is odd number
00113 #  8 is even number
00114 #  9 is bar!!
00115 #  Omoro-------!!!!
00116 #
00117 #
00118 # 4. "if" directive: 
00119 #       [if key is "string"] text1 [else] text2 [endif]
00120 #       [if key is 'string'] text1 [else] text2 [endif]
00121 #       [if key is value] text1 [else] text2 [endif]
00122 #    If "key" is [value] or "string", "text1" appears,
00123 #    otherwise "text2" appears.
00124 #
00125 # example:
00126 # dict = {"key1": "a", "key2": "b", "key3": "a"}
00127 #
00128 # template:
00129 # [if key1 is 'a']
00130 # The key1 is "a".
00131 # [elif key1 is key3]
00132 # This key1 is not "a".
00133 # [endif]
00134 #
00135 # result:
00136 # The key1 is "a".
00137 #
00138 #
00139 # 5. "if-any" directive: [if-any key1] text1 [else] text2 [endif]
00140 #    If the "key1" exists in the dictionary, "text1" appears, otherwise
00141 #    "text2" appears.
00142 #
00143 # example:
00144 # dict = {"key1": "a", "key2": "b"}
00145 #
00146 # template:
00147 # [if-any key1]
00148 # key1 exists.
00149 # [endif][if-any key3]
00150 # key3 exists.
00151 # [else]
00152 # key3 does not exists.
00153 # [endif]
00154 #
00155 # result:
00156 # key1 exists.
00157 # key3 does not exists.
00158 #
00159 #
00160 # 6. bracket and comment:
00161 #    [[] is left bracket if begin mark is "["
00162 #    [# comment ] is comment if begin/end marks are "[" and "]"
00163 #
00164 # example:
00165 # dict = {}
00166 #
00167 # template:
00168 # [[]bracket]
00169 # [# comment]
00170 #
00171 # result:
00172 # [bracket]
00173 #
00174 import string
00175 import re
00176 from types import StringType, IntType, FloatType, DictType, ListType, ClassType
00177 import sys
00178 
00179 class Template:
00180     """
00181     usage:
00182       tempalte_text = read template text from file
00183       dictionary    = create dictionaly by using yaml
00184       t = Template(tempalte_text)
00185       generated_text = t.generate(dictionary)
00186 
00187     """
00188     
00189     def __init__(self, template, begin_mark="\[", end_mark="\]"):
00190         self.__procs = [self.__proc_text,
00191                         self.__proc_cmd,
00192                         self.__proc_bracket]
00193         self.template = template
00194 
00195         # regular expression to devide text into DIRECTIVE, BRACKET and COMMENT
00196         #
00197         # default:
00198         # START_MARK: "["
00199         # END_MARK  : "]"
00200         # -> START_MARK and END_MARK can be given in ctor
00201         #
00202         # ITEM: (?:"(?:[^\\"]|\\.)*"|[-\w.]+)
00203         # \[(ITEM(?: +ITEM)*)\]|(\[\[\])|\[#[^\]]*\]
00204         # ~~~~~~~~(1)~~~~~~ ~~(2)~~~ ~~~(3)~~~~~
00205         # (1) COMMAND  : '[' ITEM (whitespace ITEM)* ']
00206         #     ITEM     : STRING | NAME
00207         #     STRING   : '"' (not-slash-or-dquote | '\' anychar)* '"'
00208         #     NAME     : (alphanum | '_' | '-' | '.')+
00209         # (2) BEGIN_MARK_ESCAPE : '[[]'
00210         # (3) COMMENT  : '[#' not-rbracket
00211         #        
00212         # re_item      = r'(?:"(?:[^\\"]|\\.)*"|[-\w.]+)'
00213         # re_command   = r'\[(%s(?: +%s)*)\]' % (re_item, re_item)
00214         # re_beginmark = r'\[\[\]'
00215         # re_comment   = r'\[#[^\]]*\]'
00216         # re_parse     = re.compile(r'%s|(%s)|%s' 
00217         #                     % (re_command, re_beginmark, re_comment))
00218         # re_args      = re.compile(r'"(?:[^\\"]|\\.)*"|[-\w.]+')
00219         #
00220         #
00221         re_item      = r'(?:"(?:[^\\"]|\\.)*"|[-\w.:]+)'
00222         re_command   = r'%s(%s(?: +%s)*)%s' % \
00223             (begin_mark, re_item, re_item, end_mark)
00224         re_bracket   = r'%s%s%s' % \
00225             (begin_mark, begin_mark, end_mark)
00226         re_comment   = r'%s#[^%s]*%s' % \
00227             (begin_mark, end_mark, end_mark)
00228         self.begin_mark = begin_mark.replace("\\","")
00229         self.re_parse = re.compile(r'%s|(%s)|%s' % \
00230                                        (re_command, re_bracket, re_comment))
00231         self.re_args  = re.compile(r'"(?:[^\\"]|\\.)*"|[-\w.:]+')
00232         self.re_number = re.compile(r'[0-9]+')
00233 
00234         # tokenize input text
00235         self.token = self.re_parse.split(self.template)
00236         self.token_len  = len(self.token)
00237         
00238         # initialize variables
00239         self.script = program
00240         self.indent = 4
00241         self.script_level  = 2
00242         self.level = 0
00243         self.index = 0
00244         self.cmd_cxt = []
00245 
00246         # parse token
00247         self.__parse_template(self.token)
00248 
00249         return
00250 
00251     def generate(self, dict):
00252         # eval generated script
00253         exec(self.script)
00254         # script includes Generator class
00255         gen = Generator(self.token, dict)
00256         # execute generated script
00257         return gen.generate()
00258 
00259     def get_script(self):
00260         return self.script
00261 
00262     def __push_level(self):
00263         self.level += 1
00264 
00265     def __pop_level(self):
00266         self.level -= 1
00267 
00268     def __write_cmd(self, cmd):
00269         tmp_cmd  = self.__indent()
00270         tmp_cmd += "self.set_index(%s)\n" % (self.index)
00271         self.script += tmp_cmd
00272         self.__write_cmd_noindex(cmd)
00273 
00274     def __write_cmd_noindex(self, cmd):
00275         tmp_cmd  = self.__indent()
00276         tmp_cmd += cmd + "\n"
00277         self.script += tmp_cmd
00278 
00279     def __parse_template(self, dict):
00280         try:
00281             # split into (TEXT DIRECTIVE BRACKET)* TEXT
00282             self.__parse()
00283         except YATException, e:
00284             self.__print_error(e)
00285             sys.exit(-1)
00286 
00287     def __indent(self):
00288         indent = " " * ((self.script_level + self.level) * self.indent)
00289         return indent
00290 
00291     def __parse(self):
00292         while self.index < self.token_len:
00293             self.__procs[self.index % 3]()
00294             self.index += 1
00295 
00296     def __proc_text(self):
00297         if self.token[self.index] == None:
00298             return
00299         cmd_text = "self.write_token(%s)" % (self.index)
00300         self.__write_cmd(cmd_text)
00301         return True
00302  
00303     def __proc_bracket(self):
00304         if self.token[self.index] == None:
00305             return
00306         cmd_text = "self.write(\"" + self.begin_mark + "\")"
00307         self.__write_cmd(cmd_text)
00308         return True
00309             
00310     def __proc_cmd(self):
00311         cmd = self.token[self.index]
00312         try:
00313             args = self.re_args.findall(cmd)
00314         except:
00315             return
00316         self.del_nl_after_cmd()
00317         argc = len(args)
00318         if argc == 0:
00319             raise InvalidDirective(self.lineno(), "_an empty directive_ ")
00320 
00321         # simple directive
00322         if argc == 1:
00323             if   args[0] == "endfor":
00324                 self.__endfor_cmd(args)
00325                 return
00326             elif args[0] == "else":
00327                 self.__else_cmd(args)
00328                 return
00329             elif args[0] == "last":
00330                 self.__last_cmd(args)
00331                 return
00332             elif args[0] == "endif":
00333                 self.__endif_cmd(args)
00334                 return
00335             else:
00336                 self.__cmd(args)
00337                 return
00338         elif argc == 2:
00339             if args[0] == "if-any":
00340                 self.__if_any_cmd(args)
00341                 return
00342         elif argc == 4: # [for key in value]
00343             if args[0] == "for" and args[2] == "in":
00344                 self.__for_cmd(args)
00345                 return True
00346             elif args[0] == "for-inv" and args[2] == "in":
00347                 self.__for_inv_cmd(args)
00348                 return True
00349             elif args[0] == "if" and args[2] == "is":
00350                 self.__if_cmd(args)
00351             elif args[0] == "elif" and args[2] == "is":
00352                 self.__elif_cmd(args)
00353             elif args[0] == "if-index" and args[2] == "is":
00354                 self.__if_index_cmd(args)
00355             elif args[0] == "elif-index" and args[2] == "is":
00356                 self.__elif_index_cmd(args)
00357             else:
00358                 raise InvalidDirective(self.lineno(), cmd)
00359         else:
00360             raise InvalidDirective(self.lineno(), cmd)
00361         return True
00362 
00363     def __cmd(self, args):
00364         cmd_text = "self.write_dict(\"%s\")" % (args[0])
00365         self.__write_cmd(cmd_text)
00366 
00367     #------------------------------------------------------------
00368     # [for] commands
00369     # - for
00370     # - last
00371     # - endfor
00372     #------------------------------------------------------------
00373     def __for_cmd(self, args):
00374         """
00375         The following [for] directive
00376           [for tmp_key in directive]
00377         is converted into the following python command.
00378           for i in len(directive):
00379               self.dicts.append({tmp_key: ditective[i])
00380         and, endfor directive terminate as the following,
00381               self.dicts.pop()
00382         """
00383         key = args[1]
00384         directive = args[3]
00385         # (key)     : variable string of index variable for [for] block
00386         # (key)_list: list value of specified directive
00387         # (key)_len : length of the list
00388         cmd_text = "%s_list = self.get_list(\"%s\")" % (key, directive)
00389         self.__write_cmd(cmd_text)
00390         cmd_text = "%s_len = len(%s_list)" % (key, key)
00391         self.__write_cmd(cmd_text)
00392         cmd_text = "for %s_index in range(len(%s_list)):" % (key, key)
00393         self.__write_cmd(cmd_text)
00394         self.__push_level()
00395         cmd_text = "self.push_dict({\"%s\": %s_list[%s_index]})" \
00396             % (key, key, key)
00397         self.__write_cmd(cmd_text)
00398         self.cmd_cxt.append("for")
00399 
00400     def __for_inv_cmd(self, args):
00401         """
00402         The following [for] directive
00403           [for tmp_key in directive]
00404         is converted into the following python command.
00405           for i in len(directive):
00406               self.dicts.append({tmp_key: ditective[i])
00407         and, endfor directive terminate as the following,
00408               self.dicts.pop()
00409         """
00410         key = args[1]
00411         directive = args[3]
00412         # (key)     : variable string of index variable for [for] block
00413         # (key)_list: list value of specified directive
00414         # (key)_len : length of the list
00415         cmd_text = "%s_list = self.get_list(\"%s\")" % (key, directive)
00416         self.__write_cmd(cmd_text)
00417         cmd_text = "%s_len = len(%s_list)" % (key, key)
00418         self.__write_cmd(cmd_text)
00419         cmd_text = "for %s_index in range(len(%s_list))[::-1]:" % (key, key)
00420         self.__write_cmd(cmd_text)
00421         self.__push_level()
00422         cmd_text = "self.push_dict({\"%s\": %s_list[%s_index]})" \
00423             % (key, key, key)
00424         self.__write_cmd(cmd_text)
00425         self.cmd_cxt.append("for-inv")
00426 
00427     def __endfor_cmd(self, args):
00428         try:
00429             cxt = self.cmd_cxt.pop()
00430             if cxt != "for" and cxt != "for-inv":
00431                 raise UnmatchedBlock(self.lineno(), "endfor")
00432             self.__write_cmd("self.pop_dict()")
00433             self.__pop_level()
00434         except:
00435             print args, self.lineno()
00436             raise UnmatchedBlock(self.lineno(), "endfor")
00437         return
00438 
00439     # end of [for] commands
00440     #------------------------------------------------------------
00441 
00442     #------------------------------------------------------------
00443     # [if] commands
00444     # - if
00445     # - if-index
00446     # - if-any
00447     #------------------------------------------------------------
00448     def __if_cmd(self, args):
00449         """
00450         The following [if] directive
00451           [if directive is string]
00452         is converted into the following python command.
00453           if self.__get_string() == "string":
00454         """
00455         directive = args[1]
00456         string = args[3]
00457         if string[0] == '"' or string[-1] == "'" \
00458                 or string[0] == '"' or string[-1] == "'":
00459             cmd_text = "if self.get_text(\"%s\") == %s:" % \
00460             (directive, string)
00461         else:
00462             cmd_text = "if self.get_text(\"%s\") == self.get_text(\"%s\"):" % \
00463             (directive, string)
00464         self.__write_cmd(cmd_text)
00465         self.__push_level()
00466         self.cmd_cxt.append("if")
00467         return
00468 
00469     def __elif_cmd(self, args):
00470         if self.cmd_cxt[-1] != "if":
00471             raise UnmatchedBlock(self.lineno(), "elif")
00472         directive = args[1]
00473         string = args[3]
00474         if string[0] == '"' or string[-1] == "'" \
00475                 or string[0] == '"' or string[-1] == "'":
00476             cmd_text = "elif self.get_text(\"%s\") == %s:" % \
00477             (directive, string)
00478         else:
00479             cmd_text = "elif self.get_text(\"%s\") == self.get_text(\"%s\"):" % \
00480             (directive, string)
00481         self.__pop_level()
00482         self.__write_cmd_noindex(cmd_text)
00483         self.__push_level()
00484         return
00485 
00486     # [if-index] commands
00487     def __if_index_cmd(self, args):
00488         # [if-index KEY is [first|even|odd|last|NUMBER]]
00489         #  ~~~0~~~  ~1~  2 ~~~~~~~~~~~~~~3~~~~~~~~~~~~
00490         cmdlist = {"first": "if %s_index == 0:",
00491                    "even" : "if (%s_index %% 2) == 0:",
00492                    "odd"  : "if (%s_index %% 2) != 0:",
00493                    "last" : "if %s_index == %s_len - 1:"}
00494         key = args[1]
00495         cmd = args[3]
00496         if len(self.re_number.findall(cmd)) == 1:
00497             cmd_text = "if %s_index == %s:" % (key, cmd)
00498         elif cmdlist.has_key(cmd):
00499             if cmd == "last":
00500                 cmd_text = cmdlist[cmd] % (key,key)
00501             else:
00502                 cmd_text = cmdlist[cmd] % (key)
00503         else:
00504             raise InvalidDirective(self.lineno(), ''.join(args))
00505         self.__write_cmd(cmd_text)
00506         self.__push_level()
00507         self.cmd_cxt.append("if-index")
00508 
00509     def __elif_index_cmd(self, args):
00510         if self.cmd_cxt[-1] != "if-index":
00511             raise UnmatchedBlock(self.lineno(), "elif-index")
00512         # [elif-index KEY is [first|even|odd|last|NUMBER]]
00513         #  ~~~0~~~  ~1~  2 ~~~~~~~~~~~~~~3~~~~~~~~~~~~
00514         cmdlist = {"first": "elif %s_index == 0:",
00515                    "even" : "elif (%s_index %% 2) == 0:",
00516                    "odd"  : "elif (%s_index %% 2) != 0:",
00517                    "last" : "elif %s_index == %s_len - 1:"}
00518         key = args[1]
00519         cmd = args[3]
00520         if len(self.re_number.findall(cmd)) == 1:
00521             cmd_text = "elif %s_index == %s:" % (key, cmd)
00522         elif cmdlist.has_key(cmd):
00523             if cmd == "last":
00524                 cmd_text = cmdlist[cmd] % (key,key)
00525             else:
00526                 cmd_text = cmdlist[cmd] % (key)
00527         else:
00528             raise InvalidDirective(self.lineno(), ' '.join(args))
00529         self.__pop_level()
00530         self.__write_cmd_noindex(cmd_text)
00531         self.__push_level()
00532 
00533     # [if-any] command
00534     def __if_any_cmd(self, args):
00535         directive = args[1]
00536         cmd_text = "if self.has_key(\"%s\"):" % (directive)
00537         self.__write_cmd(cmd_text)
00538         self.__push_level()
00539         self.cmd_cxt.append("if-any")
00540         return
00541 
00542     def __elif_any_cmd(self, args):
00543         if self.cmd_cxt[-1] != "if-any":
00544             raise UnmatchedBlock(self.lineno(), "elif-any")
00545         directive = args[1]
00546         cmd_text = "if self.has_key(\"%s\"):" % (directive)
00547         self.__pop_level()
00548         self.__write_cmd_noindex(cmd_text)
00549         self.__push_level()
00550         return
00551 
00552     # [else], [endif] commands
00553     def __else_cmd(self, args):
00554         if self.cmd_cxt[-1] != "if" and self.cmd_cxt[-1] != "if-index" \
00555                 and self.cmd_cxt[-1] != "if-any":
00556             raise UnmatchedBlock(self.lineno(), "else")
00557         self.__pop_level()
00558         self.__write_cmd_noindex("else:")
00559         self.__push_level()
00560         return
00561 
00562     def __endif_cmd(self, args):
00563         try:
00564             if self.cmd_cxt[-1] != "if" and self.cmd_cxt[-1] != "if-index" \
00565                     and self.cmd_cxt[-1] != "if-any":
00566                 raise UnmatchedBlock(self.lineno(), "endif")
00567             self.cmd_cxt.pop()
00568             self.__pop_level()
00569         except:
00570             raise UnmatchedBlock(self.lineno(), "endif")
00571         return
00572     # end of [if] commands
00573     #------------------------------------------------------------
00574 
00575     def __print_error(self, e):
00576         print "Parse Error: line", e.lineno, "in input data"
00577         print "  " + ''.join(nesteditem(e.value))
00578         lines = self.template.split("\n")
00579         length = len(lines)
00580         print "------------------------------------------------------------"
00581         for i in range(1,10):
00582             l = e.lineno - 6 + i
00583             if l > 0 and l < length:
00584                 print lines[l]
00585                 if i == 5:
00586                     uline = '~'*len(lines[l])
00587                     print uline
00588         print "------------------------------------------------------------"
00589         if hasattr(e, 'context'):
00590             print "Current context:"
00591             print e.context
00592 
00593     
00594     def del_nl_after_cmd(self):
00595         # next text index after command
00596         next = self.index + 2
00597         if next > self.token_len: return
00598         if self.token[next] == None: return
00599         text = self.token[next]
00600         tlen = len(text)
00601         if tlen > 0 and text[0] == '\n':
00602             self.token[next] = text[1:]
00603             return
00604         elif tlen > 0 and text[0] == '\r':
00605             self.token[next] = text[1:]
00606             return
00607         elif tlen > 1 and text[0:2] == '\r\n':
00608             self.token[next] = text[2:]
00609 
00610     def lineno(self):
00611         l = 1
00612         for i in range(self.index):
00613             if isinstance(self.token[i], StringType):
00614                 l += self.token[i].count('\n')
00615         for i in range(1, self.index, 3):
00616             l += 1
00617         return l
00618 
00619 
00620 #------------------------------------------------------------
00621 # Generator and GeneratorBase classes
00622 #------------------------------------------------------------
00623 program = """
00624 class Generator(GeneratorBase):
00625     def __init__(self, token, dict):
00626         GeneratorBase.__init__(self, token, dict)
00627     def generate(self):
00628         try:
00629             self.process()
00630         except YATException, e:
00631             self.print_error(e)
00632             sys.exit(-1)
00633         return self.text
00634 
00635     def process(self):
00636 """
00637 
00638 class GeneratorBase:
00639     def __init__(self, token, dict):
00640         self.token = token
00641         self.dicts = [dict]
00642         self.index = 0
00643         self.text = ""
00644 
00645     def print_error(self, e):
00646         print "\nTemplate Generation Error: line", e.lineno, "in input data"
00647         print "  " + ''.join(nesteditem(e.value))
00648         temp = ""
00649         for i, s in enumerate(self.token):
00650             if s != None:
00651                 if i % 3 == 1:
00652                     temp += "[" + s + "]\n"
00653                 else:
00654                     temp += s
00655         lines = temp.split("\n")
00656         length = len(lines)
00657         print "Template text:"
00658         print "------------------------------------------------------------"
00659         for i in range(1,10):
00660             l = e.lineno - 6 + i
00661             if l > 0 and l < length:
00662                 print lines[l]
00663                 if i == 5:
00664                     uline = '~'*len(lines[l])
00665                     print uline
00666         if hasattr(e, 'context'):
00667             print "\nCurrent context:"
00668             print "------------------------------------------------------------"
00669             print e.context
00670         
00671     def set_index(self, index):
00672         self.index = index
00673 
00674     def push_dict(self, dict):
00675         self.dicts.append(dict)
00676 
00677     def pop_dict(self):
00678         if len(self.dicts) < 2:
00679             raise UnmatchedBlock(self.lineno(), "")
00680         self.dicts.pop()
00681 
00682     def write(self, text):
00683         self.text += text
00684 
00685     def write_dict(self, keytext):
00686         self.write(self.get_text(keytext))
00687 
00688     def write_token(self, index):
00689         self.write(self.token[index])
00690 
00691     def lineno(self):
00692         cnt = 1
00693         for i in range(0, self.index, 3):
00694             if self.token[i] != None:
00695                 cnt += self.token[i].count('\n')
00696         # count deleted '\n' after commands
00697         for i in range(1, self.index, 3):
00698             if self.token[i] != None:
00699                 cnt += 1
00700         return cnt
00701                                 
00702     def get_text(self, keytext):
00703         val = self.get_value(keytext)
00704         if isinstance(val, StringType):
00705             return val
00706         if isinstance(val, IntType) or isinstance(val, FloatType):
00707             return str(val)
00708         raise UnexpectedData(self.lineno(), "\"" + keytext + \
00709                                  "\" should have string, int or float value.")
00710 
00711     def get_list(self, keytext):
00712         val = self.get_value(keytext)
00713         if not isinstance(val, ListType):
00714             raise UnexpectedData(self.lineno(),
00715                                  "\"" + keytext + "\" should have list value.")
00716         return val
00717 
00718     def has_key(self, keytext):
00719         try:
00720             self.get_value(keytext)
00721             return True
00722         except NotFound, e:
00723             return False
00724 
00725     def get_value(self, keytext):
00726         keys = keytext.split('.')
00727         for i in range(len(self.dicts) - 1, -1, -1):
00728             dict_value = self.get_dict_value(keys, self.dicts[i])
00729             if dict_value != None:
00730                 return dict_value
00731 
00732         # not found
00733         keys.pop()
00734         if len(keys) != 0:
00735             raise NotFound(self.lineno(), keytext, self.get_value(keys[0]))
00736         raise NotFound(self.lineno(), keytext) 
00737 
00738     def get_dict_value(self, keys, dict):
00739         length = len(keys)
00740         d = dict
00741         for i in range(length):
00742             if isinstance(d, DictType) and d.has_key(keys[i]):
00743                 d = d[keys[i]]
00744             else:
00745                 return None
00746         return d
00747 
00748 
00749 #------------------------------------------------------------
00750 # Exceptions                                
00751 #------------------------------------------------------------
00752 class YATException(Exception):
00753     pass
00754 
00755 class UnknownError(YATException):
00756     def __init__(self, lineno):
00757         self.lineno = lineno
00758         self.value = "Unknown error."
00759 
00760 class UnmatchedBlock(YATException):
00761     def __init__(self, lineno, msg):
00762         self.lineno = lineno
00763         self.value = "Unmatched block error: " + msg
00764 
00765 class UnexpectedData(YATException):
00766     def __init__(self, lineno, msg):
00767         self.lineno = lineno
00768         self.value = msg
00769 
00770 class NotFinalElement(YATException):
00771     def __init__(self, dictkey, dictvalue):
00772         self.value = "Specified key is not final element: ",\
00773             dictkey, "=>", dictvalue
00774 
00775 class InvalidDirective(YATException):
00776     def __init__(self, lineno, directive):
00777         self.lineno = lineno
00778         self.value = "Invalid directive: \"[" + directive + "]\""
00779 
00780 class UnmatchedData(YATException):
00781     def __init__(self, lineno, description):
00782         self.lineno = lineno
00783         self.value = "Unmatched data and input: ", description
00784 
00785 class NotFound(YATException):
00786     def __init__(self, lineno, description, context = None):
00787         self.lineno = lineno
00788         self.value = "Value not found for: \"" + description + "\"\n"
00789         if context != None:
00790             try:
00791                 import yaml
00792                 self.context = yaml.dump(context, default_flow_style = False)
00793             except:
00794                 pass
00795 
00796 #------------------------------------------------------------
00797 # other functions
00798 #------------------------------------------------------------
00799 def nesteditem(aList):
00800     for anItem in aList:
00801         if type(anItem)==list:
00802             for subitem in nesteditem(anItem):
00803                 yield subitem
00804         else:
00805             yield anItem
00806 
00807 
00808 
00809 if __name__ == "__main__":
00810     dict = []
00811     template = []
00812     #------------------------------------------------------------
00813     # Example 0
00814     #------------------------------------------------------------
00815     dict.append({"a": "This is a",
00816                  "b": {"1": "This is b.1",
00817                        "2": "This is b.2"}
00818                  })
00819     template.append("""[a]
00820 
00821 [b.1]
00822 
00823 [b.2]""")
00824 
00825     #------------------------------------------------------------
00826     # Example 1
00827     #------------------------------------------------------------
00828     dict.append({"list": [0, 1, 2],
00829                  "listed_dict": [
00830                 {"name": "x", "value": "1.0"},
00831                 {"name": "y", "value": "0.2"},
00832                 {"name": "z", "value": "0.1"}]})
00833     template.append("""[for lst in list]
00834 [lst],  
00835 [endfor]
00836 [for lst in listed_dict]
00837 [lst.name]: [lst.value]
00838 
00839 [endfor]""")
00840 
00841     #------------------------------------------------------------
00842     # Example 2
00843     #------------------------------------------------------------
00844     dict.append({"list": [0,1,2,3,4,5,6,7,8,9,10]})
00845     template.append("""[for key in list]
00846 [if-index key is 3] [key] is hoge!!
00847 [elif-index key is 6] [key] is foo!!
00848 [elif-index key is 9] [key] is bar!!
00849 [elif-index key is first] [key] is first
00850 [elif-index key is last] Omoro-------!!!!
00851 [elif-index key is odd] [key] is odd number
00852 [elif-index key is even] [key] is even number
00853 [endif]
00854 [endfor]""")
00855 
00856     #------------------------------------------------------------
00857     # Example 3
00858     #------------------------------------------------------------
00859     dict.append({"key1": "a", "key2": "b"})
00860     template.append("""[if key1 is a]
00861 The key1 is "a".
00862 [else]
00863 This key1 is not "a".
00864 [endif]""")
00865 
00866     #------------------------------------------------------------
00867     # Example 4
00868     #------------------------------------------------------------
00869     dict.append({"key1": "a", "key2": "b"})
00870     template.append("""[if-any key1]
00871 key1 exists.
00872 [endif][if-any key3]
00873 key3 exists.
00874 [else]
00875 key3 does not exists.
00876 [endif]""")
00877 
00878     dict.append({})
00879     template.append("""
00880 [[]bracket]
00881 [# comment]
00882 """)
00883 
00884     import yaml
00885     if len(dict) == len(template):
00886         for i in range(len(dict)-1,len(dict)):
00887             t = Template(template[i])
00888             print "-" * 60
00889             print "Example:", i
00890             print "-" * 60
00891             print "Template:\n"
00892             print template[i]
00893             print "-" * 60
00894             print "Dictionary:\n"
00895             print yaml.dump(dict[i], default_flow_style=False)
00896             print "-" * 60
00897             print "Generated Script:\n"
00898             print t.get_script()
00899             print "-" * 60
00900             print "Generated Text:\n"
00901             print t.generate(dict[i])
00902             print ""


openrtm_aist
Author(s): Noriaki Ando
autogenerated on Thu Aug 27 2015 14:16:39