in src/language/expressions/TLE.ts [1086:1216]
private static parseFunctionCall(tokenizer: Tokenizer, errors: Issue[]): FunctionCallValue {
assert(tokenizer);
assert(tokenizer.current, "tokenizer must have a current token.");
// tslint:disable-next-line:no-non-null-assertion // Asserted
assert.deepEqual(TokenType.Literal, tokenizer.current!.getType(), "tokenizer's current token must be a literal.");
assert(errors);
let namespaceToken: Token | undefined;
let nameToken: Token | undefined;
let periodToken: Token | undefined;
// tslint:disable-next-line:no-non-null-assertion // Asserted
let firstToken: Token = tokenizer.current!;
tokenizer.next();
// Check for <namespace>.<functionname>
// tslint:disable-next-line: strict-boolean-expressions
if (tokenizer.current && tokenizer.current.getType() === TokenType.Period) {
// It's a user-defined function because it has a namespace before the function name
periodToken = tokenizer.current;
namespaceToken = firstToken;
tokenizer.next();
// Get the function name following the period
if (tokenizer.hasCurrent() && tokenizer.current.getType() === TokenType.Literal) {
nameToken = tokenizer.current;
tokenizer.next();
} else {
errors.push(new Issue(periodToken.span, "Expected user-defined function name.", IssueKind.tleSyntax));
}
} else {
nameToken = firstToken;
}
let leftParenthesisToken: Token | undefined;
let rightParenthesisToken: Token | undefined;
let commaTokens: Token[] = [];
let argumentExpressions: (Value | undefined)[] = [];
// tslint:disable-next-line: strict-boolean-expressions
if (tokenizer.current) {
// tslint:disable-next-line: strict-boolean-expressions // False positive
while (tokenizer.current) {
if (tokenizer.current.getType() === TokenType.LeftParenthesis) {
leftParenthesisToken = tokenizer.current;
tokenizer.next();
break;
} else if (tokenizer.current.getType() === TokenType.RightSquareBracket) {
// tslint:disable-next-line: strict-boolean-expressions
errors.push(new Issue(getFullNameSpan(), "Missing function argument list.", IssueKind.tleSyntax));
break;
} else {
errors.push(new Issue(tokenizer.current.span, "Expected the end of the string.", IssueKind.tleSyntax));
tokenizer.next();
}
}
} else {
errors.push(new Issue(getFullNameSpan(), "Missing function argument list.", IssueKind.tleSyntax));
}
if (tokenizer.hasCurrent()) {
let expectingArgument: boolean = true;
// tslint:disable-next-line: strict-boolean-expressions
while (tokenizer.current) {
if (tokenizer.current.getType() === TokenType.RightParenthesis || tokenizer.current.getType() === TokenType.RightSquareBracket) {
break;
} else if (expectingArgument) {
let expression = Parser.parseExpression(tokenizer, errors);
if (!expression && tokenizer.hasCurrent() && tokenizer.current.getType() === TokenType.Comma) {
errors.push(new Issue(tokenizer.current.span, "Expected a constant string, function, or property expression.", IssueKind.tleSyntax));
}
argumentExpressions.push(expression);
expectingArgument = false;
} else if (tokenizer.current.getType() === TokenType.Comma) {
expectingArgument = true;
commaTokens.push(tokenizer.current);
tokenizer.next();
} else {
errors.push(new Issue(tokenizer.current.span, "Expected a comma (',').", IssueKind.tleSyntax));
tokenizer.next();
}
}
if (Parser.isMissingArgument(expectingArgument, leftParenthesisToken, argumentExpressions.length, tokenizer)) {
argumentExpressions.push(undefined);
let errorSpan: Span;
// tslint:disable-next-line: strict-boolean-expressions
if (tokenizer.current) {
errorSpan = tokenizer.current.span;
} else {
assert(0 < commaTokens.length);
errorSpan = commaTokens[commaTokens.length - 1].span;
}
errors.push(new Issue(errorSpan, "Expected a constant string, function, or property expression.", IssueKind.tleSyntax));
}
} else if (!!leftParenthesisToken) {
errors.push(new Issue(leftParenthesisToken.span, "Expected a right parenthesis (')').", IssueKind.tleSyntax));
}
// tslint:disable-next-line: strict-boolean-expressions
if (tokenizer.current) {
switch (tokenizer.current.getType()) {
case TokenType.RightParenthesis:
rightParenthesisToken = tokenizer.current;
tokenizer.next();
break;
case TokenType.RightSquareBracket:
if (!!leftParenthesisToken) {
errors.push(new Issue(tokenizer.current.span, "Expected a right parenthesis (')').", IssueKind.tleSyntax));
}
break;
}
}
assert(namespaceToken || nameToken, "Should have had a namespace or a name");
return new FunctionCallValue(namespaceToken, periodToken, nameToken, leftParenthesisToken, commaTokens, argumentExpressions, rightParenthesisToken);
function getFullNameSpan(): Span {
if (!nameToken) {
assert(namespaceToken);
// tslint:disable-next-line: no-non-null-assertion
return namespaceToken!.span;
} else {
// tslint:disable-next-line: strict-boolean-expressions
return nameToken.span.union(namespaceToken && namespaceToken.span);
}
}
}