def init(self, f): ''' Init parser @param f: FILE or a string to init parser from @type f: FILE or a string @return: None @rtype: None ''' self.token_list = SpecTokenList(f)
def parse(cls, token_list, parent, allowed, ctx): ''' Parse section from token list @param token_list: a token list to be used @type token_list: L{SpecTokenList} @param parent: parent section or None @type parent: L{SpecSection} @param allowed: allowed sections within the section @type allowed: list of L{SpecSection} @param ctx: parsing context @type ctx: L{SpecModelParser} @return: parsed section @rtype: L{SpecSection} ''' ret = SpecExpressionParser.obj(parent) tokens = SpecTokenList() # let's assume, that the very first token is a part of an expression tokens.token_list_append(token_list.get()) while True: tkn = token_list.touch() if str(tkn) == '>=' or str(tkn) == '<=' \ or str(tkn) == '<' or str(tkn) == '>' \ or str(tkn) == '!=' or str(tkn) == '==' \ or str(tkn) == '&&' or str(tkn) == '||': tokens.token_list_append(token_list.get()) if token_list.touch().is_eof(): raise SpecBadToken("Unexpected EOF, expected expression termination") tokens.token_list_append(token_list.get()) continue else: break ret.set_tokens(tokens) return ret
def parse_entry(cls, token_list, parent, ctx): ''' Parse a changelog entry @param token_list: a token list to be used @type token_list: L{SpecTokenList} @param parent: parent section or None @type parent: L{SpecSection} @param ctx: parsing context @type ctx: L{SpecModelParser} @return: parsed section @rtype: L{SpecSection} ''' def parse_date(date): s = str(date[0]) + ' ' + str(date[1]) + ' ' + str(date[2]) + ' ' + str(date[3]) return datetime.datetime.strptime(s, '%a %b %d %Y') def changelog_entry_beginning_callback(obj, token_list): # is there some section? if obj.section_beginning_callback(obj, token_list): # changelog message can consist of keyword like: # - Add missing Requires: golang(github.com/gorilla/mux) to devel tkn = token_list.touch() if not tkn.same_line(token_list[token_list.get_pointer() - 1]): return True # or is there another changelog entry? return str(token_list.touch()) == '*' entry = SpecChangelogParser.obj.SpecStChangelogEntry(parent) star = token_list.get() if str(star) != '*': token_list.unget() raise SpecBadToken("Expected token '*', got '%s'" % star) entry.set_star(star) date = SpecTokenList() for _ in xrange(0, 4): date.token_list_append(token_list.get()) entry.set_date(date) date_parsed = parse_date(date) entry.set_date_parsed(date_parsed) user = SpecTokenList() while not str(token_list.touch()).startswith('<'): user.token_list_append(token_list.get()) entry.set_user(user) user_email = token_list.get() entry.set_user_email(user_email) # version delim is optional here, if not stated, let's skip it if str(token_list.touch()) == '-': entry.set_version_delim(token_list.get()) version = token_list.get() entry.set_version(version) entry.set_message(token_list.get_while_not( functools.partial(changelog_entry_beginning_callback, ctx) ) ) return entry
class SpecFileParser(SpecModelParser): ''' A spec parser ''' def __init__(self, writer): self.token_list = None self.set_model_writer(writer) self.MANIPULATORS = [ SpecIfParser, SpecDefinitionParser, SpecGlobalParser, SpecDefineParser, SpecBuildParser, SpecChangelogParser, SpecCheckParser, SpecCleanParser, SpecDescriptionParser, SpecFilesParser, SpecInstallParser, SpecPackageParser, SpecPrepParser, SpecPreParser, SpecPostParser, SpecPreunParser, SpecPostunParser, SpecPretransParser, SpecPosttransParser, SpecTriggerParser, SpecTriggerinParser, SpecTriggerpreinParser, SpecTriggerunParser, SpecTriggerpostunParser, SpecVerifyscriptParser ] def init(self, f): ''' Init parser @param f: FILE or a string to init parser from @type f: FILE or a string @return: None @rtype: None ''' self.token_list = SpecTokenList(f) @staticmethod def section_beginning_callback(obj, token_list): ''' A callback for L{SpecTokenList} used to check whether next token is a section token @param obj: self instance @type obj: L{SpecModelParser} instance @param token_list: token list to be used @type token_list: L{SpecTokenList} @return: section parser to be used for parsing the upcoming section @rtype: L{SpecModelParser} ''' return obj.section_beginning(token_list) def section_beginning(self, token_list): ''' Check whether next token is a section token @param token_list: token list to be used @type token_list: L{SpecTokenList} @return: section parser to be used to parse the upcoming section @rtype: L{SpecModelParser} ''' for parser in self.MANIPULATORS: ret = parser.section_beginning(token_list) if ret is not None: return parser return None # Not found @staticmethod def section_beginning_callback_no_if(obj, token_list): ''' A callback for L{SpecTokenList} used to check whether next token is a section token, skip %ifs @param obj: self instance @type obj: L{SpecModelParser} instance @param token_list: token list to be used @type token_list: L{SpecTokenList} @return: section parser to be used for parsing the upcoming section @rtype: L{SpecModelParser} ''' return obj.section_beginning_no_if(token_list) def section_beginning_no_if(self, token_list): ''' Check whether next token is a section token, skip %if @param token_list: token list to be used @type token_list: L{SpecTokenList} @return: section parser to be used to parse the upcoming section @rtype: L{SpecModelParser} ''' for parser in self.MANIPULATORS: ret = parser.section_beginning(token_list) if ret is not None and not issubclass(ret, SpecStIf): return parser return None # Not found def parse_loop(self, token_list, parent, allowed): ''' Main parse loop to get list of parsed sections @param token_list: a list of tokens to be used @type token_list: L{SpecTokenList} @param parent: parent section @type parent: L{SpecSection} @param allowed: allowed sections to be parsed, section parsers @type allowed: list of L{SpecSectionParser} @return: list of parsed sections @rtype: L{SpecSection} ''' ret = [] found = True while found: found = False token = token_list.touch() SpecDebug.debug("- parsing round: '%s'" % str(token)) if token.is_eof(): break for t in allowed: section = t.parse(token_list, parent, allowed, self) if section: found = True SpecDebug.debug("- adding parsed section '%s'" % type(section)) ret.append(section) break if not found: SpecDebug.debug("- unparsed token '%s' on line %s" % (str(token), str(token.line))) return ret def parse_preamble(self): ''' Parse preamble of a spec file @return: parsed sections in preamble @rtype: list of L{SpecSection} ''' allowed = [ SpecIfParser, SpecDefinitionParser, SpecGlobalParser ] ret = self.parse_loop(self.token_list, None, allowed) unparsed = self.token_list.touch() SpecDebug.debug("-- preamble finished with token '%s' on line %d" % (str(unparsed), unparsed.line)) return ret def parse_loop_section(self): ''' Parse sections after preamble @return: list of parsed sections @rtype: list of L{SpecSection} ''' allowed = copy.deepcopy(self.MANIPULATORS) return self.parse_loop(self.token_list, None, allowed) def parse(self): ''' Main parser entry point - parse provided spec file @return: None @rtype: @raise SpecBadToken: when an unexpected token is reached ''' self.get_model_writer().append_items(self.parse_preamble()) self.get_model_writer().append_items(self.parse_loop_section()) eof = self.token_list.touch() if not eof.is_eof(): raise SpecBadToken("Unexpected symbol '" + str(eof.token) + "' on line " + str(eof.line))