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))