trader-server
Version:
OData server for testing strategies, simulating and real trading.
810 lines (714 loc) • 36.3 kB
text/typescript
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;