private NonTerminal Identifier() { var idSimple = new IdentifierTerminal("Identifier") { AllFirstChars = validChars, AllChars = validChars + "1234567890" }; idSimple.SetFlag(TermFlags.NoAstNode); var id = NonTerminal("identifier", null, n => new Identifier { Value = n.ChildNodes.Select(x => x.Token.ValueString).JoinStrings(".") }); id.Rule = MakePlusRule(id, ToTerm("."), idSimple); return(id); }
public ODataGrammar() { #region ===== Operator And Punctuation ===== var DOT = ToTerm(".", "dot"); var AT = ToTerm("@", "at"); var COLON = ToTerm(":", "colon"); var COMMA = ToTerm(",", "comma"); var EQ = ToTerm("=", "equal"); var SIGN = ToTerm("+") | "-"; var SEMI = ToTerm(";", "semi"); var STAR = ToTerm("*", "star"); var SQUOTE = ToTerm("'", "squote"); var OPEN = ToTerm("(", "Lpar"); var CLOSE = ToTerm(")", "Rpar"); var SLASH = ToTerm("/", "slash"); var AND = ToTerm("&", "and"); var OR = ToTerm("|", "or"); var DQUOTE = ToTerm("\"", "dquote"); var QUESTION = ToTerm("?", "question"); RegisterOperators(1, "or"); RegisterOperators(2, "and"); RegisterOperators(6, "eq", "ne"); RegisterOperators(7, "gt", "lt", "le", "ge", "has"); RegisterOperators(9, "add", "sub"); RegisterOperators(10, "mul", "div", "mod"); MarkPunctuation(",", "(", ")", "{", "}", "[", "]", ":"); #endregion #region 1. Resource Path Terminal var odataRelativeUri = new NonTerminal("odataRelativeUri"); var keyPredicate = new NonTerminal("keyPredicate"); var keyValuePair = new NonTerminal("keyValuePair"); var keyValuePairs = new NonTerminal("keyValuePairs"); var count = new NonTerminal("count"); var value = new NonTerminal("value"); var @ref = new NonTerminal("ref"); var resourcePath = new NonTerminal("resourcePath"); var boundOperation = new NonTerminal("boundOperation"); //propertyPath boundOperation singleNavigation var boundOperation_PropertyPath = new NonTerminal("boundOperation"); //collectionPath singlePath complexPath var objectPath = new NonTerminal("objectPath"); var functionParameters = new NonTerminal("functionParameters"); var functionParameter = new NonTerminal("functionParameter"); var parameterAlias = new NonTerminal("parameterAlias"); var functionParameterList = new NonTerminal("functionParameter"); var crossjoin = new NonTerminal("crossjoin"); var crossjoinList = new NonTerminal("crossjoinList"); #endregion #region 2. Query Options Termianl var entityOption = new NonTerminal("entityOption"); var entityOptions = new NonTerminal("entityOptions"); var id = new NonTerminal("id"); var searchOrExpr = new NonTerminal("searchOrExpr"); var searchPhrase = new NonTerminal("searchPhrase"); var searchWord = new NonTerminal("searchWord"); var selectItem = new NonTerminal("selectItem"); var systemQueryOption = new NonTerminal("systemQueryOption"); var aliasAndValue = new NonTerminal("aliasAndValue"); var customQueryOption = new NonTerminal("customQueryOption"); var expand = new NonTerminal("expand"); var filter = new NonTerminal("filter"); var format = new NonTerminal("format"); var inlinecount = new NonTerminal("inlinecount"); var orderby = new NonTerminal("orderby"); var search = new NonTerminal("search"); var select = new NonTerminal("select"); var skip = new NonTerminal("skip"); var skiptoken = new NonTerminal("skiptoken"); var top = new NonTerminal("top"); var expandItems = new NonTerminal("expandItems"); var levels = new NonTerminal("levels"); var expandPath = new NonTerminal("expandPath"); var expandRefOptions = new NonTerminal("expandRefOptions"); var expandCountOptions = new NonTerminal("expandCountOptions"); var expandOptions = new NonTerminal("expandOptions"); var expandCountOption = new NonTerminal("expandCountOption"); var expandRefOption = new NonTerminal("expandRefOption"); var orderbyItems = new NonTerminal("orderbyItems"); var searchExpr = new NonTerminal("searchExpr"); var searchTerm = new NonTerminal("searchTerm"); var searchAndExpr = new NonTerminal("searchAndExpr"); var selectItems = new NonTerminal("selectItems"); var allOperationsInSchema = new NonTerminal("allOperationsInSchema"); var action = new NonTerminal("action"); var _function = new NonTerminal("_function"); var parameterNames = new NonTerminal("parameterNames"); var parameterValue = new NonTerminal("parameterValue"); var customName = new NonTerminal("customName"); var queryOptions = new NonTerminal("queryOptions"); var queryOption = new NonTerminal("queryOption"); var expandItem = new NonTerminal("expandItem"); var expandOption = new NonTerminal("expandOption"); var orderbyItem = new NonTerminal("orderbyItem"); var selectProperty = new NonTerminal("selectProperty"); var parameterName = new NonTerminal("parameterName"); var customValue = new NonTerminal("customValue"); var selectOptionPC = new NonTerminal("selectOptionPC"); var selectOption = new NonTerminal("selectOption"); #endregion #region 2.1 System Query Option $apply Termianl var apply = new NonTerminal("apply"); var applyExpr = new NonTerminal("applyExpr"); var applyTrafo = new NonTerminal("applyTrafo"); var aggregateTrafo = new NonTerminal("aggregateTrafo"); var bottomcountTrafo = new NonTerminal("bottomcountTrafo"); var bottompercentTrafo = new NonTerminal("bottompercentTrafo"); var bottomsumTrafo = new NonTerminal("bottomsumTrafo"); var computeTrafo = new NonTerminal("computeTrafo"); var concatTrafo = new NonTerminal("concatTrafo"); var expandTrafo = new NonTerminal("expandTrafo"); var filterTrafo = new NonTerminal("filterTrafo"); var groupbyTrafo = new NonTerminal("groupbyTrafo"); var identityTrafo = new NonTerminal("identityTrafo"); var searchTrafo = new NonTerminal("searchTrafo"); var topcountTrafo = new NonTerminal("topcountTrafo"); var toppercentTrafo = new NonTerminal("toppercentTrafo"); var topsumTrafo = new NonTerminal("topsumTrafo"); var customFunction = new NonTerminal("customFunction"); var aggregateExpr = new NonTerminal("aggregateExpr"); var asAlias = new NonTerminal("asAlias"); var aggregateFrom = new NonTerminal("aggregateFrom"); var aggregateWith = new NonTerminal("aggregateWith"); var aggregateMethod = new NonTerminal("aggregateMethod"); var groupingProperty = new NonTerminal("groupingProperty"); var entityNavigationProperty = new NonTerminal("entityNavigationProperty"); var primitiveProperty = new NonTerminal("primitiveProperty"); var pathSegment = new NonTerminal("pathSegment"); var navigationProperty = new NonTerminal("navigationProperty"); var computeExpr = new NonTerminal("computeExpr"); var groupbyList = new NonTerminal("groupbyList"); var groupbyElement = new NonTerminal("groupbyElement"); var rollupSpec = new NonTerminal("rollupSpec"); var entityColFunction = new NonTerminal("entityColFunction"); var groupbyElements = new NonTerminal("groupbyElements"); var groupingPropertys = new NonTerminal("groupingPropertys"); var computeExprs = new NonTerminal("computeExprs"); var applyExprs = new NonTerminal("applyExprs"); var expandfilterTrafos = new NonTerminal("expandfilterTrafos"); var aggregateExprs = new NonTerminal("aggregateExprs"); #endregion #region 4. Expressions Termianl var rootExpr = new NonTerminal("rootExpr"); var firstMemberExpr = new NonTerminal("firstMemberExpr"); var functionExpr = new NonTerminal("functionExpr"); var parenExpr = new NonTerminal("parenExpr"); var commonExpr = new NonTerminal("commonExpr"); var memberPathExpr = new NonTerminal("memberPathExpr"); var boolCommonExpr = commonExpr; var negateExpr = new NonTerminal("negateExpr"); var methodCallExpr = new NonTerminal("methodCallExpr"); var castExpr = new NonTerminal("castExpr"); var addExpr = new NonTerminal("addExpr"); var subExpr = new NonTerminal("subExpr"); var mulExpr = new NonTerminal("mulExpr"); var divExpr = new NonTerminal("divExpr"); var modExpr = new NonTerminal("modExpr"); var boolMethodCallExpr = new NonTerminal("boolMethodCallExpr"); var notExpr = new NonTerminal("notExpr"); var neExpr = new NonTerminal("neExpr"); var ltExpr = new NonTerminal("ltExpr"); var leExpr = new NonTerminal("leExpr"); var gtExpr = new NonTerminal("gtExpr"); var geExpr = new NonTerminal("geExpr"); var hasExpr = new NonTerminal("hasExpr"); var andExpr = new NonTerminal("andExpr"); var orExpr = new NonTerminal("orExpr"); var eqExpr = new NonTerminal("eqExpr"); var isofExpr = new NonTerminal("isofExpr"); var lambdaExpr = new NonTerminal("lambdaExpr"); var anyExpr = new NonTerminal("anyExpr"); var allExpr = new NonTerminal("allExpr"); var indexOfMethodCallExpr = new NonTerminal("indexOfMethodCallExpr"); var toLowerMethodCallExpr = new NonTerminal("toLowerMethodCallExpr"); var toUpperMethodCallExpr = new NonTerminal("toUpperMethodCallExpr"); var trimMethodCallExpr = new NonTerminal("trimMethodCallExpr"); var substringMethodCallExpr = new NonTerminal("substringMethodCallExpr"); var concatMethodCallExpr = new NonTerminal("concatMethodCallExpr"); var lengthMethodCallExpr = new NonTerminal("lengthMethodCallExpr"); var yearMethodCallExpr = new NonTerminal("yearMethodCallExpr"); var monthMethodCallExpr = new NonTerminal("monthMethodCallExpr"); var dayMethodCallExpr = new NonTerminal("dayMethodCallExpr"); var hourMethodCallExpr = new NonTerminal("hourMethodCallExpr"); var minuteMethodCallExpr = new NonTerminal("minuteMethodCallExpr"); var secondMethodCallExpr = new NonTerminal("secondMethodCallExpr"); var fractionalsecondsMethodCallExpr = new NonTerminal("fractionalsecondsMethodCallExpr"); var totalsecondsMethodCallExpr = new NonTerminal("totalsecondsMethodCallExpr"); var dateMethodCallExpr = new NonTerminal("dateMethodCallExpr"); var timeMethodCallExpr = new NonTerminal("timeMethodCallExpr"); var roundMethodCallExpr = new NonTerminal("roundMethodCallExpr"); var floorMethodCallExpr = new NonTerminal("floorMethodCallExpr"); var ceilingMethodCallExpr = new NonTerminal("ceilingMethodCallExpr"); var distanceMethodCallExpr = new NonTerminal("distanceMethodCallExpr"); var geoLengthMethodCallExpr = new NonTerminal("geoLengthMethodCallExpr"); var totalOffsetMinutesMethodCallExpr = new NonTerminal("totalOffsetMinutesMethodCallExpr"); var minDateTimeMethodCallExpr = new NonTerminal("minDateTimeMethodCallExpr"); var maxDateTimeMethodCallExpr = new NonTerminal("maxDateTimeMethodCallExpr"); var nowMethodCallExpr = new NonTerminal("nowMethodCallExpr"); var endsWithMethodCallExpr = new NonTerminal("endsWithMethodCallExpr"); var startsWithMethodCallExpr = new NonTerminal("startsWithMethodCallExpr"); var containsMethodCallExpr = new NonTerminal("containsMethodCallExpr"); var intersectsMethodCallExpr = new NonTerminal("intersectsMethodCallExpr"); var singlePathExpr = new NonTerminal("singlePathExpr"); var collectionPathExpr = new NonTerminal("collectionPathExpr"); var functionExprContent = new NonTerminal("functionExprContent"); var functionExprParameter = new NonTerminal("functionExprParameter"); var functionExprParameters = new NonTerminal("functionExprParameters"); #endregion #region 5. JSON format for function parameters Termianl var begin_object = ToTerm("{"); var end_object = ToTerm("}"); var begin_array = ToTerm("["); var end_array = ToTerm("]"); var quotation_mark = DQUOTE; var name_separator = COLON; var value_separator = COMMA; var primitiveLiteralInJSON = new NonTerminal("primitiveLiteralInJSON"); var arrayOrObject = new NonTerminal("arrayOrObject"); var termName = new NonTerminal("termName"); var arrayInUri = new NonTerminal("arrayInUri"); var arrayItemsInUri = new NonTerminal("arrayItemsInUri"); var complexInUri = new NonTerminal("complexInUri"); var complexInUris = new NonTerminal("complexInUris"); var objectPropertyInUri = new NonTerminal("objectPropertyInUri"); #endregion #region 6. Names and identifiers Termianl var odataIdentifier = new IdentifierTerminal("odataIdentifier"); odataIdentifier.SetFlag(TermFlags.NoAstNode); var qualifiedFullName = new NonTerminal("qualifiedFullName"); var qualifiedTypeName = new NonTerminal("qualifiedTypeName"); #endregion #region 7. Literal Data Values Terminal var numberInt = new NumberLiteral("number", NumberOptions.IntOnly); var booleanValue = ToTerm("true") | ToTerm("false"); var dquoteString = new StringLiteral("dquoteString", "\""); var primitiveLiteral = new NonTerminal("primitiveLiteral"); var binary = new NonTerminal("binary"); var @null = new NonTerminal("null"); var nullValue = new NonTerminal("nullValue"); var numberLiteral = new NumberLiteral("numberLiteral"); var stringLiteral = new StringLiteral("stringLiteral", "'"); var guid = new NonTerminal("guid"); var date = new NonTerminal("date"); var dateTime = new NonTerminal("dateTime"); var dateTimeOffset = new NonTerminal("dateTimeOffset"); var timeOfDay = new NonTerminal("timeOfDay"); var duration = new NonTerminal("duration"); var @enum = new NonTerminal("enum"); var enumValue = new NonTerminal("enumValue"); var single_enumValue = new NonTerminal("single_enumValue"); #endregion #region 1. Resource Path Rule resourcePath.Rule = boundOperation + objectPath.Q() | crossjoin | "$all"; keyPredicate.Rule = OPEN + keyValuePairs + CLOSE; keyValuePairs.Rule = MakePlusRule(keyValuePairs, COMMA, keyValuePair); keyValuePair.Rule = (odataIdentifier + EQ).Q() + primitiveLiteral; count.Rule = SLASH + "$count"; @ref.Rule = SLASH + "$ref"; value.Rule = SLASH + "$value"; //collectionPath singlePath complexPath objectPath.Rule = @ref | count | value | boundOperation_PropertyPath; //propertyPath boundOperation singleNavigation collectionNavigation boundOperation_PropertyPath.Rule = SLASH + boundOperation + objectPath.Q(); boundOperation.Rule = qualifiedFullName + functionParameters.Q(); functionParameters.Rule = OPEN + functionParameterList + CLOSE; functionParameterList.Rule = MakeStarRule(functionParameterList, COMMA, functionParameter); functionParameter.Rule = (odataIdentifier + EQ).Q() + (parameterAlias | primitiveLiteral); parameterAlias.Rule = AT + odataIdentifier; parameterName.Rule = odataIdentifier; crossjoin.Rule = "$crossjoin" + OPEN + crossjoinList + CLOSE; crossjoinList.Rule = MakePlusRule(crossjoinList, COMMA, odataIdentifier); #endregion #region 2. Query Options Rule queryOptions.Rule = MakePlusRule(queryOptions, AND, queryOption); queryOption.Rule = systemQueryOption | aliasAndValue | customQueryOption; entityOptions.Rule = MakeStarRule(entityOptions, AND, entityOption); entityOption.Rule = expand | id | format | select | customQueryOption; id.Rule = ToTerm("$id") + EQ + ODataTermianlFacotry.CreateCustomQueryOption("odataid"); systemQueryOption.Rule = expand | filter | format | id | inlinecount | orderby | search | select | skip | skiptoken | apply | top; expand.Rule = "$expand" + EQ + expandItems; expandItems.Rule = MakeStarRule(expandItems, COMMA, expandItem); expandItem.Rule = STAR + (@ref | OPEN + levels + CLOSE).Q() | expandPath + ((@ref | count) + (OPEN + expandRefOptions + CLOSE).Q() | OPEN + expandOptions + CLOSE ).Q(); expandPath.Rule = MakePlusRule(expandPath, SLASH, qualifiedFullName); expandCountOptions.Rule = MakeStarRule(expandCountOptions, SEMI, expandCountOption); expandRefOptions.Rule = MakeStarRule(expandRefOptions, SEMI, expandRefOption); expandCountOption.Rule = filter | search; expandRefOption.Rule = expandCountOption | orderby | skip | top | inlinecount; expandOptions.Rule = MakeStarRule(expandOptions, SEMI, expandOption); expandOption.Rule = expandRefOption | select | apply | expand | levels; levels.Rule = "$levels" + EQ + (numberInt | "max"); filter.Rule = "$filter" + EQ + boolCommonExpr; orderby.Rule = "$orderby" + EQ + orderbyItems; orderbyItems.Rule = MakeStarRule(orderbyItems, COMMA, orderbyItem); orderbyItem.Rule = commonExpr + ((ToTerm("asc") | "desc")).Q(); skip.Rule = "$skip" + EQ + numberInt; top.Rule = "$top" + EQ + numberInt; format.Rule = "$format" + EQ + (ToTerm("atom") | "json" | "xml" | odataIdentifier ); inlinecount.Rule = "$count" + EQ + booleanValue; search.Rule = "$search" + EQ + searchExpr; searchExpr.Rule = (OPEN + searchExpr + CLOSE | searchTerm) + (searchOrExpr | searchAndExpr).Q(); searchOrExpr.Rule = "OR" + searchExpr; searchAndExpr.Rule = ToTerm("AND").Q() + searchExpr; searchTerm.Rule = ToTerm("NOT").Q() + (searchPhrase | searchWord); searchPhrase.Rule = dquoteString; searchWord.Rule = odataIdentifier; select.Rule = "$select" + EQ + selectItems; selectItems.Rule = MakeStarRule(selectItems, COMMA, selectItem); selectItem.Rule = STAR | allOperationsInSchema | selectProperty + (OPEN + parameterNames + CLOSE).Q(); selectProperty.Rule = MakePlusRule(selectProperty, SLASH, qualifiedFullName); allOperationsInSchema.Rule = qualifiedFullName + "." + STAR; parameterNames.Rule = MakeStarRule(parameterNames, COMMA, parameterName); skiptoken.Rule = "$skiptoken" + EQ + odataIdentifier; aliasAndValue.Rule = parameterAlias + EQ + parameterValue; parameterValue.Rule = commonExpr; customQueryOption.Rule = customName + (EQ + customValue).Q(); customName.Rule = ODataTermianlFacotry.CreateCustomQueryOption("customName"); customValue.Rule = ODataTermianlFacotry.CreateCustomQueryOption("customValue"); #endregion #region 2.1 System Query Option $apply Rule apply.Rule = "$apply" + EQ + applyExpr; applyExpr.Rule = MakePlusRule(applyExpr, SLASH, applyTrafo); applyTrafo.Rule = aggregateTrafo | bottomcountTrafo | bottompercentTrafo | bottomsumTrafo | computeTrafo | concatTrafo | expandTrafo | filterTrafo | groupbyTrafo | identityTrafo | searchTrafo | topcountTrafo | toppercentTrafo | topsumTrafo | customFunction ; aggregateExprs.Rule = MakePlusRule(aggregateExprs, COMMA, aggregateExpr); aggregateTrafo.Rule = "aggregate" + OPEN + aggregateExprs + CLOSE; /* * aggregateExpr = customAggregate [ asAlias aggregateFrom ] * / commonExpr aggregateWith asAlias [ aggregateFrom ] * / pathPrefix '$count' asAlias * / pathPrefix customAggregate * / pathPrefix pathSegment OPEN aggregateExpr CLOSE * * 由于以下两个产生式冲突,因此改写产生式如下 * commonExpr->memberPathExpr * aggregateExpr->pathPrefix pathSegment OPEN aggregateExpr CLOSE */ aggregateExpr.Rule = (commonExpr | "$count") + aggregateWith.Q() + asAlias.Q() + aggregateFrom.Q(); aggregateWith.Rule = "with" + aggregateMethod; aggregateFrom.Rule = "from" + groupingProperty + aggregateWith.Q() + aggregateFrom.Q(); aggregateMethod.Rule = ToTerm("sum") | "min" | "max" | "average" | "countdistinct" | qualifiedFullName; asAlias.Rule = "as" + odataIdentifier; groupingProperty.Rule = pathSegment; pathSegment.Rule = MakePlusRule(pathSegment, SLASH, qualifiedFullName); computeTrafo.Rule = "compute" + OPEN + computeExprs + CLOSE; computeExprs.Rule = MakePlusRule(computeExprs, COMMA, computeExpr); computeExpr.Rule = commonExpr + asAlias; bottomcountTrafo.Rule = "bottomcount" + OPEN + commonExpr + COMMA + commonExpr + CLOSE; bottompercentTrafo.Rule = "bottompercent" + OPEN + commonExpr + COMMA + commonExpr + CLOSE; bottomsumTrafo.Rule = "bottomsum" + OPEN + commonExpr + COMMA + commonExpr + CLOSE; applyExprs.Rule = MakePlusRule(applyExprs, COMMA, applyExpr); expandfilterTrafos.Rule = MakeStarRule(expandfilterTrafos, COMMA + (expandTrafo | filterTrafo)); concatTrafo.Rule = "concat" + OPEN + applyExprs + CLOSE; expandTrafo.Rule = "expand" + OPEN + expandPath + expandfilterTrafos + CLOSE; filterTrafo.Rule = "filter" + OPEN + boolCommonExpr + CLOSE; searchTrafo.Rule = "search" + OPEN + searchExpr + CLOSE; groupbyTrafo.Rule = "groupby" + OPEN + groupbyList + (COMMA + applyExpr).Q() + CLOSE; groupbyList.Rule = OPEN + groupbyElements + CLOSE; groupbyElements.Rule = MakePlusRule(groupbyElements, COMMA, groupbyElement); groupbyElement.Rule = groupingProperty | rollupSpec; groupingPropertys.Rule = MakePlusRule(groupingPropertys, COMMA + groupingProperty); rollupSpec.Rule = "rollup" + OPEN + ("$all" | groupingProperty) + groupingPropertys + CLOSE; identityTrafo.Rule = ToTerm("identity"); topcountTrafo.Rule = "topcount" + OPEN + commonExpr + COMMA + commonExpr + CLOSE; toppercentTrafo.Rule = "toppercent" + OPEN + commonExpr + COMMA + commonExpr + CLOSE; topsumTrafo.Rule = "topsum" + OPEN + commonExpr + COMMA + commonExpr + CLOSE; customFunction.Rule = qualifiedFullName + OPEN + functionExprParameters + CLOSE; #endregion #region 4. Expressions Rule /* * commonExpr = ( primitiveLiteral * / parameterAlias * / arrayOrObject * / rootExpr * / firstMemberExpr * / functionExpr * / negateExpr * / methodCallExpr * / parenExpr * / castExpr * ) * [ addExpr * / subExpr * / mulExpr * / divExpr * / modExpr * ] * * boolCommonExpr = ( isofExpr * / boolMethodCallExpr * / notExpr * / commonExpr * [ eqExpr * / neExpr * / ltExpr * / leExpr * / gtExpr * / geExpr * / hasExpr * ] * / boolParenExpr * ) [ andExpr / orExpr ] * 解决 boolParenExpr 与 parenExpr 解析冲突 */ commonExpr.Rule = (primitiveLiteral | parameterAlias | arrayOrObject | castExpr | rootExpr | firstMemberExpr | memberPathExpr | methodCallExpr | isofExpr | boolMethodCallExpr | notExpr | parenExpr | negateExpr ) + (addExpr | subExpr | mulExpr | divExpr | modExpr | eqExpr | neExpr | ltExpr | leExpr | gtExpr | geExpr | hasExpr | andExpr | orExpr ).Q(); parenExpr.Rule = OPEN + commonExpr + CLOSE; rootExpr.Rule = ToTerm("$root/") + odataIdentifier + keyPredicate.Q() + (singlePathExpr | collectionPathExpr).Q(); firstMemberExpr.Rule = ToTerm("$it") + (SLASH + memberPathExpr).Q(); collectionPathExpr.Rule = count | SLASH + anyExpr | SLASH + allExpr; singlePathExpr.Rule = SLASH + memberPathExpr; memberPathExpr.Rule = functionExpr + (singlePathExpr | collectionPathExpr).Q(); functionExpr.Rule = qualifiedFullName + functionExprContent.Q(); functionExprContent.Rule = OPEN + functionExprParameters + CLOSE; functionExprParameters.Rule = MakeStarRule(functionExprParameters, COMMA, functionExprParameter); functionExprParameter.Rule = parameterName + EQ + parameterValue | aggregateExpr; lambdaExpr.Rule = odataIdentifier + COLON + boolCommonExpr; anyExpr.Rule = ToTerm("any") + OPEN + lambdaExpr.Q() + CLOSE; allExpr.Rule = ToTerm("all") + OPEN + lambdaExpr + CLOSE; methodCallExpr.Rule = indexOfMethodCallExpr | toLowerMethodCallExpr | toUpperMethodCallExpr | trimMethodCallExpr | substringMethodCallExpr | concatMethodCallExpr | lengthMethodCallExpr | yearMethodCallExpr | monthMethodCallExpr | dayMethodCallExpr | hourMethodCallExpr | minuteMethodCallExpr | secondMethodCallExpr | fractionalsecondsMethodCallExpr | totalsecondsMethodCallExpr | dateMethodCallExpr | timeMethodCallExpr | roundMethodCallExpr | floorMethodCallExpr | ceilingMethodCallExpr | distanceMethodCallExpr | geoLengthMethodCallExpr | totalOffsetMinutesMethodCallExpr | minDateTimeMethodCallExpr | maxDateTimeMethodCallExpr | nowMethodCallExpr; boolMethodCallExpr.Rule = endsWithMethodCallExpr | startsWithMethodCallExpr | containsMethodCallExpr | intersectsMethodCallExpr; containsMethodCallExpr.Rule = "contains" + OPEN + commonExpr + COMMA + commonExpr + CLOSE; startsWithMethodCallExpr.Rule = "startswith" + OPEN + commonExpr + COMMA + commonExpr + CLOSE; endsWithMethodCallExpr.Rule = "endswith" + OPEN + commonExpr + COMMA + commonExpr + CLOSE; lengthMethodCallExpr.Rule = "length" + OPEN + commonExpr + CLOSE; indexOfMethodCallExpr.Rule = "indexof" + OPEN + commonExpr + COMMA + commonExpr + CLOSE; substringMethodCallExpr.Rule = "substring" + OPEN + commonExpr + COMMA + commonExpr + (COMMA + commonExpr).Q() + CLOSE; toLowerMethodCallExpr.Rule = "tolower" + OPEN + commonExpr + CLOSE; toUpperMethodCallExpr.Rule = "toupper" + OPEN + commonExpr + CLOSE; trimMethodCallExpr.Rule = "trim" + OPEN + commonExpr + CLOSE; concatMethodCallExpr.Rule = "concat" + OPEN + commonExpr + COMMA + commonExpr + CLOSE; yearMethodCallExpr.Rule = "year" + OPEN + commonExpr + CLOSE; monthMethodCallExpr.Rule = "month" + OPEN + commonExpr + CLOSE; dayMethodCallExpr.Rule = "day" + OPEN + commonExpr + CLOSE; hourMethodCallExpr.Rule = "hour" + OPEN + commonExpr + CLOSE; minuteMethodCallExpr.Rule = "minute" + OPEN + commonExpr + CLOSE; secondMethodCallExpr.Rule = "second" + OPEN + commonExpr + CLOSE; fractionalsecondsMethodCallExpr.Rule = "fractionalseconds" + OPEN + commonExpr + CLOSE; totalsecondsMethodCallExpr.Rule = "totalseconds" + OPEN + commonExpr + CLOSE; dateMethodCallExpr.Rule = "date" + OPEN + commonExpr + CLOSE; timeMethodCallExpr.Rule = "time" + OPEN + commonExpr + CLOSE; totalOffsetMinutesMethodCallExpr.Rule = "totaloffsetminutes" + OPEN + commonExpr + CLOSE; minDateTimeMethodCallExpr.Rule = ToTerm("mindatetime(") + ")"; maxDateTimeMethodCallExpr.Rule = ToTerm("maxdatetime(") + ")"; nowMethodCallExpr.Rule = ToTerm("now(") + ")"; roundMethodCallExpr.Rule = "round" + OPEN + commonExpr + CLOSE; floorMethodCallExpr.Rule = "floor" + OPEN + commonExpr + CLOSE; ceilingMethodCallExpr.Rule = "ceiling" + OPEN + commonExpr + CLOSE; distanceMethodCallExpr.Rule = "geo.distance" + OPEN + commonExpr + COMMA + commonExpr + CLOSE; geoLengthMethodCallExpr.Rule = "geo.length" + OPEN + commonExpr + CLOSE; intersectsMethodCallExpr.Rule = "geo.intersects" + OPEN + commonExpr + COMMA + commonExpr + CLOSE; isofExpr.Rule = ToTerm("isof") + OPEN + commonExpr + COMMA + qualifiedTypeName + CLOSE; castExpr.Rule = ToTerm("cast") + OPEN + commonExpr + COMMA + qualifiedTypeName + CLOSE; andExpr.Rule = ToTerm("and") + boolCommonExpr; orExpr.Rule = ToTerm("or") + boolCommonExpr; eqExpr.Rule = "eq" + commonExpr; neExpr.Rule = "ne" + commonExpr; ltExpr.Rule = "lt" + commonExpr; leExpr.Rule = "le" + commonExpr; gtExpr.Rule = "gt" + commonExpr; geExpr.Rule = "ge" + commonExpr; hasExpr.Rule = "has" + commonExpr; addExpr.Rule = "add" + commonExpr; subExpr.Rule = "sub" + commonExpr; mulExpr.Rule = "mul" + commonExpr; divExpr.Rule = "div" + commonExpr; modExpr.Rule = "mod" + commonExpr; negateExpr.Rule = ToTerm("-") + commonExpr; notExpr.Rule = "not" + boolCommonExpr; #endregion #region 5. JSON format for function parameters Rule arrayOrObject.Rule = arrayInUri | complexInUri; arrayInUri.Rule = begin_array + arrayItemsInUri + end_array; arrayItemsInUri.Rule = MakeStarRule(arrayItemsInUri, value_separator, complexInUri | primitiveLiteralInJSON | rootExpr); complexInUri.Rule = begin_object + complexInUris + end_object; complexInUris.Rule = MakeStarRule(complexInUris, value_separator, objectPropertyInUri); objectPropertyInUri.Rule = quotation_mark + odataIdentifier + quotation_mark + name_separator + (arrayInUri | complexInUri | primitiveLiteralInJSON | rootExpr ); primitiveLiteralInJSON.Rule = dquoteString | numberLiteral | booleanValue | @null; #endregion #region 6. Names and identifiers qualifiedTypeName.Rule = qualifiedFullName | "Collection" + OPEN + qualifiedFullName + CLOSE; qualifiedFullName.Rule = MakePlusRule(qualifiedFullName, DOT, odataIdentifier); #endregion #region 7. Literal Data Values primitiveLiteral.Rule = @null | booleanValue | guid | date | dateTime | dateTimeOffset | timeOfDay | duration | @enum | binary | numberLiteral | stringLiteral; @null.Rule = nullValue + (SQUOTE + qualifiedTypeName + SQUOTE).Q(); nullValue.Rule = "null"; binary.Rule = (ToTerm("X") | "binary") + SQUOTE + ODataTermianlFacotry.CreateBinary("binaryValue") + SQUOTE; guid.Rule = ToTerm("guid") + SQUOTE + ODataTermianlFacotry.CreateGuid("guidValue") + SQUOTE; date.Rule = ToTerm("date") + SQUOTE + ODataTermianlFacotry.CreateDate("dateValue") + SQUOTE; dateTime.Rule = ToTerm("datetime") + SQUOTE + ODataTermianlFacotry.CreateDateTime("dateTimeValue") + SQUOTE; dateTimeOffset.Rule = ToTerm("datetimeoffset") + SQUOTE + ODataTermianlFacotry.CreateDateTimeOffset("dateTimeOffsetValue") + SQUOTE; timeOfDay.Rule = ToTerm("timeofday") + SQUOTE + ODataTermianlFacotry.CreateTimeOfDay("timeOfDayValue") + SQUOTE; duration.Rule = ToTerm("duration") + SQUOTE + ODataTermianlFacotry.CreateDuration("durationValue") + SQUOTE; @enum.Rule = ToTerm("enum") + qualifiedFullName + SQUOTE + enumValue + SQUOTE; enumValue.Rule = MakeStarRule(enumValue, COMMA, single_enumValue); single_enumValue.Rule = odataIdentifier | numberInt; #endregion // TODO: 3. Context URL Fragments // TODO: context odataRelativeUri.Rule = "$batch" | "$entity" + QUESTION + entityOptions | "$metadata" + (QUESTION + format).Q("metadataFormat") //[context] | resourcePath + (QUESTION + queryOptions).Q("resourceQuery"); Root = odataRelativeUri; }
private NonTerminal Expression(NonTerminal identifier, NonTerminal selectStatement) { var datePartLiteral = NonTerminal("datePartLiteral", null, c => new LiteralExpression { Value = ToDatePart(c), SqlType = SqlType.DatePart }); var stringLiteral = new StringLiteral("string", "\"", StringOptions.AllowsAllEscapes | StringOptions.AllowsDoubledQuote, (context, node) => node.AstNode = new LiteralExpression { Value = node.Token.Value }); var parameterName = new IdentifierTerminal("parameterName") { AllFirstChars = validChars, AllChars = validChars + "1234567890" }; parameterName.SetFlag(TermFlags.NoAstNode); var parameterLiteral = NonTerminal("parameter", "&" + parameterName, node => new ParameterExpression { Name = node.ChildNodes[1].Token.ValueString }); var valueLiteral = NonTerminal("valueLiteral", Transient("valueFunction", ToTerm("value") | "ЗНАЧЕНИЕ") + "(" + identifier + ")", node => new ValueLiteralExpression { Value = ((Identifier)node.ChildNodes[1].AstNode).Value }); var nullLiteral = NonTerminal("nullLiteral", ToTerm("null"), node => new LiteralExpression()); var boolLiteral = NonTerminal("boolLiteral", ToTerm("true") | "false" | "ложь" | "истина", node => { var text = node.FindTokenAndGetText().ToLower(); return(new LiteralExpression { Value = text == "true" || text == "истина" }); }); var columnRef = NonTerminal("columnRef", identifier, n => new ColumnReferenceExpression { Name = ((Identifier)n.ChildNodes[0].AstNode).Value }); var term = NonTerminal("term", null, TermFlags.IsTransient); var binOp = NonTerminal("binOp", null, ToBinaryOperator); binOp.SetFlag(TermFlags.InheritPrecedence); var inExpr = NonTerminal("inExpr", null, ToInExpression); var binExpr = NonTerminal("binExpr", null, ToBinaryExpression); var exprList = NonTerminal("exprList", null); var aggregateFunctionName = NonTerminal("aggregationFunctionName", null, ToAggregationFunction); var aggregateArg = NonTerminal("aggregateArg", null); var aggregate = NonTerminal("aggregate", null, ToAggregateFunctionExpression); var queryFunctionExpr = NonTerminal("queryFunctionExpr", null, ToQueryFunctionExpression); var isNullExpression = NonTerminal("isNullExpression", null, ToIsNullExpression); var isReferenceExpression = NonTerminal("isReference", columnRef + "ССЫЛКА" + identifier, ToIsReferenceExpression); var isNull = NonTerminal("isNull", null, TermFlags.NoAstNode); var expression = NonTerminal("expression", null, TermFlags.IsTransient); var unExpr = NonTerminal("unExpr", null, ToUnaryExpression); var subquery = NonTerminal("parSelectStatement", null, ToSubquery); var unOp = NonTerminal("unOp", null, ToUnaryOperator); unOp.SetFlag(TermFlags.InheritPrecedence); var functionArgs = NonTerminal("funArgs", null, TermFlags.IsTransient); var parExpr = NonTerminal("parExpr", null, TermFlags.IsTransient); var parExprList = NonTerminal("parExprList", null, TermFlags.IsTransient); var dateTruncExpression = NonTerminal("dateTruncExpression", null, ToDateTruncExpression); var caseElement = NonTerminal("caseElement", null, ToCaseElement); var caseElementList = NonTerminal("caseElementList", null); var caseExpression = NonTerminal("caseExpression", null, ToCaseExpression); var defaultCaseOpt = NonTerminal("defaultCaseOpt", null, c => c.ChildNodes.Count > 1 ? c.ChildNodes[1].AstNode : null); //rules exprList.Rule = MakeStarRule(exprList, ToTerm(","), expression); parExprList.Rule = "(" + exprList + ")"; parExpr.Rule = "(" + expression + ")"; term.Rule = columnRef | stringLiteral | numberLiteral | valueLiteral | boolLiteral | nullLiteral | aggregate | queryFunctionExpr | parameterLiteral | parExpr | subquery; subquery.Rule = "(" + selectStatement + ")"; unOp.Rule = not | "-"; unExpr.Rule = unOp + expression; binOp.Rule = ToTerm("+") | "-" | "*" | "/" | "%" | "=" | ">" | "<" | ">=" | "<=" | "<>" | "!=" | "AND" | "OR" | "LIKE" | "И" | "ИЛИ" | "ПОДОБНО"; binExpr.Rule = expression + binOp + expression; expression.Rule = term | unExpr | binExpr | inExpr | isNullExpression | isReferenceExpression | dateTruncExpression | caseExpression; functionArgs.Rule = parExprList | subquery; queryFunctionExpr.Rule = identifier + functionArgs; aggregateFunctionName.Rule = ToTerm(aggregateFunctions[0]); for (var i = 1; i < aggregateFunctions.Length; i++) { aggregateFunctionName.Rule |= aggregateFunctions[i]; } aggregateArg.Rule = ToTerm("*") | distinctOpt + expression; aggregate.Rule = aggregateFunctionName + "(" + aggregateArg + ")"; inExpr.Rule = columnRef + Transient("in", ToTerm("IN") | "В") + functionArgs; datePartLiteral.Rule = ToTerm("year") | "quarter" | "month" | "week" | "day" | "hour" | "minute" | "ГОД" | "КВАРТАЛ" | "МЕСЯЦ" | "НЕДЕЛЯ" | "ДЕНЬ" | "ЧАС" | "МИНУТА"; dateTruncExpression.Rule = Transient("beginOfPeriod", ToTerm("beginOfPeriod") | "НачалоПериода") + ToTerm("(") + expression + "," + datePartLiteral + ")"; caseElement.Rule = Transient("when", ToTerm("WHEN") | "КОГДА") + expression + Transient("then", ToTerm("THEN") | "ТОГДА") + expression; caseElementList.Rule = MakeListRule(caseElementList, Empty, caseElement); caseExpression.Rule = Transient("case", ToTerm("CASE") | "ВЫБОР") + caseElementList + defaultCaseOpt + Transient("end", ToTerm("END") | "КОНЕЦ"); defaultCaseOpt.Rule = Empty | (Transient("else", ToTerm("ELSE") | "ИНАЧЕ") + expression); isNull.Rule = NonTerminal("is", ToTerm("IS") | "ЕСТЬ") + (Empty | not) + "NULL"; isNullExpression.Rule = term + isNull; return(expression); }