diff --git a/plugin/xule/XuleParser.py b/plugin/xule/XuleParser.py index 4ee4e1f99..9d6e2890a 100644 --- a/plugin/xule/XuleParser.py +++ b/plugin/xule/XuleParser.py @@ -144,7 +144,36 @@ def parseRules(files, dest, compile_type, max_recurse_depth=None): if orig_recursionlimit < new_depth: sys.setrecursionlimit(new_depth) - xuleGrammar = get_grammar() + # Process files only to extract output attribute declarations + xuleFile_outAttrDeclarations = get_grammar(only_output_attr_declarations=True) + found_output_declarations = [] + for ruleFile in sorted(files): + processFile = ruleFile.strip() + if os.path.isfile(processFile): + parseRes = xuleFile_outAttrDeclarations.parseFile(processFile).asDict()['xuleDoc'] + out_declarations = [x for x in parseRes if x['exprName'] == 'outputAttributeDeclaration'] + found_output_declarations.extend(out_declarations) + + elif os.path.isdir(processFile): + #Remove an ending slash if there is one + processFile = processFile[:-1] if processFile.endswith(os.sep) else processFile + for root, dirs, walk_files in os.walk(ruleFile.strip()): + for name in sorted(walk_files): + if os.path.splitext(name)[1] == ".xule": + print("Processing output attribute declarations for: %s" % os.path.basename(name)) + relpath = os.path.relpath(root, processFile) + if relpath == '.': + relpath = '' + parseRes = xuleFile_outAttrDeclarations.parseFile(os.path.join(processFile, relpath,name)).asDict()['xuleDoc'] + out_declarations = [x for x in parseRes if x['exprName'] == 'outputAttributeDeclaration'] + found_output_declarations.extend(out_declarations) + else: + print("Not a file or directory: %s" % processFile) + new_output_attributes = [x['attributeName'] for x in found_output_declarations] + + + # Process files with completed grammar + xuleGrammar = get_grammar(extra_output_attributes=new_output_attributes) ruleSet = xrsb.XuleRuleSetBuilder(compile_type) ruleSet.append(dest) diff --git a/plugin/xule/xule_grammar.py b/plugin/xule/xule_grammar.py index e500b6f3e..4761736f9 100644 --- a/plugin/xule/xule_grammar.py +++ b/plugin/xule/xule_grammar.py @@ -27,7 +27,8 @@ Combine, Optional, nums, Forward, Group, ZeroOrMore, ParserElement, delimitedList, Suppress, Regex, QuotedString, OneOrMore, oneOf, cStyleComment, CharsNotIn, - lineEnd, White, SkipTo, Empty, stringStart, stringEnd, alphas, printables, removeQuotes) + lineEnd, White, SkipTo, Empty, stringStart, stringEnd, alphas, printables, removeQuotes, + Or) INRESULT = False @@ -128,7 +129,7 @@ def buildPrecedenceExpressions( baseExpr, opList, lpar=Suppress('('), rpar=Suppr def nodeName(name): return Empty().setParseAction(lambda: name).setResultsName('exprName') -def get_grammar(): +def get_grammar(only_output_attr_declarations=False, extra_output_attributes=[]): """Return the XULE grammar""" global INRESULT @@ -651,8 +652,10 @@ def get_grammar(): nodeName('ruleNameSeparator') ) + default_output_attributes = ['message', 'severity', 'rule-suffix', 'rule-focus'] + total_output_attributes = default_output_attributes + extra_output_attributes ruleResult = Group( ~declarationKeywords + - (CaselessKeyword('message') | CaselessKeyword('severity') | CaselessKeyword('rule-suffix') | CaselessKeyword('rule-focus') | simpleName).setResultsName('resultName') + Empty().setParseAction(in_result) + + (Or(CaselessKeyword(x) for x in total_output_attributes) | simpleName).setResultsName('resultName') + Empty().setParseAction(in_result) + expr.setResultsName('resultExpr').setParseAction(out_result).setFailAction(out_result) + nodeName('result') ) @@ -710,6 +713,12 @@ def get_grammar(): Suppress(versionKeyword) + Word(printables).setResultsName('version') + nodeName('versionDeclaration') ) + xuleFile_outAttrDeclarations = (stringStart + + ZeroOrMore( + Group( outputAttributeDeclaration | SkipTo(outputAttributeDeclaration, include=True) | (SkipTo(stringEnd, include=True).setResultsName('text') + nodeName('otherText')) ) + ) + + stringEnd).setResultsName('xuleDoc').ignore(comment) + xuleFile = (stringStart + ZeroOrMore(Group(ruleNameSeparator | ruleNamePrefix | @@ -726,4 +735,7 @@ def get_grammar(): #xuleFile = (stringStart + Optional(header) + ZeroOrMore(packageBody) + stringEnd).setResultsName("xule").ignore(comment) - return xuleFile + if only_output_attr_declarations: + return xuleFile_outAttrDeclarations + else: + return xuleFile