in src/language/expressions/TLE.ts [995:1083]
private static parseExpression(tokenizer: Tokenizer, errors: Issue[]): Value | undefined {
let expression: Value;
if (tokenizer.current) {
let rootExpression: Value | undefined; // Initial expression
let token = tokenizer.current;
let tokenType = token.getType();
if (tokenType === TokenType.Literal) {
rootExpression = Parser.parseFunctionCall(tokenizer, errors);
} else if (tokenType === TokenType.QuotedString) {
if (!token.stringValue.endsWith(token.stringValue[0])) {
errors.push(new Issue(token.span, "A constant string is missing an end quote.", IssueKind.tleSyntax));
}
rootExpression = new StringValue(token);
tokenizer.next();
} else if (tokenType === TokenType.Number) {
rootExpression = new NumberValue(token);
tokenizer.next();
} else if (tokenType !== TokenType.RightSquareBracket && tokenType !== TokenType.Comma) {
errors.push(new Issue(token.span, "Template language expressions must start with a function.", IssueKind.tleSyntax));
tokenizer.next();
}
if (!rootExpression) {
return undefined;
}
expression = rootExpression;
} else {
return undefined;
}
// Check for property or array accesses off of the root expression
while (<Token | undefined>tokenizer.current) {
if (tokenizer.current.getType() === TokenType.Period) {
let periodToken = tokenizer.current;
tokenizer.next();
let propertyNameToken: Token | undefined;
let errorSpan: Span | undefined;
if (<Token | undefined>tokenizer.current) {
if (tokenizer.current.getType() === TokenType.Literal) {
propertyNameToken = tokenizer.current;
tokenizer.next();
} else {
errorSpan = tokenizer.current.span;
let tokenType = tokenizer.current.getType();
if (tokenType !== TokenType.RightParenthesis
&& tokenType !== TokenType.RightSquareBracket
&& tokenType !== TokenType.Comma
) {
tokenizer.next();
}
}
} else {
errorSpan = periodToken.span;
}
if (!propertyNameToken) {
assert(errorSpan);
// tslint:disable-next-line: no-non-null-assertion // Asserted
errors.push(new Issue(errorSpan!, "Expected a literal value.", IssueKind.tleSyntax));
}
// We go ahead and create a property access expression whether the property name
// was correctly given or not, so we can have proper intellisense/etc.
expression = new PropertyAccess(expression, periodToken, propertyNameToken);
} else if (tokenizer.current.getType() === TokenType.LeftSquareBracket) {
let leftSquareBracketToken: Token = tokenizer.current;
tokenizer.next();
let indexValue: Value | undefined = Parser.parseExpression(tokenizer, errors);
let rightSquareBracketToken: Token | undefined;
if (<Token | undefined>tokenizer.current && tokenizer.current.getType() === TokenType.RightSquareBracket) {
rightSquareBracketToken = tokenizer.current;
tokenizer.next();
}
expression = new ArrayAccessValue(expression, leftSquareBracketToken, indexValue, rightSquareBracketToken);
} else {
break;
}
}
return expression;
}