in src/powerquery-parser/parser/parsers/naive.ts [1767:1920]
export function readFieldSpecificationList(
state: ParseState,
parser: Parser,
allowOpenMarker: boolean,
testPostCommaError: (state: ParseState) => ParseError.TInnerParseError | undefined,
): Ast.FieldSpecificationList {
const nodeKind: Ast.NodeKind.FieldSpecificationList = Ast.NodeKind.FieldSpecificationList;
const trace: Trace = state.traceManager.entry(NaiveTraceConstant.Parse, readFieldSpecificationList.name, {
[NaiveTraceConstant.TokenIndex]: state.tokenIndex,
});
state.maybeCancellationToken?.throwIfCancelled();
ParseStateUtils.startContext(state, nodeKind);
const leftBracketConstant: Ast.IConstant<Constant.WrapperConstant.LeftBracket> = readTokenKindAsConstant(
state,
Token.TokenKind.LeftBracket,
Constant.WrapperConstant.LeftBracket,
);
const fields: Ast.ICsv<Ast.FieldSpecification>[] = [];
let continueReadingValues: boolean = true;
let isOnOpenRecordMarker: boolean = false;
const fieldArrayNodeKind: Ast.NodeKind.ArrayWrapper = Ast.NodeKind.ArrayWrapper;
ParseStateUtils.startContext(state, fieldArrayNodeKind);
while (continueReadingValues) {
const maybeError: ParseError.TInnerParseError | undefined = testPostCommaError(state);
if (maybeError) {
trace.exit({
[NaiveTraceConstant.TokenIndex]: state.tokenIndex,
[TraceConstant.IsThrowing]: true,
});
throw maybeError;
}
if (ParseStateUtils.isOnTokenKind(state, Token.TokenKind.Ellipsis)) {
if (allowOpenMarker) {
if (isOnOpenRecordMarker) {
trace.exit({
[NaiveTraceConstant.TokenIndex]: state.tokenIndex,
[TraceConstant.IsThrowing]: true,
});
throw fieldSpecificationListReadError(state, false);
} else {
isOnOpenRecordMarker = true;
continueReadingValues = false;
}
} else {
trace.exit({
[NaiveTraceConstant.TokenIndex]: state.tokenIndex,
[TraceConstant.IsThrowing]: true,
});
throw fieldSpecificationListReadError(state, allowOpenMarker);
}
} else if (ParseStateUtils.isOnGeneralizedIdentifierStart(state)) {
const csvNodeKind: Ast.NodeKind.Csv = Ast.NodeKind.Csv;
ParseStateUtils.startContext(state, csvNodeKind);
const fieldSpecificationNodeKind: Ast.NodeKind.FieldSpecification = Ast.NodeKind.FieldSpecification;
ParseStateUtils.startContext(state, fieldSpecificationNodeKind);
const maybeOptionalConstant: Ast.IConstant<Constant.LanguageConstant.Optional> | undefined =
maybeReadConstantKind(state, Constant.LanguageConstant.Optional);
const name: Ast.GeneralizedIdentifier = parser.readGeneralizedIdentifier(state, parser);
const maybeFieldTypeSpecification: Ast.FieldTypeSpecification | undefined = maybeReadFieldTypeSpecification(
state,
parser,
);
const field: Ast.FieldSpecification = {
...ParseStateUtils.assertGetContextNodeMetadata(state),
kind: fieldSpecificationNodeKind,
isLeaf: false,
maybeOptionalConstant,
name,
maybeFieldTypeSpecification,
};
ParseStateUtils.endContext(state, field);
const maybeCommaConstant: Ast.IConstant<Constant.MiscConstant.Comma> | undefined =
maybeReadTokenKindAsConstant(state, Token.TokenKind.Comma, Constant.MiscConstant.Comma);
continueReadingValues = maybeCommaConstant !== undefined;
const csv: Ast.ICsv<Ast.FieldSpecification> = {
...ParseStateUtils.assertGetContextNodeMetadata(state),
kind: csvNodeKind,
isLeaf: false,
node: field,
maybeCommaConstant,
};
ParseStateUtils.endContext(state, csv);
fields.push(csv);
} else {
trace.exit({
[NaiveTraceConstant.TokenIndex]: state.tokenIndex,
[TraceConstant.IsThrowing]: true,
});
throw fieldSpecificationListReadError(state, allowOpenMarker);
}
}
const fieldArray: Ast.ICsvArray<Ast.FieldSpecification> = {
...ParseStateUtils.assertGetContextNodeMetadata(state),
kind: fieldArrayNodeKind,
elements: fields,
isLeaf: false,
};
ParseStateUtils.endContext(state, fieldArray);
let maybeOpenRecordMarkerConstant: Ast.IConstant<Constant.MiscConstant.Ellipsis> | undefined = undefined;
if (isOnOpenRecordMarker) {
maybeOpenRecordMarkerConstant = readTokenKindAsConstant(
state,
Token.TokenKind.Ellipsis,
Constant.MiscConstant.Ellipsis,
);
}
const rightBracketConstant: Ast.IConstant<Constant.WrapperConstant.RightBracket> = readTokenKindAsConstant(
state,
Token.TokenKind.RightBracket,
Constant.WrapperConstant.RightBracket,
);
const fieldSpecificationList: Ast.FieldSpecificationList = {
...ParseStateUtils.assertGetContextNodeMetadata(state),
kind: nodeKind,
isLeaf: false,
openWrapperConstant: leftBracketConstant,
content: fieldArray,
maybeOpenRecordMarkerConstant,
closeWrapperConstant: rightBracketConstant,
};
ParseStateUtils.endContext(state, fieldSpecificationList);
trace.exit({ [NaiveTraceConstant.TokenIndex]: state.tokenIndex });
return fieldSpecificationList;
}