Srikanth Vavilapalli | 1725e49 | 2014-12-01 17:50:52 -0800 | [diff] [blame] | 1 | #!/usr/bin/python |
| 2 | # |
| 3 | # Copyright (c) 2013 Big Switch Networks, Inc. |
| 4 | # |
| 5 | # Licensed under the Eclipse Public License, Version 1.0 (the |
| 6 | # "License"); you may not use this file except in compliance with the |
| 7 | # License. You may obtain a copy of the License at |
| 8 | # |
| 9 | # http://www.eclipse.org/legal/epl-v10.html |
| 10 | # |
| 11 | # Unless required by applicable law or agreed to in writing, software |
| 12 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
| 14 | # implied. See the License for the specific language governing |
| 15 | # permissions and limitations under the License. |
| 16 | # |
| 17 | |
| 18 | # Simple command description builder. |
| 19 | # |
| 20 | |
| 21 | import os |
| 22 | import copy |
| 23 | import fileinput |
| 24 | import traceback |
| 25 | import argparse |
| 26 | |
| 27 | def parse(*line): |
| 28 | if args.p: |
| 29 | print line |
| 30 | |
| 31 | def debug(*line): |
| 32 | if args.d: |
| 33 | print line |
| 34 | |
| 35 | def verbose(*line): |
| 36 | if args.v: |
| 37 | print line |
| 38 | |
| 39 | def error(*line): |
| 40 | print line |
| 41 | |
| 42 | |
| 43 | add_token = ('o', '+') |
| 44 | front_token = ('o', '^') |
| 45 | end_token = ('o', '$') |
| 46 | |
| 47 | def tokens(line): |
| 48 | """ |
| 49 | Returns the tokenzied line, with a eol token at the end |
| 50 | The start-token must be prefixed before parsing |
| 51 | """ |
| 52 | tokens = [] |
| 53 | i = 0 |
| 54 | end = len(line) |
| 55 | while i < end: |
| 56 | # break |
| 57 | while line[i] in ' \t\r\n': |
| 58 | i += 1 |
| 59 | if i == end: |
| 60 | break |
| 61 | if i == end: |
| 62 | break |
| 63 | if line[i] in '[]{}<>()|': |
| 64 | tokens.append(('o', line[i])) # 'o' <= char, op |
| 65 | i += 1 |
| 66 | continue |
| 67 | # span. |
| 68 | token = '' |
| 69 | run_i = i |
| 70 | while not line[run_i] in ' \t[]{}<>|\n': |
| 71 | run_i += 1 |
| 72 | if run_i == end: |
| 73 | break |
| 74 | tokens.append(('t', line[i:run_i])) # 't' <= token |
| 75 | i = run_i |
| 76 | # |
| 77 | tokens.append(end_token) # 't' <= '$' for eol |
| 78 | |
| 79 | return tokens |
| 80 | |
| 81 | priority_dict = { |
| 82 | '^' : 0, # hat, front of line |
| 83 | '$' : 1, # newline, end of line |
| 84 | ')' : 2, |
| 85 | '(' : 3, |
| 86 | '}' : 4, |
| 87 | '{' : 5, |
| 88 | ']' : 6, |
| 89 | '[' : 7, |
| 90 | '>' : 8, |
| 91 | '<' : 9, |
| 92 | '|' : 10, |
| 93 | '+' : 11, |
| 94 | } |
| 95 | |
| 96 | def priority(tok): |
| 97 | if not is_op(tok): |
| 98 | return -1 # lower than any with a valid priority, enables push |
| 99 | if not tok[1] in priority_dict: |
| 100 | return 100 # higher than any with a valid priority, enables push |
| 101 | return priority_dict[tok[1]] |
| 102 | |
| 103 | def is_op(tok): |
| 104 | return tok[0] == 'o' |
| 105 | |
| 106 | def is_token(tok): |
| 107 | return tok[0] == 't' |
| 108 | |
| 109 | def is_field(tok): |
| 110 | return tok[0] == 'field' |
| 111 | |
| 112 | def is_tree(tok): |
| 113 | return tok[0] == 'tree' |
| 114 | |
| 115 | def is_list(tok): |
| 116 | return type(tok) == list |
| 117 | |
| 118 | def op_of(tok): |
| 119 | return tok[1] |
| 120 | |
| 121 | def token_of(tok): |
| 122 | return tok[1] |
| 123 | |
| 124 | def field_list_of(tok): |
| 125 | return tok[1] |
| 126 | |
| 127 | balance = { |
| 128 | ']' : '[', |
| 129 | '}' : '{', |
| 130 | '>' : '<', |
| 131 | ')' : '(', |
| 132 | '$' : '^', |
| 133 | } |
| 134 | |
| 135 | def partner(tok): |
| 136 | if is_op(tok): |
| 137 | if token_of(tok) in balance: |
| 138 | return balance[token_of(tok)] |
| 139 | return None |
| 140 | |
| 141 | |
| 142 | stack = [] |
| 143 | |
| 144 | def print_stack(): |
| 145 | for s in stack: |
| 146 | print s |
| 147 | |
| 148 | def push(item): |
| 149 | parse("PUSH ", stack, "ADD ", item) |
| 150 | stack.append(item) |
| 151 | |
| 152 | def pop(): |
| 153 | parse( "POP", stack ) |
| 154 | p = stack[-1] |
| 155 | del stack[-1] |
| 156 | return p |
| 157 | |
| 158 | def reset_stack(): |
| 159 | global stack |
| 160 | stack = [] |
| 161 | |
| 162 | def peek(i = 1): |
| 163 | top = len(stack) |
| 164 | if top < i: |
| 165 | return ('o','^') # <= front of line |
| 166 | return stack[-i] |
| 167 | |
| 168 | def is_in_order(collect): |
| 169 | if is_op(collect[1]) and collect[1][1] == '+': |
| 170 | return True |
| 171 | return False |
| 172 | |
| 173 | def is_either(collect): |
| 174 | if is_op(collect[1]) and collect[1][1] == '|': |
| 175 | return True |
| 176 | return False |
| 177 | |
| 178 | def gather_field_list(collect, field_list): |
| 179 | if type(collect) == list: |
| 180 | for f in collect: |
| 181 | gather_field_list(f, field_list) |
| 182 | elif is_token(collect): |
| 183 | field_list.append(collect) |
| 184 | elif is_tree(collect): |
| 185 | gather_field_list(token_of(token_of(collect)), field_list) |
| 186 | else: |
| 187 | field_list.append(field_list) |
| 188 | |
| 189 | def gather_field(collect): |
| 190 | parse( "GATHER FIELD ", collect) |
| 191 | field_list = [] |
| 192 | if is_token(collect): |
| 193 | field_list.append(collect) |
| 194 | elif is_tree(collect): |
| 195 | gather_field_list(token_of(token_of(collect)), field_list) |
| 196 | elif type(collect) == list: |
| 197 | gather_field_list(collect, field_list) |
| 198 | else: |
| 199 | field_list.append(collect) |
| 200 | return ('field', field_list) |
| 201 | |
| 202 | def tree_builder(collect, tok): |
| 203 | result = None |
| 204 | op = op_of(tok) |
| 205 | parse( "WHAT ", collect, tok) |
| 206 | if op == '}': # { stuff } ... select one from the args |
| 207 | # XXX early return |
| 208 | if len(collect) == 1: |
| 209 | result = ('CHOICE ALONE', collect) |
| 210 | elif is_either(collect): |
| 211 | result = ("CHOICE OF", [c for c in collect if not is_op(c)]) |
| 212 | elif is_in_order(collect): |
| 213 | result = ("CHOICE ORDER", [c for c in collect if not is_op(c)]) |
| 214 | elif is_tree(collect): |
| 215 | result = ('CHOICE TREE', collect) |
| 216 | elif is_field(collect): |
| 217 | return gather_field(collect) |
| 218 | elif is_token(collect): |
| 219 | return collect |
| 220 | elif is_token(collect): |
| 221 | return collect |
| 222 | else: |
| 223 | result = ("CHOICE TROUBLE", op, collect) |
| 224 | elif op == ']': # [ stuff ] ... stuff which is optional |
| 225 | if len(collect) == 1: |
| 226 | result = ('OPTION ALONE', collect) |
| 227 | elif is_either(collect): |
| 228 | result = ("OPTION OF", [c for c in collect if not is_op(c)]) |
| 229 | elif is_in_order(collect): |
| 230 | result = ("OPTION ORDER", [c for c in collect if not is_op(c)]) |
| 231 | elif is_tree(collect): |
| 232 | result = ('OPTION TREE', collect) |
| 233 | elif is_field(collect): |
| 234 | return ('tree', ('OPTION FIELD', collect)) |
| 235 | elif is_token(collect): |
| 236 | result = ('OPTION TOKEN', collect) |
| 237 | else: |
| 238 | result = ("OPTION TROUBLE", op, collect) |
| 239 | elif op == ')': # ( stuff ) ... no semantic meaning, |
| 240 | # XXX early return |
| 241 | return collect |
| 242 | elif op == '>': # description of a field |
| 243 | gather = gather_field(collect) |
| 244 | parse("GATHERED: ",gather) |
| 245 | return gather |
| 246 | elif op == '|': # either of |
| 247 | result = ('EITHER', [c for c in collect if not is_op(c)]) |
| 248 | elif op == '+': # sum of |
| 249 | result = ('ORDER', [c for c in collect if not is_op(c)]) |
| 250 | elif op == '$': # eol, collect up any tree's left |
| 251 | # XXX syntax error? |
| 252 | print "STACK " |
| 253 | print_stack() |
| 254 | print "TOK ", tok |
| 255 | print "COLLECT", collect |
| 256 | exit() |
| 257 | else: |
| 258 | parse('return collect, later tok', tok) |
| 259 | return collect |
| 260 | parse( "BUILD ", op, type(result)) |
| 261 | return ('tree', result) |
| 262 | |
| 263 | |
| 264 | def single_token(tok): |
| 265 | (which, t) = tok |
| 266 | parse( "NEXT", which, t, peek()) |
| 267 | |
| 268 | if is_token(tok) and is_token(peek()): |
| 269 | # two tokens in a row, pretend the op is '+' |
| 270 | push(add_token) |
| 271 | |
| 272 | # is this a <tree><tree> ? |
| 273 | if is_tree(peek()) and (is_tree(peek(2)) or is_field(peek(2))): |
| 274 | # collect together as many as possible |
| 275 | collect = [pop()] |
| 276 | while is_tree(peek()) or is_field(peek()): |
| 277 | collect.insert(0, pop()) |
| 278 | push(tree_builder(collect, add_token)) |
| 279 | # is this a <tree><tree> ? |
| 280 | elif (not is_op(peek())) and (not is_op(peek(2))): |
| 281 | # collect together as many as possible |
| 282 | collect = [pop()] |
| 283 | while not is_op(peek()): |
| 284 | collect.insert(0, pop()) |
| 285 | push(tree_builder(collect, add_token)) |
| 286 | |
| 287 | if is_op(tok): |
| 288 | if not is_op(peek(1)): # item or token or field |
| 289 | parse( 'PRIO ', tok, priority(tok), peek(2), priority(peek(2))) |
| 290 | while priority(tok) < priority(peek(2)): |
| 291 | # collect as many from the same priority |
| 292 | last = pop() |
| 293 | parse( "-->", stack, tok, last) |
| 294 | # uniary op? |
| 295 | if is_op(peek()) and partner(tok) == op_of(peek()): |
| 296 | parse( "UNIARY ") |
| 297 | pop() # <= pop matching op |
| 298 | push(tree_builder(last, tok)) # <= token popped off |
| 299 | parse( "LEAVE", stack, tok) |
| 300 | return # don't push the uniary right op |
| 301 | |
| 302 | collect = last |
| 303 | op = tok |
| 304 | if is_op(peek()): |
| 305 | op = peek() |
| 306 | parse( "BINARY ", op) |
| 307 | collect = [last] |
| 308 | while is_op(peek()) and \ |
| 309 | not (partner(tok) == op_of(peek())) and \ |
| 310 | priority(op) == priority(peek()): |
| 311 | parse( "WHY ", op_of(op), priority(op), op_of(peek()), priority(peek())) |
| 312 | collect.insert(0, pop()) # <= op |
| 313 | collect.insert(0, pop()) # <= token |
| 314 | if len(collect) == 1: |
| 315 | print "NOT BINARY", tok, op, peek |
| 316 | exit() |
| 317 | parse( "==> ", collect, tok) |
| 318 | parse( "__ ", stack) |
| 319 | push(tree_builder(collect, op)) |
| 320 | parse( "SO FAR ", stack) |
| 321 | parse( "OP FAR ", tok) |
| 322 | push(tok) |
| 323 | parse( "LAST", stack, tok) |
| 324 | |
| 325 | |
| 326 | # |
| 327 | def single_line(tokens): |
| 328 | reset_stack() |
| 329 | for (which, t) in tokens: |
| 330 | single_token((which, t)) |
| 331 | |
| 332 | def all_tokens(token_list): |
| 333 | for token in token_list: |
| 334 | parse( "ALL TOKEN? ", token) |
| 335 | if not is_token(token): |
| 336 | return False |
| 337 | return True |
| 338 | |
| 339 | |
| 340 | class printer: |
| 341 | def __init__(self, form, is_optional, indent = 2): |
| 342 | self.form = form |
| 343 | self.is_optional = is_optional |
| 344 | self.need_optional = False |
| 345 | self.indent = indent |
| 346 | |
| 347 | def __str__(self): |
| 348 | return "form %s need %s optional %s indent %s" % ( |
| 349 | self.form, self.need_optional, self.is_optional, self.indent) |
| 350 | |
| 351 | def indents(self, extra = 0): |
| 352 | return " " * (self.indent + extra) |
| 353 | |
| 354 | def to_dict(self): |
| 355 | self.form = 'dict' |
| 356 | |
| 357 | def is_dict(self): |
| 358 | if self.form == 'dict': |
| 359 | return True |
| 360 | return False |
| 361 | |
| 362 | def to_tuple(self): |
| 363 | self.form = 'tuple' |
| 364 | |
| 365 | def is_tuple(self): |
| 366 | if self.form == 'tuple': |
| 367 | return True |
| 368 | return False |
| 369 | |
| 370 | def more_indent(self, incr = 1): |
| 371 | self.indent += incr |
| 372 | |
| 373 | def less_indent(self, decr = 1): |
| 374 | self.indent -= decr |
| 375 | |
| 376 | def nest(self, incr = 1, form = None, is_optional = None): |
| 377 | new = copy.deepcopy(self) |
| 378 | new.indent += 1 |
| 379 | if form: |
| 380 | new.form = form |
| 381 | if is_optional: |
| 382 | new.is_optional = is_optional |
| 383 | return new |
| 384 | |
| 385 | class description: |
| 386 | def __init__(self): |
| 387 | self.desc = [] |
| 388 | |
| 389 | def raw_out(self, line): |
| 390 | self.desc.append(line) |
| 391 | |
| 392 | def out(self, line, printer): |
| 393 | self.desc.append(printer.indents() + line) |
| 394 | |
| 395 | def out_with_indent(self, line, printer): |
| 396 | self.desc.append(printer.indents(1) + line) |
| 397 | |
| 398 | def result(self): |
| 399 | return '\n'.join(self.desc) |
| 400 | |
| 401 | desc = description() |
| 402 | |
| 403 | def single_recurse(tree): |
| 404 | """ |
| 405 | look for nested trees whose leaf only has a single element |
| 406 | """ |
| 407 | return False |
| 408 | |
| 409 | def maker_in_order(in_order, printer): |
| 410 | debug( "IN_ORDER ", is_tree(in_order), in_order ) |
| 411 | if is_list(in_order): |
| 412 | was_dict = False |
| 413 | desc.out('# %d items in order' % len(in_order) , printer) |
| 414 | desc.out('# %s ' % printer , printer) |
| 415 | if printer.is_dict(): |
| 416 | printer.to_tuple() |
| 417 | desc.out("(", printer) |
| 418 | printer.more_indent() |
| 419 | was_dict = True |
| 420 | do_optional = False |
| 421 | if printer.is_optional: |
| 422 | if not was_dict: |
| 423 | desc.out("(", printer) |
| 424 | printer.more_indent() |
| 425 | do_optional = True |
| 426 | save_need_optional = printer.need_optional |
| 427 | printer.need_optional = True |
| 428 | printer.is_optional = False |
| 429 | |
| 430 | for (n, tree) in enumerate(in_order, 1): |
| 431 | debug( "IN_ORDER ITEM ", n, is_token(tree), tree) |
| 432 | desc.out('# item %d %s' % (n, printer) , printer) |
| 433 | maker_items(tree, printer) |
| 434 | |
| 435 | if was_dict or do_optional: |
| 436 | printer.less_indent() |
| 437 | desc.out("),", printer) |
| 438 | if was_dict: |
| 439 | printer.to_dict() |
| 440 | if do_optional: |
| 441 | printer.is_optional = True |
| 442 | printer.need_optional = save_need_optional |
| 443 | |
| 444 | elif is_tree(in_order): |
| 445 | was_dict = False |
| 446 | if printer.is_dict(): |
| 447 | desc.out("(", printer) # )( |
| 448 | desc.out("#in_order2", printer) |
| 449 | traceback.print_stack() |
| 450 | printer.to_tuple() |
| 451 | printer.more_indent() |
| 452 | was_dict = True |
| 453 | debug( "IN_ORDER TREE ", token_of(in_order) ) |
| 454 | maker_do_op(token_of(in_order), printer) |
| 455 | if was_dict: |
| 456 | printer.less_indent() |
| 457 | desc.out("),", printer) |
| 458 | printer.to_dict() |
| 459 | elif is_token(in_order): |
| 460 | maker_items(in_order, printer.nest(incr = 1)) |
| 461 | elif is_field(in_order): |
| 462 | maker_field(field_list_of(in_order), printer.nest(incr = 1)) |
| 463 | else: |
| 464 | error( "IN_ORDER STUCK" ) |
| 465 | |
| 466 | def maker_field(field_list, printer): |
| 467 | was_tuple = False |
| 468 | if printer.is_tuple: |
| 469 | was_tuple = True |
| 470 | desc.out("{", printer) |
| 471 | printer.more_indent() |
| 472 | printer.to_tuple() |
| 473 | |
| 474 | if printer.need_optional: |
| 475 | desc.out("'optional' : %s," % printer.is_optional, printer) |
| 476 | |
| 477 | for field in field_list: |
| 478 | # Add more items here to provide more field decoration |
| 479 | printer.more_indent |
| 480 | value = token_of(field) |
| 481 | if value.find('=') == -1: |
| 482 | desc.out("'field' : '%s'," % value, printer) |
| 483 | else: |
| 484 | desc.out("'%s' : '%s'," % tuple(value.split('=')), printer) |
| 485 | printer.less_indent |
| 486 | |
| 487 | if was_tuple: |
| 488 | printer.less_indent() |
| 489 | desc.out( "},", printer ) |
| 490 | printer.to_dict() |
| 491 | |
| 492 | def maker_choice(tree_tuple, printer): |
| 493 | debug( 'MAKER_CHOICE', tree_tuple, printer.indent ) |
| 494 | |
| 495 | if is_tree(tree_tuple): |
| 496 | # XXX some tree's can be squashed. |
| 497 | debug( "MAKER_CHOICE ITEM ", tree_tuple ) |
| 498 | maker_do_op(token_of(tree_tuple), printer) |
| 499 | return |
| 500 | |
| 501 | # choice needs to print a dictionary. |
| 502 | was_tuple = False |
| 503 | if printer.is_tuple(): |
| 504 | printer.to_dict() |
| 505 | was_tuple = True |
| 506 | |
| 507 | desc.out('{', printer) |
| 508 | printer.more_indent() |
| 509 | |
| 510 | if printer.is_optional: |
| 511 | desc.out("'optional': %s," % printer.is_optional, printer) |
| 512 | desc.out("'choices' : (", printer) |
| 513 | desc.out(" # maker_choice", printer) |
| 514 | |
| 515 | if is_list(tree_tuple): |
| 516 | debug( "CHOICE LIST", len(tree_tuple), tree_tuple ) |
| 517 | printer.more_indent() |
| 518 | for (n, item) in enumerate(tree_tuple, 1): |
| 519 | debug( "CHOICE LIst #%d" % n ) |
| 520 | debug( " ITEM ", item ) |
| 521 | maker_items(item, printer) |
| 522 | printer.less_indent() |
| 523 | elif is_tree(tree_tuple): |
| 524 | debug( "CHOICE TREE" ) |
| 525 | (tree_which, tree) = tree_tuple[1] |
| 526 | # tree_which == 'tree' |
| 527 | maker_do_op(token_of(tree_tuple), printer.nest(form = 'tuple', incr = 1)) |
| 528 | elif is_field(tree_tuple): |
| 529 | debug( "CHOICE FIELD", tree_tuple[1] ) |
| 530 | printer.more_indent() |
| 531 | maker_field(field_list_of(tree_tuple), printer) |
| 532 | printer.less_indent() |
| 533 | else: |
| 534 | error( 'MAKER_CHOICE CONFUSED' ) |
| 535 | |
| 536 | desc.out(")", printer) |
| 537 | printer.less_indent() |
| 538 | desc.out('},', printer) |
| 539 | |
| 540 | if was_tuple: |
| 541 | printer.to_tuple() |
| 542 | |
| 543 | |
| 544 | def maker_do_op(op_tuple, printer): |
| 545 | debug( 'OP=> ', op_tuple ) |
| 546 | (op, operands) = op_tuple |
| 547 | debug( 'OP ', op_tuple, op, operands ) |
| 548 | if op == 'ORDER': |
| 549 | debug( "OP IN_ORDER ", operands ) |
| 550 | maker_in_order(operands, printer) |
| 551 | elif op == 'EITHER': |
| 552 | # XXX wrong |
| 553 | maker_choice(operands, printer) |
| 554 | elif op.startswith('CHOICE'): |
| 555 | maker_choice(operands, printer) |
| 556 | elif op.startswith('OPTION'): |
| 557 | was_optional = printer.is_optional |
| 558 | printer.is_optional = True |
| 559 | debug( 'OP OPTIONAL', operands ) |
| 560 | maker_items(operands, printer) |
| 561 | printer.is_optional = was_optional |
| 562 | |
| 563 | |
| 564 | def maker_trees(trees, printer): |
| 565 | (tree_which, op) = trees |
| 566 | maker_do_op(op, printer) |
| 567 | |
| 568 | |
| 569 | def maker_items(items, printer): |
| 570 | debug( "ITEMS-> ", type(items), items ) |
| 571 | if type(items) == list: |
| 572 | for item in items: |
| 573 | if is_tree(item): |
| 574 | debug( "TREE ", item ) |
| 575 | maker_do_op(item, printer) |
| 576 | elif is_field(item): |
| 577 | desc.out("{", printer) |
| 578 | maker_field(field_list_of(item), printer) |
| 579 | if printer.need_optional: |
| 580 | desc.out("'optional' : %s," % printer.is_optional, printer) |
| 581 | desc.out( "},", printer) |
| 582 | elif is_token(item): |
| 583 | desc.out("{", printer) |
| 584 | printer.more_indent() |
| 585 | desc.out("'token' : '%s'," % token_of(item), printer) |
| 586 | if printer.need_optional: |
| 587 | desc.out("'optional' : %s," % printer.is_optional, printer) |
| 588 | printer.less_indent() |
| 589 | desc.out("},", printer) |
| 590 | elif is_tree(items): |
| 591 | maker_do_op(token_of(items), printer) |
| 592 | elif is_field(items): |
| 593 | maker_field(field_list_of(items), printer) |
| 594 | elif is_token(items): |
| 595 | debug( 'ITEMS TOKEN', items ) |
| 596 | desc.out( "{", printer) |
| 597 | printer.more_indent() |
| 598 | desc.out( "'token' : '%s'," % token_of(items), printer) |
| 599 | if printer.need_optional: |
| 600 | desc.out( "'optional' : %s," % printer.is_optional, printer) |
| 601 | printer.less_indent() |
| 602 | desc.out( "},", printer) |
| 603 | else: |
| 604 | error( "ITEMS> STUCK", items ) |
| 605 | |
| 606 | |
| 607 | # |
| 608 | def maker_args(args, printer): |
| 609 | debug( "MAKER_ARGS ", args ) |
| 610 | (pick, item) = args |
| 611 | if pick == 'EITHER': |
| 612 | debug( "MAKER_ARGS EITHER ", item ) |
| 613 | if len(item) >= 1: |
| 614 | desc.raw_out( ' args : {') |
| 615 | if all_tokens(item): |
| 616 | for choice in item: |
| 617 | desc.raw_out(" '%s'," % token_of(choice, 3)) |
| 618 | else: |
| 619 | maker_trees(item, printer) |
| 620 | desc.raw_out( ' },' ) |
| 621 | else: # exactly one choice |
| 622 | desc.raw_out( ' args : { ' ) |
| 623 | if all_token(item): |
| 624 | desc.raw_out(" '%s'," % token_of(item[0])) |
| 625 | else: |
| 626 | print maker_trees(item, printer) |
| 627 | desc.raw_out( ' },' ) |
| 628 | elif pick.startswith('CHOICE'): |
| 629 | debug( "CHOICE", len(item) ) |
| 630 | if len(item) == 1: |
| 631 | maker_args(item) |
| 632 | elif is_tree(item) and token_of(item)[0] == 'EITHER': |
| 633 | maker_choice(token_of(item), printer) |
| 634 | elif is_field(item) or is_token(item): |
| 635 | maker_choice(item, printer) |
| 636 | else: |
| 637 | error( "CHOICE HELP ", item ) |
| 638 | elif pick.startswith('ORDER'): |
| 639 | # ought to choose the form of the printer based on item |
| 640 | desc.out("'args' : {", printer) |
| 641 | printer.less_indent() |
| 642 | maker_in_order(item, printer) |
| 643 | printer.less_indent() |
| 644 | desc.out('}', printer) |
| 645 | elif pick.startswith('OPTION'): |
| 646 | printer.is_optional = True |
| 647 | desc.raw_out( ' args : {') |
| 648 | maker_trees(item, printer) |
| 649 | desc.raw_out( ' },') |
| 650 | else: |
| 651 | error( "MAKER_PICKER HELP ", pick ) |
| 652 | |
| 653 | saved_input = [] |
| 654 | |
| 655 | # |
| 656 | def maker(name_tuple, no_supported, result, printer): |
| 657 | |
| 658 | name = token_of(name_tuple) |
| 659 | verbose( 'Name: %s no %s Result %s' % (name, no_supported, result) ) |
| 660 | |
| 661 | type = 'add-command-type' |
| 662 | mode = 'login' |
| 663 | new_mode = 'config-CHANGE' |
| 664 | obj_type = None |
| 665 | # |
| 666 | # command-name@command-type@command-mode@obj-type@new_mode |
| 667 | # |
| 668 | if name.find('@') >= 0: |
| 669 | name_parts = name.split('@') |
| 670 | name = name_parts[0] |
| 671 | type = name_parts[1] |
| 672 | if len(name_parts) > 2: |
| 673 | mode = name_parts[2] |
| 674 | if len(name_parts) > 3: |
| 675 | obj_type = name_parts[3] |
| 676 | if len(name_parts) > 4: |
| 677 | new_mode = name_parts[4] |
| 678 | # name-value pairs? |
| 679 | |
| 680 | debug( "NAME ", (name) ) |
| 681 | debug( 'command name ', name ) |
| 682 | desc.raw_out( '%s_%s_COMMAND_DESCRIPTION = {' % |
| 683 | (args.n.upper(), name.replace("-","_").upper())) |
| 684 | desc.raw_out( " 'name' : '%s'," % name) |
| 685 | desc.raw_out( " 'mode' : '%s'," % mode) |
| 686 | if no_supported == False: |
| 687 | desc.raw_out( " 'no-supported' : False,") |
| 688 | desc.raw_out( " 'command-type' : '%s'," % type) |
| 689 | if obj_type: |
| 690 | desc.raw_out( " 'obj-type' : '%s'," % obj_type) |
| 691 | if type == 'config-submode': |
| 692 | desc.raw_out( " 'submode-name' : '%s'," % new_mode) |
| 693 | desc.raw_out( " 'parent-id' : None,") |
| 694 | desc.raw_out( " 'short-help' : 'add-short-command-help',") |
| 695 | if args.f: |
| 696 | desc.raw_out( " 'feature' : '%s'," % args.f) |
| 697 | # if the remaining length is two, ORDER should be popped. |
| 698 | desc.raw_out( " 'args' : ( ") |
| 699 | maker_items(result, printer) |
| 700 | desc.raw_out( " ),") |
| 701 | desc.raw_out( "}") |
| 702 | return |
| 703 | |
| 704 | if len(order_list) == 2 and len(order) == 1: |
| 705 | build_choice = None |
| 706 | if is_tree(order_list[1]): |
| 707 | debug( "MAKER TREE.", token_of(order_list[1]) ) |
| 708 | if token_of(order_list[1])[0].startswith('CHOICE'): |
| 709 | choice = token_of(order_list[1]) |
| 710 | build_choice = order_list[1] |
| 711 | if build_choice: |
| 712 | desc.out("'args' : {", printer) |
| 713 | printer.more_indent() |
| 714 | maker_choice(build_choice, printer) |
| 715 | printer.less_indent() |
| 716 | desc.out( '},', printer) |
| 717 | else: |
| 718 | print "XXX", order_list |
| 719 | print "XXX", order_list[1] |
| 720 | desc.out("'args' : (", printer) |
| 721 | printer.more_indent() |
| 722 | printer.to_tuple() |
| 723 | maker_in_order(order_list[1], printer) |
| 724 | printer.less_indent() |
| 725 | desc.out( '),', printer) |
| 726 | elif len(order) > 1: |
| 727 | maker_args((order[0], order[1:]), printer) |
| 728 | else: |
| 729 | desc.raw_out('}') |
| 730 | |
| 731 | |
| 732 | parser = argparse.ArgumentParser(prog='desc_maker') |
| 733 | parser.add_argument('file') |
| 734 | parser.add_argument('-p') |
| 735 | parser.add_argument('-d') |
| 736 | parser.add_argument('-v') |
| 737 | parser.add_argument('-n', default = "NEW") |
| 738 | parser.add_argument('-f') |
| 739 | args = parser.parse_args() |
| 740 | |
| 741 | for line in fileinput.input(args.file): |
| 742 | |
| 743 | line_tokens = tokens(line) |
| 744 | if len(line_tokens) < 2: # why 2? even blank lines get eol |
| 745 | saved_input.append( "# @ %s" % line) |
| 746 | continue |
| 747 | # |
| 748 | # remove '[' 'no' ']' if its there, don't forget the leading '^' |
| 749 | no_supported = False |
| 750 | |
| 751 | if len(line_tokens) > 1: |
| 752 | if token_of(line_tokens[0]) == '#': |
| 753 | saved_input.append( "# @ %s" % line) |
| 754 | continue |
| 755 | elif token_of(line_tokens[0]) == '[': |
| 756 | if len(line_tokens) > 2: |
| 757 | if token_of(line_tokens[1]) == 'no': |
| 758 | if len(line_tokens) > 3: |
| 759 | if token_of(line_tokens[2]) == ']': |
| 760 | if len(line_tokens) > 4: |
| 761 | no_supported = True |
| 762 | name = line_tokens[3] |
| 763 | parse_tokens = line_tokens[4:] |
| 764 | else: |
| 765 | print 'Warning: name required after \[ no \']' |
| 766 | continue |
| 767 | else: |
| 768 | print 'Warning: only \'\[ no \]\' allowed as prefix' |
| 769 | continue |
| 770 | else: |
| 771 | print 'Warning: only \'\[ no \]\' allowed as prefix' |
| 772 | continue |
| 773 | else: |
| 774 | print 'Warning: only single \[ in line' |
| 775 | continue |
| 776 | else: |
| 777 | name = line_tokens[0] |
| 778 | parse_tokens = line_tokens[1:] |
| 779 | |
| 780 | saved_input.append( "# @ %s" % line) |
| 781 | single_line([front_token] + parse_tokens) |
| 782 | |
| 783 | # should look like ^ tree $ |
| 784 | if len(stack) == 3 and not is_op(stack[1]): |
| 785 | debug( "OK------------------ -> ", token_of(stack[1]) ) |
| 786 | a_printer = printer('tuple', is_optional = False) |
| 787 | desc.out('\n#\n# %s#\n' % line, a_printer) |
| 788 | maker(name, no_supported, stack[1], a_printer) |
| 789 | else: |
| 790 | # |
| 791 | # Could peek at the stack to get an idea of the nature of the syntax error |
| 792 | print "SYNTAX ERROR", name, stack |
| 793 | |
| 794 | # |
| 795 | # |
| 796 | |
| 797 | print "#" |
| 798 | print "# Command used as input for this run are listed below," |
| 799 | print "# Fish the command out by egreping '^# @' " |
| 800 | print "#" |
| 801 | |
| 802 | print ''.join(saved_input) |
| 803 | print desc.result() |