UNPKG

trader-server

Version:

OData server for testing strategies, simulating and real trading.

810 lines (714 loc) 36.3 kB
import Utils from "./utils"; import Lexer from "./lexer"; import PrimitiveLiteral from "./primitiveLiteral"; import NameOrIdentifier from "./nameOrIdentifier"; import ArrayOrObject from "./json"; export namespace Expressions { export function commonExpr(value: Utils.SourceArray, index: number): Lexer.Token { let token = PrimitiveLiteral.primitiveLiteral(value, index) || parameterAlias(value, index) || ArrayOrObject.arrayOrObject(value, index) || rootExpr(value, index) || methodCallExpr(value, index) || firstMemberExpr(value, index) || functionExpr(value, index) || negateExpr(value, index) || parenExpr(value, index) || castExpr(value, index); if (!token) return; let expr = addExpr(value, token.next) || subExpr(value, token.next) || mulExpr(value, token.next) || divExpr(value, token.next) || modExpr(value, token.next); if (expr) { token.value = { left: Lexer.clone(token), right: expr.value }; token.next = expr.value.next; token.type = expr.type; token.raw = Utils.stringify(value, token.position, token.next); } if (token) return Lexer.tokenize(value, token.position, token.next, token, Lexer.TokenType.CommonExpression); } export function boolCommonExpr(value: Utils.SourceArray, index: number): Lexer.Token { let token = isofExpr(value, index) || boolMethodCallExpr(value, index) || notExpr(value, index) || commonExpr(value, index) || boolParenExpr(value, index); if (!token) return; let commonMoreExpr = undefined; if (token.type === Lexer.TokenType.CommonExpression) { commonMoreExpr = eqExpr(value, token.next) || neExpr(value, token.next) || ltExpr(value, token.next) || leExpr(value, token.next) || gtExpr(value, token.next) || geExpr(value, token.next) || hasExpr(value, token.next); if (commonMoreExpr) { token.value = { left: token.value, right: commonMoreExpr.value }; token.next = commonMoreExpr.value.next; token.type = commonMoreExpr.type; token.raw = Utils.stringify(value, token.position, token.next); } } let expr = andExpr(value, token.next) || orExpr(value, token.next); if (expr) { let left = Lexer.clone(token); token.next = expr.value.next; token.value = { left: left, right: expr.value }; token.type = expr.type; token.raw = Utils.stringify(value, token.position, token.next); if (token.type === Lexer.TokenType.AndExpression && token.value.right.type === Lexer.TokenType.OrExpression) { token.value.left = Lexer.tokenize(value, token.value.left.position, token.value.right.value.left.next, { left: token.value.left, right: token.value.right.value.left }, token.type); token.type = token.value.right.type; token.value.right = token.value.right.value.right; } } return token; } export function andExpr(value: Utils.SourceArray, index: number): Lexer.Token { let rws = Lexer.RWS(value, index); if (rws === index || !Utils.equals(value, rws, "and")) return; let start = index; index = rws + 3; rws = Lexer.RWS(value, index); if (rws === index) return; index = rws; let token = boolCommonExpr(value, index); if (!token) return; return Lexer.tokenize(value, start, index, token, Lexer.TokenType.AndExpression); } export function orExpr(value: Utils.SourceArray, index: number): Lexer.Token { let rws = Lexer.RWS(value, index); if (rws === index || !Utils.equals(value, rws, "or")) return; let start = index; index = rws + 2; rws = Lexer.RWS(value, index); if (rws === index) return; index = rws; let token = boolCommonExpr(value, index); if (!token) return; return Lexer.tokenize(value, start, index, token, Lexer.TokenType.OrExpression); } export function leftRightExpr(value: Utils.SourceArray, index: number, expr: string, tokenType: Lexer.TokenType): Lexer.Token { let rws = Lexer.RWS(value, index); if (rws === index) return; let start = index; index = rws; if (!Utils.equals(value, index, expr)) return; index += expr.length; rws = Lexer.RWS(value, index); if (rws === index) return; index = rws; let token = commonExpr(value, index); if (!token) return; return Lexer.tokenize(value, start, index, token.value, tokenType); } export function eqExpr(value: Utils.SourceArray, index: number): Lexer.Token { return leftRightExpr(value, index, "eq", Lexer.TokenType.EqualsExpression); } export function neExpr(value: Utils.SourceArray, index: number): Lexer.Token { return leftRightExpr(value, index, "ne", Lexer.TokenType.NotEqualsExpression); } export function ltExpr(value: Utils.SourceArray, index: number): Lexer.Token { return leftRightExpr(value, index, "lt", Lexer.TokenType.LesserThanExpression); } export function leExpr(value: Utils.SourceArray, index: number): Lexer.Token { return leftRightExpr(value, index, "le", Lexer.TokenType.LesserOrEqualsExpression); } export function gtExpr(value: Utils.SourceArray, index: number): Lexer.Token { return leftRightExpr(value, index, "gt", Lexer.TokenType.GreaterThanExpression); } export function geExpr(value: Utils.SourceArray, index: number): Lexer.Token { return leftRightExpr(value, index, "ge", Lexer.TokenType.GreaterOrEqualsExpression); } export function hasExpr(value: Utils.SourceArray, index: number): Lexer.Token { return leftRightExpr(value, index, "has", Lexer.TokenType.HasExpression); } export function addExpr(value: Utils.SourceArray, index: number): Lexer.Token { return leftRightExpr(value, index, "add", Lexer.TokenType.AddExpression); } export function subExpr(value: Utils.SourceArray, index: number): Lexer.Token { return leftRightExpr(value, index, "sub", Lexer.TokenType.SubExpression); } export function mulExpr(value: Utils.SourceArray, index: number): Lexer.Token { return leftRightExpr(value, index, "mul", Lexer.TokenType.MulExpression); } export function divExpr(value: Utils.SourceArray, index: number): Lexer.Token { return leftRightExpr(value, index, "div", Lexer.TokenType.DivExpression); } export function modExpr(value: Utils.SourceArray, index: number): Lexer.Token { return leftRightExpr(value, index, "mod", Lexer.TokenType.ModExpression); } export function notExpr(value: Utils.SourceArray, index: number): Lexer.Token { if (!Utils.equals(value, index, "not")) return; let start = index; index += 3; let rws = Lexer.RWS(value, index); if (rws === index) return; index = rws; let token = boolCommonExpr(value, index); if (!token) return; return Lexer.tokenize(value, start, token.next, token, Lexer.TokenType.NotExpression); } export function boolParenExpr(value: Utils.SourceArray, index: number): Lexer.Token { let open = Lexer.OPEN(value, index); if (!open) return; let start = index; index = open; index = Lexer.BWS(value, index); let token = boolCommonExpr(value, index); if (!token) return; index = Lexer.BWS(value, token.next); let close = Lexer.CLOSE(value, index); if (!close) return; index = close; return Lexer.tokenize(value, start, index, token, Lexer.TokenType.BoolParenExpression); } export function parenExpr(value: Utils.SourceArray, index: number): Lexer.Token { let open = Lexer.OPEN(value, index); if (!open) return; let start = index; index = open; index = Lexer.BWS(value, index); let token = commonExpr(value, index); if (!token) return; index = Lexer.BWS(value, token.next); let close = Lexer.CLOSE(value, index); if (!close) return; index = close; return Lexer.tokenize(value, start, index, token.value, Lexer.TokenType.ParenExpression); } export function boolMethodCallExpr(value: Utils.SourceArray, index: number): Lexer.Token { return endsWithMethodCallExpr(value, index) || startsWithMethodCallExpr(value, index) || containsMethodCallExpr(value, index) || intersectsMethodCallExpr(value, index); } export function methodCallExpr(value: Utils.SourceArray, index: number): Lexer.Token { return indexOfMethodCallExpr(value, index) || toLowerMethodCallExpr(value, index) || toUpperMethodCallExpr(value, index) || trimMethodCallExpr(value, index) || substringMethodCallExpr(value, index) || substringOfMethodCallExpr(value, index) || concatMethodCallExpr(value, index) || lengthMethodCallExpr(value, index) || yearMethodCallExpr(value, index) || monthMethodCallExpr(value, index) || dayMethodCallExpr(value, index) || hourMethodCallExpr(value, index) || minuteMethodCallExpr(value, index) || secondMethodCallExpr(value, index) || fractionalsecondsMethodCallExpr(value, index) || totalsecondsMethodCallExpr(value, index) || dateMethodCallExpr(value, index) || timeMethodCallExpr(value, index) || roundMethodCallExpr(value, index) || floorMethodCallExpr(value, index) || ceilingMethodCallExpr(value, index) || distanceMethodCallExpr(value, index) || geoLengthMethodCallExpr(value, index) || totalOffsetMinutesMethodCallExpr(value, index) || minDateTimeMethodCallExpr(value, index) || maxDateTimeMethodCallExpr(value, index) || nowMethodCallExpr(value, index); } export function methodCallExprFactory(value: Utils.SourceArray, index: number, method: string, min?: number, max?: number): Lexer.Token { if (typeof min === "undefined") min = 0; if (typeof max === "undefined") max = min; if (!Utils.equals(value, index, method)) return; let start = index; index += method.length; let open = Lexer.OPEN(value, index); if (!open) return; index = open; index = Lexer.BWS(value, index); let parameters; if (min > 0) { parameters = []; while (parameters.length < max) { let expr = commonExpr(value, index); if (parameters.length < min && !expr) return; else if (expr) { parameters.push(expr.value); index = expr.next; index = Lexer.BWS(value, index); let comma = Lexer.COMMA(value, index); if (parameters.length < min && !comma) return; if (comma) index = comma; else break; index = Lexer.BWS(value, index); } else break; } } index = Lexer.BWS(value, index); let close = Lexer.CLOSE(value, index); if (!close) return; index = close; return Lexer.tokenize(value, start, index, { method: method, parameters: parameters }, Lexer.TokenType.MethodCallExpression); } export function containsMethodCallExpr(value: Utils.SourceArray, index: number): Lexer.Token { return methodCallExprFactory(value, index, "contains", 2); } export function startsWithMethodCallExpr(value: Utils.SourceArray, index: number): Lexer.Token { return methodCallExprFactory(value, index, "startswith", 2); } export function endsWithMethodCallExpr(value: Utils.SourceArray, index: number): Lexer.Token { return methodCallExprFactory(value, index, "endswith", 2); } export function lengthMethodCallExpr(value: Utils.SourceArray, index: number): Lexer.Token { return methodCallExprFactory(value, index, "length", 1); } export function indexOfMethodCallExpr(value: Utils.SourceArray, index: number): Lexer.Token { return methodCallExprFactory(value, index, "indexof", 2); } export function substringMethodCallExpr(value: Utils.SourceArray, index: number): Lexer.Token { return methodCallExprFactory(value, index, "substring", 2, 3); } export function substringOfMethodCallExpr(value: Utils.SourceArray, index: number): Lexer.Token { return methodCallExprFactory(value, index, "substringof", 2); } export function toLowerMethodCallExpr(value: Utils.SourceArray, index: number): Lexer.Token { return methodCallExprFactory(value, index, "tolower", 1); } export function toUpperMethodCallExpr(value: Utils.SourceArray, index: number): Lexer.Token { return methodCallExprFactory(value, index, "toupper", 1); } export function trimMethodCallExpr(value: Utils.SourceArray, index: number): Lexer.Token { return methodCallExprFactory(value, index, "trim", 1); } export function concatMethodCallExpr(value: Utils.SourceArray, index: number): Lexer.Token { return methodCallExprFactory(value, index, "concat", 2); } export function yearMethodCallExpr(value: Utils.SourceArray, index: number): Lexer.Token { return methodCallExprFactory(value, index, "year", 1); } export function monthMethodCallExpr(value: Utils.SourceArray, index: number): Lexer.Token { return methodCallExprFactory(value, index, "month", 1); } export function dayMethodCallExpr(value: Utils.SourceArray, index: number): Lexer.Token { return methodCallExprFactory(value, index, "day", 1); } export function hourMethodCallExpr(value: Utils.SourceArray, index: number): Lexer.Token { return methodCallExprFactory(value, index, "hour", 1); } export function minuteMethodCallExpr(value: Utils.SourceArray, index: number): Lexer.Token { return methodCallExprFactory(value, index, "minute", 1); } export function secondMethodCallExpr(value: Utils.SourceArray, index: number): Lexer.Token { return methodCallExprFactory(value, index, "second", 1); } export function fractionalsecondsMethodCallExpr(value: Utils.SourceArray, index: number): Lexer.Token { return methodCallExprFactory(value, index, "fractionalseconds", 1); } export function totalsecondsMethodCallExpr(value: Utils.SourceArray, index: number): Lexer.Token { return methodCallExprFactory(value, index, "totalseconds", 1); } export function dateMethodCallExpr(value: Utils.SourceArray, index: number): Lexer.Token { return methodCallExprFactory(value, index, "date", 1); } export function timeMethodCallExpr(value: Utils.SourceArray, index: number): Lexer.Token { return methodCallExprFactory(value, index, "time", 1); } export function totalOffsetMinutesMethodCallExpr(value: Utils.SourceArray, index: number): Lexer.Token { return methodCallExprFactory(value, index, "totaloffsetminutes", 1); } export function minDateTimeMethodCallExpr(value: Utils.SourceArray, index: number): Lexer.Token { return methodCallExprFactory(value, index, "mindatetime", 0); } export function maxDateTimeMethodCallExpr(value: Utils.SourceArray, index: number): Lexer.Token { return methodCallExprFactory(value, index, "maxdatetime", 0); } export function nowMethodCallExpr(value: Utils.SourceArray, index: number): Lexer.Token { return methodCallExprFactory(value, index, "now", 0); } export function roundMethodCallExpr(value: Utils.SourceArray, index: number): Lexer.Token { return methodCallExprFactory(value, index, "round", 1); } export function floorMethodCallExpr(value: Utils.SourceArray, index: number): Lexer.Token { return methodCallExprFactory(value, index, "floor", 1); } export function ceilingMethodCallExpr(value: Utils.SourceArray, index: number): Lexer.Token { return methodCallExprFactory(value, index, "ceiling", 1); } export function distanceMethodCallExpr(value: Utils.SourceArray, index: number): Lexer.Token { return methodCallExprFactory(value, index, "geo.distance", 2); } export function geoLengthMethodCallExpr(value: Utils.SourceArray, index: number): Lexer.Token { return methodCallExprFactory(value, index, "geo.length", 1); } export function intersectsMethodCallExpr(value: Utils.SourceArray, index: number): Lexer.Token { return methodCallExprFactory(value, index, "geo.intersects", 2); } export function isofExpr(value: Utils.SourceArray, index: number): Lexer.Token { if (!Utils.equals(value, index, "isof")) return; let start = index; index += 4; let open = Lexer.OPEN(value, index); if (!open) return; index = open; index = Lexer.BWS(value, index); let expr = commonExpr(value, index); if (expr) { index = expr.next; index = Lexer.BWS(value, index); let comma = Lexer.COMMA(value, index); if (!comma) return; index = comma; index = Lexer.BWS(value, index); } let typeName = NameOrIdentifier.qualifiedTypeName(value, index); if (!typeName) return; index = typeName.next; index = Lexer.BWS(value, index); let close = Lexer.CLOSE(value, index); if (!close) return; index = close; return Lexer.tokenize(value, start, index, { target: expr, typename: typeName }, Lexer.TokenType.IsOfExpression); } export function castExpr(value: Utils.SourceArray, index: number): Lexer.Token { if (!Utils.equals(value, index, "cast")) return; let start = index; index += 4; let open = Lexer.OPEN(value, index); if (!open) return; index = open; index = Lexer.BWS(value, index); let expr = commonExpr(value, index); if (expr) { index = expr.next; index = Lexer.BWS(value, index); let comma = Lexer.COMMA(value, index); if (!comma) return; index = comma; index = Lexer.BWS(value, index); } let typeName = NameOrIdentifier.qualifiedTypeName(value, index); if (!typeName) return; index = typeName.next; index = Lexer.BWS(value, index); let close = Lexer.CLOSE(value, index); if (!close) return; index = close; return Lexer.tokenize(value, start, index, { target: expr, typename: typeName }, Lexer.TokenType.CastExpression); } export function negateExpr(value: Utils.SourceArray, index: number): Lexer.Token { if (value[index] !== 0x2d) return; let start = index; index++; index = Lexer.BWS(value, index); let expr = commonExpr(value, index); if (!expr) return; return Lexer.tokenize(value, start, expr.next, expr, Lexer.TokenType.NegateExpression); } export function firstMemberExpr(value: Utils.SourceArray, index: number): Lexer.Token { let token = inscopeVariableExpr(value, index); let member; let start = index; if (token) { if (value[token.next] === 0x2f) { index = token.next + 1; member = memberExpr(value, index); if (!member) return; return Lexer.tokenize(value, start, member.next, [token, member], Lexer.TokenType.FirstMemberExpression); } } else member = memberExpr(value, index); token = token || member; if (!token) return; return Lexer.tokenize(value, start, token.next, token, Lexer.TokenType.FirstMemberExpression); } export function memberExpr(value: Utils.SourceArray, index: number): Lexer.Token { let start = index; let token = NameOrIdentifier.qualifiedEntityTypeName(value, index); if (token) { if (value[token.next] !== 0x2f) return; index = token.next + 1; } let next = propertyPathExpr(value, index) || boundFunctionExpr(value, index); if (!next) return; return Lexer.tokenize(value, start, next.next, token ? { name: token, value: next } : next, Lexer.TokenType.MemberExpression); } export function propertyPathExpr(value: Utils.SourceArray, index: number): Lexer.Token { let token: any = NameOrIdentifier.odataIdentifier(value, index); let start = index; if (token) { index = token.next; let nav = collectionPathExpr(value, token.next) || collectionNavigationExpr(value, token.next) || singleNavigationExpr(value, token.next) || complexPathExpr(value, token.next) || singlePathExpr(value, token.next); if (nav) { index = nav.next; token = { current: Lexer.clone(token), next: nav }; } }else if (!token) { token = NameOrIdentifier.streamProperty(value, index); if (token) index = token.next; } if (!token) return; return Lexer.tokenize(value, start, index, token, Lexer.TokenType.PropertyPathExpression); } export function inscopeVariableExpr(value: Utils.SourceArray, index: number): Lexer.Token { return implicitVariableExpr(value, index) || (isLambdaPredicate ? lambdaVariableExpr(value, index) : undefined); } export function implicitVariableExpr(value: Utils.SourceArray, index: number): Lexer.Token { if (Utils.equals(value, index, "$it")) return Lexer.tokenize(value, index, index + 3, "$it", Lexer.TokenType.ImplicitVariableExpression); } let isLambdaPredicate = false; let hasLambdaVariableExpr = false; export function lambdaVariableExpr(value: Utils.SourceArray, index: number): Lexer.Token { let token = NameOrIdentifier.odataIdentifier(value, index, Lexer.TokenType.LambdaVariableExpression); if (token) { hasLambdaVariableExpr = true; return token; } } export function lambdaPredicateExpr(value: Utils.SourceArray, index: number): Lexer.Token { isLambdaPredicate = true; let token = boolCommonExpr(value, index); isLambdaPredicate = false; if (token && hasLambdaVariableExpr) { hasLambdaVariableExpr = false; return Lexer.tokenize(value, token.position, token.next, token, Lexer.TokenType.LambdaPredicateExpression); } } export function anyExpr(value: Utils.SourceArray, index: number): Lexer.Token { if (!Utils.equals(value, index, "any")) return; let start = index; index += 3; let open = Lexer.OPEN(value, index); if (!open) return; index = open; index = Lexer.BWS(value, index); let variable = lambdaVariableExpr(value, index); let predicate; if (variable) { index = variable.next; index = Lexer.BWS(value, index); let colon = Lexer.COLON(value, index); if (!colon) return; index = colon; index = Lexer.BWS(value, index); predicate = lambdaPredicateExpr(value, index); if (!predicate) return; index = predicate.next; } index = Lexer.BWS(value, index); let close = Lexer.CLOSE(value, index); if (!close) return; index = close; return Lexer.tokenize(value, start, index, { variable: variable, predicate: predicate }, Lexer.TokenType.AnyExpression); } export function allExpr(value: Utils.SourceArray, index: number): Lexer.Token { if (!Utils.equals(value, index, "all")) return; let start = index; index += 3; let open = Lexer.OPEN(value, index); if (!open) return; index = open; index = Lexer.BWS(value, index); let variable = lambdaVariableExpr(value, index); if (!variable) return; index = variable.next; index = Lexer.BWS(value, index); let colon = Lexer.COLON(value, index); if (!colon) return; index = colon; index = Lexer.BWS(value, index); let predicate = lambdaPredicateExpr(value, index); if (!predicate) return; index = predicate.next; index = Lexer.BWS(value, index); let close = Lexer.CLOSE(value, index); if (!close) return; index = close; return Lexer.tokenize(value, start, index, { variable: variable, predicate: predicate }, Lexer.TokenType.AllExpression); } export function collectionNavigationExpr(value: Utils.SourceArray, index: number): Lexer.Token { let start = index; let entity, predicate, navigation, path; if (value[index] === 0x2f) { index++; entity = NameOrIdentifier.qualifiedEntityTypeName(value, index); if (!entity) return; index = entity.next; } predicate = keyPredicate(value, index); if (predicate) { index = predicate.next; navigation = singleNavigationExpr(value, index); if (navigation) index = navigation.next; } else { path = collectionPathExpr(value, index); if (path) index = path.next; } if (index > start) { return Lexer.tokenize(value, start, index, { entity: entity, predicate: predicate, navigation: navigation, path: path }, Lexer.TokenType.CollectionNavigationExpression); } } export function keyPredicate(value: Utils.SourceArray, index: number, metadataContext?: any): Lexer.Token { return simpleKey(value, index, metadataContext) || compoundKey(value, index); } export function simpleKey(value: Utils.SourceArray, index: number, metadataContext?: any): Lexer.Token { let open = Lexer.OPEN(value, index); if (!open) return; let start = index; index = open; let token = keyPropertyValue(value, index); if (!token) return; let close = Lexer.CLOSE(value, token.next); if (!close) return; let key; if (typeof metadataContext === "object" && metadataContext.key && metadataContext.key.propertyRefs && metadataContext.key.propertyRefs[0] && metadataContext.key.propertyRefs[0].name) { key = metadataContext.key.propertyRefs[0].name; } return Lexer.tokenize(value, start, close, { key: key, value: token }, Lexer.TokenType.SimpleKey); } export function compoundKey(value: Utils.SourceArray, index: number): Lexer.Token { let open = Lexer.OPEN(value, index); if (!open) return; let start = index; index = open; let pair = keyValuePair(value, index); if (!pair) return; let keys = []; while (pair) { keys.push(pair); let comma = Lexer.COMMA(value, pair.next); if (comma) pair = keyValuePair(value, comma); else pair = null; } index = keys[keys.length - 1].next; let close = Lexer.CLOSE(value, index); if (!close) return; index = close; return Lexer.tokenize(value, start, index, keys, Lexer.TokenType.CompoundKey); } export function keyValuePair(value: Utils.SourceArray, index: number): Lexer.Token { let prop = NameOrIdentifier.primitiveKeyProperty(value, index) || keyPropertyAlias(value, index); if (!prop) return; let eq = Lexer.EQ(value, prop.next); if (!eq) return; let val = keyPropertyValue(value, eq); if (val) return Lexer.tokenize(value, index, val.next, { key: prop, value: val }, Lexer.TokenType.KeyValuePair); } export function keyPropertyValue(value: Utils.SourceArray, index: number): Lexer.Token { let token = PrimitiveLiteral.primitiveLiteral(value, index); if (token) { token.type = Lexer.TokenType.KeyPropertyValue; return token; } } export function keyPropertyAlias(value: Utils.SourceArray, index: number): Lexer.Token { return NameOrIdentifier.odataIdentifier(value, index, Lexer.TokenType.KeyPropertyAlias); } export function singleNavigationExpr(value: Utils.SourceArray, index: number): Lexer.Token { if (value[index] !== 0x2f) return; let member = memberExpr(value, index + 1); if (member) return Lexer.tokenize(value, index, member.next, member, Lexer.TokenType.SingleNavigationExpression); } export function collectionPathExpr(value: Utils.SourceArray, index: number): Lexer.Token { let token = countExpr(value, index); if (!token) { if (value[index] === 0x2f) { token = boundFunctionExpr(value, index + 1) || anyExpr(value, index + 1) || allExpr(value, index + 1); } } if (token) return Lexer.tokenize(value, index, token.next, token, Lexer.TokenType.CollectionPathExpression); } export function complexPathExpr(value: Utils.SourceArray, index: number): Lexer.Token { if (value[index] !== 0x2f) return; let start = index; index++; let token = NameOrIdentifier.qualifiedComplexTypeName(value, index); if (token) { if (value[token.next] !== 0x2f) return; index = token.next + 1; } let expr = propertyPathExpr(value, index) || boundFunctionExpr(value, index); if (expr) return Lexer.tokenize(value, start, expr.next, token ? [token, expr] : [expr], Lexer.TokenType.ComplexPathExpression); } export function singlePathExpr(value: Utils.SourceArray, index: number): Lexer.Token { if (value[index] !== 0x2f) return; let boundFunction = boundFunctionExpr(value, index + 1); if (boundFunction) return Lexer.tokenize(value, index, boundFunction.next, boundFunction, Lexer.TokenType.SinglePathExpression); } export function functionExpr(value: Utils.SourceArray, index: number): Lexer.Token { let namespaceNext = NameOrIdentifier.namespace(value, index); if (namespaceNext === index || value[namespaceNext] !== 0x2e) return; let start = index; index = namespaceNext + 1; let token = NameOrIdentifier.odataIdentifier(value, index); if (!token) return; token.position = start; token.value.namespace = Utils.stringify(value, start, namespaceNext); token.raw = Utils.stringify(value, start, token.next); index = token.next; let params = functionExprParameters(value, index); if (!params) return; index = params.next; let expr = collectionPathExpr(value, index) || collectionNavigationExpr(value, index) || singleNavigationExpr(value, index) || complexPathExpr(value, index) || singlePathExpr(value, index); if (expr) index = expr.next; return Lexer.tokenize(value, start, index, { fn: token, params: params, expression: expr }, Lexer.TokenType.FunctionExpression); } export function boundFunctionExpr(value: Utils.SourceArray, index: number): Lexer.Token { return functionExpr(value, index); } export function functionExprParameters(value: Utils.SourceArray, index: number): Lexer.Token { let open = Lexer.OPEN(value, index); if (!open) return; let start = index; index = open; let params = []; let expr = functionExprParameter(value, index); while (expr) { params.push(expr); let comma = Lexer.COMMA(value, expr.next); if (comma) { index = comma; expr = functionExprParameter(value, index); if (!expr) return; } else { index = expr.next; expr = null; } } let close = Lexer.CLOSE(value, index); if (!close) return; index = close; return Lexer.tokenize(value, start, index, params, Lexer.TokenType.FunctionExpressionParameters); } export function functionExprParameter(value: Utils.SourceArray, index: number): Lexer.Token { let name = parameterName(value, index); if (!name) return; let eq = Lexer.EQ(value, name.next); if (!name || !eq) return; let start = index; index = eq; let param = parameterAlias(value, index) || parameterValue(value, index); if (!param) return; return Lexer.tokenize(value, start, param.next, { name: name, value: param }, Lexer.TokenType.FunctionExpressionParameter); } export function parameterName(value: Utils.SourceArray, index: number): Lexer.Token { return NameOrIdentifier.odataIdentifier(value, index, Lexer.TokenType.ParameterName); } export function parameterAlias(value: Utils.SourceArray, index: number): Lexer.Token { let at = Lexer.AT(value, index); if (!at) return; let id = NameOrIdentifier.odataIdentifier(value, at); if (id) return Lexer.tokenize(value, index, id.next, id.value, Lexer.TokenType.ParameterAlias); } export function parameterValue(value: Utils.SourceArray, index: number): Lexer.Token { let token = ArrayOrObject.arrayOrObject(value, index) || commonExpr(value, index); if (token) return Lexer.tokenize(value, index, token.next, token.value, Lexer.TokenType.ParameterValue); } export function countExpr(value: Utils.SourceArray, index: number): Lexer.Token { if (Utils.equals(value, index, "/$count")) return Lexer.tokenize(value, index, index + 7, "/$count", Lexer.TokenType.CountExpression); } export function refExpr(value: Utils.SourceArray, index: number): Lexer.Token { if (Utils.equals(value, index, "/$ref")) return Lexer.tokenize(value, index, index + 5, "/$ref", Lexer.TokenType.RefExpression); } export function valueExpr(value: Utils.SourceArray, index: number): Lexer.Token { if (Utils.equals(value, index, "/$value")) return Lexer.tokenize(value, index, index + 7, "/$value", Lexer.TokenType.ValueExpression); } export function rootExpr(value: Utils.SourceArray, index: number): Lexer.Token { if (!Utils.equals(value, index, "$root/")) return; let start = index; index += 6; let entitySet = NameOrIdentifier.entitySetName(value, index); let predicate, entity, token; if (entitySet) predicate = keyPredicate(value, entitySet.next); if (!(entitySet && predicate)) { entity = NameOrIdentifier.singletonEntity(value, index); if (!entity) return; token = { entity: entity }; }else token = { entitySet: entitySet, keys: predicate }; index = (predicate || entity).next; let nav = singleNavigationExpr(value, index); if (nav) index = nav.next; return Lexer.tokenize(value, start, index, { current: token, next: nav }, Lexer.TokenType.RootExpression); } } export default Expressions;