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