in src/powerquery-parser/parser/parsers/naive.ts [2871:3001]
function genericReadParameterList<T extends Ast.TParameterType>(
state: ParseState,
parser: Parser,
typeReader: () => T,
): Ast.IParameterList<T> {
const nodeKind: Ast.NodeKind.ParameterList = Ast.NodeKind.ParameterList;
const trace: Trace = state.traceManager.entry(NaiveTraceConstant.Parse, genericReadParameterList.name, {
[NaiveTraceConstant.TokenIndex]: state.tokenIndex,
});
ParseStateUtils.startContext(state, nodeKind);
const leftParenthesisConstant: Ast.IConstant<Constant.WrapperConstant.LeftParenthesis> = readTokenKindAsConstant(
state,
Token.TokenKind.LeftParenthesis,
Constant.WrapperConstant.LeftParenthesis,
);
let continueReadingValues: boolean = !ParseStateUtils.isOnTokenKind(state, Token.TokenKind.RightParenthesis);
let reachedOptionalParameter: boolean = false;
const paramterArrayNodeKind: Ast.NodeKind.ArrayWrapper = Ast.NodeKind.ArrayWrapper;
ParseStateUtils.startContext(state, paramterArrayNodeKind);
const parameters: Ast.ICsv<Ast.IParameter<T>>[] = [];
while (continueReadingValues) {
ParseStateUtils.startContext(state, Ast.NodeKind.Csv);
ParseStateUtils.startContext(state, Ast.NodeKind.Parameter);
const maybeError: ParseError.TInnerParseError | undefined =
testCsvContinuationDanglingCommaForParenthesis(state);
if (maybeError) {
trace.exit({
[NaiveTraceConstant.TokenIndex]: state.tokenIndex,
[TraceConstant.IsThrowing]: true,
});
throw maybeError;
}
const maybeOptionalConstant: Ast.IConstant<Constant.LanguageConstant.Optional> | undefined =
maybeReadConstantKind(state, Constant.LanguageConstant.Optional);
if (reachedOptionalParameter && !maybeOptionalConstant) {
const token: Token.Token = ParseStateUtils.assertGetTokenAt(state, state.tokenIndex);
trace.exit({
[NaiveTraceConstant.TokenIndex]: state.tokenIndex,
[TraceConstant.IsThrowing]: true,
});
throw new ParseError.RequiredParameterAfterOptionalParameterError(
state.locale,
token,
state.lexerSnapshot.graphemePositionStartFrom(token),
);
} else if (maybeOptionalConstant) {
reachedOptionalParameter = true;
}
const name: Ast.Identifier = parser.readIdentifier(state, parser);
const maybeParameterType: T = typeReader();
const parameter: Ast.IParameter<T> = {
...ParseStateUtils.assertGetContextNodeMetadata(state),
kind: Ast.NodeKind.Parameter,
isLeaf: false,
maybeOptionalConstant,
name,
maybeParameterType,
};
ParseStateUtils.endContext(state, parameter);
const maybeCommaConstant: Ast.IConstant<Constant.MiscConstant.Comma> | undefined = maybeReadTokenKindAsConstant(
state,
Token.TokenKind.Comma,
Constant.MiscConstant.Comma,
);
continueReadingValues = maybeCommaConstant !== undefined;
const csv: Ast.ICsv<Ast.IParameter<T>> = {
...ParseStateUtils.assertGetContextNodeMetadata(state),
kind: Ast.NodeKind.Csv,
isLeaf: false,
node: parameter,
maybeCommaConstant,
};
ParseStateUtils.endContext(state, csv);
parameters.push(csv);
}
const parameterArray: Ast.ICsvArray<Ast.IParameter<T>> = {
...ParseStateUtils.assertGetContextNodeMetadata(state),
kind: paramterArrayNodeKind,
elements: parameters,
isLeaf: false,
};
ParseStateUtils.endContext(state, parameterArray);
const rightParenthesisConstant: Ast.IConstant<Constant.WrapperConstant.RightParenthesis> = readTokenKindAsConstant(
state,
Token.TokenKind.RightParenthesis,
Constant.WrapperConstant.RightParenthesis,
);
const parameterList: Ast.IParameterList<T> = {
...ParseStateUtils.assertGetContextNodeMetadata(state),
kind: nodeKind,
isLeaf: false,
openWrapperConstant: leftParenthesisConstant,
content: parameterArray,
closeWrapperConstant: rightParenthesisConstant,
};
ParseStateUtils.endContext(state, parameterList);
trace.exit({
[NaiveTraceConstant.TokenIndex]: state.tokenIndex,
[TraceConstant.IsThrowing]: false,
});
return parameterList;
}