# above qName definition allows double :: and excludes non-ascii letters # qName = Regex("[_A-Za-z\xC0-\xD6\xD8-\xF6\xF8-\xFF\u0100-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]" # r"[_\-\." # "\xB7A-Za-z0-9\xC0-\xD6\xD8-\xF6\xF8-\xFF\u0100-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u0300-\u036F\u203F-\u2040]*" # "[:]?" # r"[_\-\." # "\xB7A-Za-z0-9\xC0-\xD6\xD8-\xF6\xF8-\xFF\u0100-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u0300-\u036F\u203F-\u2040]*") ncName = Word(alphas + '_',alphanums + '_-.') prefixOp = Literal(":") decimalPoint = Literal('.') exponentLiteral = CaselessLiteral('e') plusorminusLiteral = Literal('+') | Literal('-') digits = Word(nums) integerLiteral = Combine( Optional(plusorminusLiteral) + digits ) decimalFractionLiteral = Combine( Optional(plusorminusLiteral) + decimalPoint + digits ) infLiteral = Combine( Optional(plusorminusLiteral) + Literal("INF") ) nanLiteral = Literal("NaN") floatLiteral = ( Combine( integerLiteral + ( ( decimalPoint + Optional(digits) + exponentLiteral + integerLiteral ) | ( exponentLiteral + integerLiteral ) ) ) | Combine( decimalFractionLiteral + exponentLiteral + integerLiteral ) | infLiteral | nanLiteral ) decimalLiteral = ( Combine( integerLiteral + decimalPoint + Optional(digits) ) | decimalFractionLiteral ) #emptySequence = Literal( "(" ) + Literal( ")" ) lParen = Literal( "(" )
def compileSphinxGrammar(cntlr): global isGrammarCompiled, sphinxProg, lineno if isGrammarCompiled: return sphinxProg debugParsing = True cntlr.showStatus(_("Compiling Sphinx Grammar")) if sys.version[0] >= '3': # python 3 requires modified parser to allow release of global objects when closing DTS from arelle.pyparsing.pyparsing_py3 import ( Word, Keyword, alphas, Literal, CaselessLiteral, Combine, Optional, nums, Or, Forward, Group, ZeroOrMore, StringEnd, alphanums, ParserElement, quotedString, delimitedList, Suppress, Regex, FollowedBy, lineno) else: from pyparsing import (Word, Keyword, alphas, Literal, CaselessLiteral, Combine, Optional, nums, Or, Forward, Group, ZeroOrMore, StringEnd, alphanums, ParserElement, quotedString, delimitedList, Suppress, Regex, FollowedBy, lineno) ParserElement.enablePackrat() """ the pyparsing parser constructs are defined in this method to prevent the need to compile the grammar when the plug in is loaded (which is likely to be when setting up GUI menus or command line parser). instead the grammar is compiled the first time that any sphinx needs to be parsed only the sphinxExpression (result below) needs to be global for the parser """ # define grammar sphinxComment = Regex( r"/(?:\*(?:[^*]*\*+)+?/|/[^\n]*(?:\n[^\n]*)*?(?:(?<!\\)|\Z))" ).setParseAction(compileComment) variableRef = Regex( "[$]" # variable prefix # localname part "([A-Za-z\xC0-\xD6\xD8-\xF6\xF8-\xFF\u0100-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD_]" "[A-Za-z0-9\xC0-\xD6\xD8-\xF6\xF8-\xFF\u0100-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u0300-\u036F\u203F-\u2040\xB7_.-]*)" ) qName = Regex( "([A-Za-z\xC0-\xD6\xD8-\xF6\xF8-\xFF\u0100-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD_]" "[A-Za-z0-9\xC0-\xD6\xD8-\xF6\xF8-\xFF\u0100-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u0300-\u036F\u203F-\u2040\xB7_.-]*:)?" # localname or wildcard-localname part "([A-Za-z\xC0-\xD6\xD8-\xF6\xF8-\xFF\u0100-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD_]" "[A-Za-z0-9\xC0-\xD6\xD8-\xF6\xF8-\xFF\u0100-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u0300-\u036F\u203F-\u2040\xB7_.-]*|[*])" ) ncName = Regex( "([A-Za-z\xC0-\xD6\xD8-\xF6\xF8-\xFF\u0100-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD_]" "[A-Za-z0-9\xC0-\xD6\xD8-\xF6\xF8-\xFF\u0100-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u0300-\u036F\u203F-\u2040\xB7_.-]*)" ).setName("ncName").setDebug(debugParsing) #annotationName = Word("@",alphanums + '_-.').setName("annotationName").setDebug(debugParsing) annotationName = Regex( "@[A-Za-z\xC0-\xD6\xD8-\xF6\xF8-\xFF\u0100-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD_]\w*" ).setName("annotationName").setDebug(debugParsing) decimalPoint = Literal('.') exponentLiteral = CaselessLiteral('e') plusorminusLiteral = Literal('+') | Literal('-') digits = Word(nums) integerLiteral = Combine(Optional(plusorminusLiteral) + digits) decimalFractionLiteral = Combine( Optional(plusorminusLiteral) + decimalPoint + digits) infLiteral = Combine(Optional(plusorminusLiteral) + Literal("INF")) nanLiteral = Literal("NaN") floatLiteral = (Combine(integerLiteral + ( (decimalPoint + Optional(digits) + exponentLiteral + integerLiteral) | (exponentLiteral + integerLiteral) | (decimalPoint + Optional(digits)))) | Combine(decimalFractionLiteral + exponentLiteral + integerLiteral) | decimalFractionLiteral | infLiteral | nanLiteral) #emptySequence = Literal( "(" ) + Literal( ")" ) lParen = Literal("(") rParen = Literal(")") lPred = Literal("[[") | Literal("[") rPred = Literal("]]") | Literal("]") commaOp = Literal(",") ifOp = Keyword("if") elseOp = Keyword("else") forOp = Keyword("for") inOp = Keyword("in") withOp = Keyword("with") notOp = Keyword("not") valuesOp = Keyword("values") andOp = Keyword("and") orOp = Keyword("or") neOp = Literal("!=") leOp = Literal("<=") ltOp = Literal("<") geOp = Literal(">=") gtOp = Literal(">") eqOp = Literal("==") compOp = leOp | ltOp | geOp | gtOp plusOp = Literal("|+|") | Literal("|+") | Literal("+|") | Literal("+") minusOp = Literal("|-|") | Literal("|-") | Literal("-|") | Literal("-") plusMinusOp = (plusOp | minusOp).setParseAction(compileOp) multOp = Literal("*") divOp = Literal("/") varAssign = Literal("=") tagOp = Literal("#") asOp = Keyword("as") whereOp = Keyword("where") wildOp = Literal("**") | Literal("*") methodOp = Literal("::") formulaOp = Literal(":=") namespaceDeclaration = ( Literal("xmlns") + Optional(Suppress(Literal(":")) + ncName) + Suppress(Literal("=")) + quotedString ).setParseAction(compileNamespaceDeclaration).ignore(sphinxComment) annotationDeclaration = ( Suppress(Keyword("annotation")) + ncName + Optional(Suppress(Keyword("as")) + ncName) ).setParseAction(compileAnnotationDeclaration).ignore(sphinxComment) packageDeclaration = ( Suppress(Keyword("package")) + ncName).setParseAction(compilePackageDeclaration).ignore(sphinxComment) severity = (Suppress(Keyword("severity")) + (ncName)).setParseAction(compileSeverity).ignore(sphinxComment) expr = Forward() atom = ((forOp - Suppress(lParen) - ncName - Suppress(inOp) - expr - Suppress(rParen) - expr).setParseAction(compileFor) | (ifOp - Suppress(lParen) - expr - Suppress(rParen) - expr - Suppress(elseOp) - expr).setParseAction(compileIf) | (ncName + Suppress(lParen) + Optional( delimitedList( ZeroOrMore((ncName + Optional(tagOp + Optional(ncName)) + varAssign + expr + Suppress(Literal(";")) ).setParseAction(compileVariableAssignment)) + Optional(ncName + varAssign) + expr)) + Suppress(rParen)).setParseAction(compileFunctionReference) | (floatLiteral).setParseAction(compileFloatLiteral) | (integerLiteral).setParseAction(compileIntegerLiteral) | (quotedString).setParseAction(compileStringLiteral) | (Optional(qName) + lPred + Optional( delimitedList( ((whereOp + expr) | ((qName | variableRef) + Optional(tagOp + Optional(ncName)) + Optional( (varAssign + (wildOp | expr) | (inOp + expr) | (asOp + ncName + varAssign + wildOp + Optional(whereOp + expr))))) ).setParseAction(compileHyperspaceAxis), delim=';')) + rPred).setParseAction(compileHyperspaceExpression) | (variableRef).setParseAction(compileVariableReference) | (qName).setParseAction(compileQname) | (Suppress(lParen) - expr - Optional(commaOp - Optional(expr - ZeroOrMore(commaOp - expr))) - Suppress(rParen)).setParseAction(compileBrackets) ).ignore(sphinxComment) atom.setName("atom").setDebug(debugParsing) valueExpr = atom taggedExpr = (valueExpr - Optional(tagOp - ncName) ).setParseAction(compileTagAssignment).ignore(sphinxComment) methodExpr = ( (methodOp + ncName + ZeroOrMore(methodOp + taggedExpr) ).setParseAction(compileMethodReference) | (ZeroOrMore(taggedExpr + methodOp) + taggedExpr) ).setParseAction(compileMethodReference).ignore(sphinxComment) unaryExpr = ( Optional(plusMinusOp) + methodExpr).setParseAction(compileUnaryOperation).ignore(sphinxComment) negateExpr = ( Optional(notOp) + unaryExpr).setParseAction(compileUnaryOperation).ignore(sphinxComment) valuesExpr = (Optional(valuesOp) + negateExpr).setParseAction( compileValuesIteration).ignore(sphinxComment) method2Expr = (valuesExpr + Optional(methodOp + methodExpr)).setParseAction( compileMethodReference).ignore(sphinxComment) multiplyExpr = (method2Expr + Optional(multOp + method2Expr)).setParseAction( compileBinaryOperation).ignore(sphinxComment) divideExpr = (multiplyExpr + Optional(divOp + multiplyExpr)).setParseAction( compileBinaryOperation).ignore(sphinxComment) addExpr = (divideExpr + Optional(plusOp + divideExpr) ).setParseAction(compileBinaryOperation).ignore(sphinxComment) subtractExpr = (addExpr + Optional(minusOp + addExpr)).setParseAction( compileBinaryOperation).ignore(sphinxComment) equalityExpr = (subtractExpr + Optional(eqOp + subtractExpr)).setParseAction( compileBinaryOperation).ignore(sphinxComment) inequalityExpr = (equalityExpr + Optional(neOp + equalityExpr)).setParseAction( compileBinaryOperation).ignore(sphinxComment) comparisonExpr = (inequalityExpr + Optional(compOp + inequalityExpr)).setParseAction( compileBinaryOperation).ignore(sphinxComment) andExpr = (comparisonExpr + Optional(andOp + comparisonExpr) ).setParseAction(compileBinaryOperation).ignore(sphinxComment) orExpr = (andExpr + Optional(orOp + andExpr) ).setParseAction(compileBinaryOperation).ignore(sphinxComment) formulaExpr = (orExpr + Optional(formulaOp + orExpr)).setParseAction( compileBinaryOperation).ignore(sphinxComment) withExpr = (Optional(withOp + Suppress(lParen) + expr + Suppress(rParen)) + ZeroOrMore( (ncName + Optional(tagOp + Optional(ncName)) + varAssign + expr + Suppress(Literal(";"))).setParseAction( compileVariableAssignment).ignore(sphinxComment)) + formulaExpr).setParseAction(compileWith) #parsedExpr = withExpr #parsedExpr.setName("parsedExpr").setDebug(debugParsing) #expr << parsedExpr expr << withExpr expr.setName("expr").setDebug(debugParsing) annotation = (annotationName + Optional( Suppress(lParen) + Optional(delimitedList(expr)) + Suppress(rParen))).setParseAction(compileAnnotation).ignore( sphinxComment).setName("annotation").setDebug(debugParsing) constant = (Suppress(Keyword("constant")) + ncName + Optional(tagOp + Optional(ncName)) + varAssign + expr).setParseAction(compileConstant).ignore(sphinxComment) functionDeclaration = ( (Keyword("function") | Keyword("macro")) + ncName + lParen + Optional(delimitedList(ncName)) + rParen + expr).setParseAction(compileFunctionDeclaration).ignore(sphinxComment) message = (Suppress(Keyword("message")) + expr).setParseAction(compileMessage) preconditionDeclaration = ( Suppress(Keyword("precondition")) + ncName + expr + Optional( Keyword("otherwise") + Keyword("raise") + ncName + Optional(severity) + Optional(message)) ).setParseAction(compilePreconditionDeclaration).ignore(sphinxComment) assignedExpr = (ncName + Optional(tagOp + Optional(ncName)) + varAssign + expr + Suppress(Literal(";"))).setParseAction( compileVariableAssignment).ignore(sphinxComment) precondition = ( Suppress(Keyword("require")) + delimitedList(ncName)).setParseAction(compilePrecondition).ignore( sphinxComment).setName("precondition").setDebug(debugParsing) formulaRule = (Optional(precondition) + Keyword("formula") + ncName + Optional(severity) + Optional((Keyword("bind") + expr)) + ZeroOrMore(assignedExpr) + expr + Optional(message) ).setParseAction(compileFormulaRule).ignore(sphinxComment) reportRule = (Optional(precondition) + Keyword("report") + ncName + Optional(severity) + ZeroOrMore(assignedExpr) + expr + Optional(message) ).setParseAction(compileReportRule).ignore(sphinxComment) validationRule = (Optional(precondition) + Keyword("raise") + ncName + Optional(severity) + ZeroOrMore(assignedExpr) + expr + Optional(message)).setParseAction( compileValidationRule).ignore(sphinxComment) ruleBase = ( Optional(precondition) + Suppress(Keyword("rule-base")) + ZeroOrMore( (Suppress(Keyword("transform")) + (Keyword("namespace") + expr + Suppress(Keyword("to")) + expr) | (Keyword("qname") + expr + Suppress(Keyword("to")) + expr)).setParseAction(compileTransform)) ).setParseAction(compileRuleBase).ignore(sphinxComment).setName( "ruleBase").setDebug(debugParsing) sphinxProg = ( ZeroOrMore(namespaceDeclaration | sphinxComment) + ZeroOrMore(annotationDeclaration | annotation | constant | preconditionDeclaration | packageDeclaration | functionDeclaration | ruleBase | formulaRule | reportRule | validationRule | sphinxComment)) + StringEnd() sphinxProg.ignore(sphinxComment) startedAt = time.time() cntlr.modelManager.showStatus(_("initializing sphinx grammar")) sphinxProg.parseString("// force initialization\n", parseAll=True) from arelle.Locale import format_string logMessage( "INFO", "info", format_string(cntlr.modelManager.locale, _("Sphinx grammar initialized in %.2f secs"), time.time() - startedAt)) isGrammarCompiled = True return sphinxProg