@rightcapital/phpdoc-parser
Version:
TypeScript version of PHPDoc parser with support for intersection types and generics
578 lines (577 loc) • 29.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TypeParser = void 0;
const const_expr_array_node_1 = require("../ast/const-expr/const-expr-array-node");
const const_expr_integer_node_1 = require("../ast/const-expr/const-expr-integer-node");
const const_expr_string_node_1 = require("../ast/const-expr/const-expr-string-node");
const quote_aware_const_expr_string_node_1 = require("../ast/const-expr/quote-aware-const-expr-string-node");
const array_shape_item_node_1 = require("../ast/type/array-shape-item-node");
const array_shape_node_1 = require("../ast/type/array-shape-node");
const array_type_node_1 = require("../ast/type/array-type-node");
const callable_type_node_1 = require("../ast/type/callable-type-node");
const callable_type_parameter_node_1 = require("../ast/type/callable-type-parameter-node");
const conditional_type_for_parameter_node_1 = require("../ast/type/conditional-type-for-parameter-node");
const conditional_type_node_1 = require("../ast/type/conditional-type-node");
const const_type_node_1 = require("../ast/type/const-type-node");
const generic_type_node_1 = require("../ast/type/generic-type-node");
const identifier_type_node_1 = require("../ast/type/identifier-type-node");
const intersection_type_node_1 = require("../ast/type/intersection-type-node");
const nullable_type_node_1 = require("../ast/type/nullable-type-node");
const object_shape_item_node_1 = require("../ast/type/object-shape-item-node");
const object_shape_node_1 = require("../ast/type/object-shape-node");
const offset_access_type_node_1 = require("../ast/type/offset-access-type-node");
const this_type_node_1 = require("../ast/type/this-type-node");
const union_type_node_1 = require("../ast/type/union-type-node");
const types_1 = require("../ast/types");
const lexer_1 = require("../lexer/lexer");
const parser_exception_1 = require("./parser-exception");
const string_unescaper_1 = require("./string-unescaper");
class TypeParser {
constructor(constExprParser = null, quoteAwareConstExprString = false, usedAttributes = {}) {
var _a, _b;
this.constExprParser = constExprParser;
this.quoteAwareConstExprString = quoteAwareConstExprString;
this.useLinesAttributes = (_a = usedAttributes.lines) !== null && _a !== void 0 ? _a : false;
this.useIndexAttributes = (_b = usedAttributes.indexes) !== null && _b !== void 0 ? _b : false;
}
parse(tokens) {
const startLine = tokens.currentTokenLine();
const startIndex = tokens.currentTokenIndex();
if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_NULLABLE)) {
return this.parseNullable(tokens);
}
let type = this.parseAtomic(tokens);
if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_UNION)) {
type = this.parseUnion(tokens, type);
}
else if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_INTERSECTION)) {
type = this.parseIntersection(tokens, type);
}
else if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_OPEN_SQUARE_BRACKET)) {
type = this.tryParseArrayOrOffsetAccess(tokens, type);
}
return this.enrichWithAttributes(tokens, type, startLine, startIndex);
}
enrichWithAttributes(tokens, type, startLine, startIndex) {
if (this.useLinesAttributes) {
type.setAttribute(types_1.Attribute.START_LINE, startLine);
type.setAttribute(types_1.Attribute.END_LINE, tokens.currentTokenLine());
}
if (this.useIndexAttributes) {
type.setAttribute(types_1.Attribute.START_INDEX, startIndex);
type.setAttribute(types_1.Attribute.END_INDEX, tokens.endIndexOfLastRelevantToken());
}
return type;
}
subParse(tokens) {
const startLine = tokens.currentTokenLine();
const startIndex = tokens.currentTokenIndex();
let type;
if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_NULLABLE)) {
type = this.parseNullable(tokens);
}
else {
type = this.parseAtomic(tokens);
if (tokens.isCurrentTokenValue('is')) {
type = this.parseConditional(tokens, type);
}
else {
tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL);
if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_UNION)) {
type = this.subParseUnion(tokens, type);
}
else if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_INTERSECTION)) {
type = this.subParseIntersection(tokens, type);
}
}
}
return this.enrichWithAttributes(tokens, type, startLine, startIndex);
}
parseAtomic(tokens) {
const startLine = tokens.currentTokenLine();
const startIndex = tokens.currentTokenIndex();
let type;
if (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_OPEN_PARENTHESES)) {
tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL);
type = this.subParse(tokens);
tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL);
tokens.consumeTokenType(lexer_1.Lexer.TOKEN_CLOSE_PARENTHESES);
if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_OPEN_SQUARE_BRACKET)) {
type = this.tryParseArrayOrOffsetAccess(tokens, type);
}
return this.enrichWithAttributes(tokens, type, startLine, startIndex);
}
if (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_THIS_VARIABLE)) {
type = new this_type_node_1.ThisTypeNode();
if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_OPEN_SQUARE_BRACKET)) {
type = this.tryParseArrayOrOffsetAccess(tokens, this.enrichWithAttributes(tokens, type, startLine, startIndex));
}
return this.enrichWithAttributes(tokens, type, startLine, startIndex);
}
const currentTokenValue = tokens.currentTokenValue();
tokens.pushSavePoint();
if (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_IDENTIFIER)) {
const identifierTypeNode = new identifier_type_node_1.IdentifierTypeNode(currentTokenValue);
type = identifierTypeNode;
if (!tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_DOUBLE_COLON)) {
if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_OPEN_ANGLE_BRACKET)) {
type = this.parseGeneric(tokens, identifierTypeNode);
}
else if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_OPEN_SQUARE_BRACKET)) {
type = this.tryParseArrayOrOffsetAccess(tokens, type);
}
else if (['array', 'list', 'object'].includes(identifierTypeNode.name) &&
tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_OPEN_CURLY_BRACKET) &&
!tokens.isPrecededByHorizontalWhitespace()) {
if (identifierTypeNode.name === 'object') {
type = this.parseObjectShape(tokens);
}
else {
type = this.parseArrayShape(tokens, type, identifierTypeNode.name);
}
if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_OPEN_SQUARE_BRACKET)) {
type = this.tryParseArrayOrOffsetAccess(tokens, type);
}
}
return this.enrichWithAttributes(tokens, type, startLine, startIndex);
}
tokens.rollback();
}
else {
tokens.dropSavePoint();
}
const exception = new parser_exception_1.ParserException(tokens.currentTokenValue(), tokens.currentTokenType(), tokens.currentTokenOffset(), lexer_1.Lexer.TOKEN_IDENTIFIER, null, tokens.currentTokenLine());
if (this.constExprParser === null) {
throw exception;
}
try {
const constExpr = this.constExprParser.parse(tokens, true);
if (constExpr instanceof const_expr_array_node_1.ConstExprArrayNode) {
throw exception;
}
return this.enrichWithAttributes(tokens, new const_type_node_1.ConstTypeNode(constExpr), startLine, startIndex);
}
catch (error) {
exception.cause = error;
throw exception;
}
}
parseUnion(tokens, type) {
const types = [type];
while (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_UNION)) {
types.push(this.parseAtomic(tokens));
}
return new union_type_node_1.UnionTypeNode(types);
}
subParseUnion(tokens, type) {
const types = [type];
while (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_UNION)) {
tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL);
types.push(this.parseAtomic(tokens));
tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL);
}
return new union_type_node_1.UnionTypeNode(types);
}
parseIntersection(tokens, type) {
const types = [type];
while (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_INTERSECTION)) {
types.push(this.parseAtomic(tokens));
}
return new intersection_type_node_1.IntersectionTypeNode(types);
}
subParseIntersection(tokens, type) {
const types = [type];
while (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_INTERSECTION)) {
tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL);
types.push(this.parseAtomic(tokens));
tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL);
}
return new intersection_type_node_1.IntersectionTypeNode(types);
}
parseConditional(tokens, subjectType) {
tokens.consumeTokenType(lexer_1.Lexer.TOKEN_IDENTIFIER);
let negated = false;
if (tokens.isCurrentTokenValue('not')) {
negated = true;
tokens.consumeTokenType(lexer_1.Lexer.TOKEN_IDENTIFIER);
}
const targetType = this.parse(tokens);
tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL);
tokens.consumeTokenType(lexer_1.Lexer.TOKEN_NULLABLE);
tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL);
const ifType = this.parse(tokens);
tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL);
tokens.consumeTokenType(lexer_1.Lexer.TOKEN_COLON);
tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL);
const elseType = this.subParse(tokens);
return new conditional_type_node_1.ConditionalTypeNode(subjectType, targetType, ifType, elseType, negated);
}
parseConditionalForParameter(tokens, parameterName) {
tokens.consumeTokenType(lexer_1.Lexer.TOKEN_VARIABLE);
tokens.consumeTokenValue(lexer_1.Lexer.TOKEN_IDENTIFIER, 'is');
let negated = false;
if (tokens.isCurrentTokenValue('not')) {
negated = true;
tokens.consumeTokenType(lexer_1.Lexer.TOKEN_IDENTIFIER);
}
const targetType = this.parse(tokens);
tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL);
tokens.consumeTokenType(lexer_1.Lexer.TOKEN_NULLABLE);
tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL);
const ifType = this.parse(tokens);
tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL);
tokens.consumeTokenType(lexer_1.Lexer.TOKEN_COLON);
tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL);
const elseType = this.subParse(tokens);
return new conditional_type_for_parameter_node_1.ConditionalTypeForParameterNode(parameterName, targetType, ifType, elseType, negated);
}
parseNullable(tokens) {
tokens.consumeTokenType(lexer_1.Lexer.TOKEN_NULLABLE);
const type = this.parseAtomic(tokens);
return new nullable_type_node_1.NullableTypeNode(type);
}
isHtml(tokens) {
tokens.consumeTokenType(lexer_1.Lexer.TOKEN_OPEN_ANGLE_BRACKET);
if (!tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_IDENTIFIER)) {
return false;
}
const htmlTagName = tokens.currentTokenValue();
tokens.next();
if (!tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_CLOSE_ANGLE_BRACKET)) {
return false;
}
while (!tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_END)) {
if (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_OPEN_ANGLE_BRACKET) &&
tokens.currentTokenValue().includes(`/${htmlTagName}>`)) {
return true;
}
tokens.next();
}
return false;
}
parseGeneric(tokens, baseType) {
tokens.consumeTokenType(lexer_1.Lexer.TOKEN_OPEN_ANGLE_BRACKET);
tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL);
const genericTypes = [];
const variances = [];
const [genericType, variance] = this.parseGenericTypeArgument(tokens);
genericTypes.push(genericType);
variances.push(variance);
tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL);
while (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_COMMA)) {
tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL);
if (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_CLOSE_ANGLE_BRACKET)) {
break;
}
const [genericTypeToAddInWhileLoop, varianceToAddInWhileLoop] = this.parseGenericTypeArgument(tokens);
genericTypes.push(genericTypeToAddInWhileLoop);
variances.push(varianceToAddInWhileLoop);
tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL);
}
tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL);
tokens.consumeTokenType(lexer_1.Lexer.TOKEN_CLOSE_ANGLE_BRACKET);
const type = new generic_type_node_1.GenericTypeNode(baseType, genericTypes, variances);
const startLine = baseType.getAttribute(types_1.Attribute.START_LINE);
const startIndex = baseType.getAttribute(types_1.Attribute.START_INDEX);
if (startLine !== null && startIndex !== null) {
return this.enrichWithAttributes(tokens, type, baseType.getAttribute(types_1.Attribute.START_LINE), baseType.getAttribute(types_1.Attribute.START_INDEX));
}
return type;
}
parseGenericTypeArgument(tokens) {
const startLine = tokens.currentTokenLine();
const startIndex = tokens.currentTokenIndex();
if (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_WILDCARD)) {
return [
this.enrichWithAttributes(tokens, new identifier_type_node_1.IdentifierTypeNode('mixed'), startLine, startIndex),
generic_type_node_1.GenericTypeNode.VARIANCE_BIVARIANT,
];
}
let variance;
if (tokens.tryConsumeTokenValue('contravariant')) {
variance = generic_type_node_1.GenericTypeNode.VARIANCE_CONTRAVARIANT;
}
else if (tokens.tryConsumeTokenValue('covariant')) {
variance = generic_type_node_1.GenericTypeNode.VARIANCE_COVARIANT;
}
else {
variance = generic_type_node_1.GenericTypeNode.VARIANCE_INVARIANT;
}
const type = this.parse(tokens);
return [type, variance];
}
parseCallable(tokens, identifier) {
tokens.consumeTokenType(lexer_1.Lexer.TOKEN_OPEN_PARENTHESES);
tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL);
const parameters = [];
if (!tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_CLOSE_PARENTHESES)) {
parameters.push(this.parseCallableParameter(tokens));
tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL);
while (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_COMMA)) {
tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL);
if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_CLOSE_PARENTHESES)) {
break;
}
parameters.push(this.parseCallableParameter(tokens));
tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL);
}
}
tokens.consumeTokenType(lexer_1.Lexer.TOKEN_CLOSE_PARENTHESES);
tokens.consumeTokenType(lexer_1.Lexer.TOKEN_COLON);
const returnType = this.parseCallableReturnType(tokens);
return new callable_type_node_1.CallableTypeNode(identifier, parameters, returnType);
}
parseCallableParameter(tokens) {
const startLine = tokens.currentTokenLine();
const startIndex = tokens.currentTokenIndex();
const type = this.parse(tokens);
const isReference = tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_REFERENCE);
const isVariadic = tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_VARIADIC);
let parameterName = '';
if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_VARIABLE)) {
parameterName = tokens.currentTokenValue();
tokens.consumeTokenType(lexer_1.Lexer.TOKEN_VARIABLE);
}
const isOptional = tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_EQUAL);
return this.enrichWithAttributes(tokens, new callable_type_parameter_node_1.CallableTypeParameterNode(type, isReference, isVariadic, parameterName, isOptional), startLine, startIndex);
}
parseCallableReturnType(tokens) {
const startLine = tokens.currentTokenLine();
const startIndex = tokens.currentTokenIndex();
let type;
if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_NULLABLE)) {
return this.parseNullable(tokens);
}
if (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_OPEN_PARENTHESES)) {
type = this.parse(tokens);
tokens.consumeTokenType(lexer_1.Lexer.TOKEN_CLOSE_PARENTHESES);
if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_OPEN_SQUARE_BRACKET)) {
type = this.tryParseArrayOrOffsetAccess(tokens, type);
}
return type;
}
if (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_THIS_VARIABLE)) {
type = new this_type_node_1.ThisTypeNode();
if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_OPEN_SQUARE_BRACKET)) {
type = this.tryParseArrayOrOffsetAccess(tokens, this.enrichWithAttributes(tokens, type, startLine, startIndex));
}
return type;
}
const currentTokenValue = tokens.currentTokenValue();
tokens.pushSavePoint();
if (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_IDENTIFIER)) {
type = new identifier_type_node_1.IdentifierTypeNode(currentTokenValue);
if (!tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_DOUBLE_COLON)) {
if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_OPEN_ANGLE_BRACKET)) {
type = this.parseGeneric(tokens, this.enrichWithAttributes(tokens, type, startLine, startIndex));
}
else if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_OPEN_SQUARE_BRACKET)) {
type = this.tryParseArrayOrOffsetAccess(tokens, this.enrichWithAttributes(tokens, type, startLine, startIndex));
}
}
else {
tokens.rollback();
}
return type;
}
tokens.dropSavePoint();
const exception = new parser_exception_1.ParserException(tokens.currentTokenValue(), tokens.currentTokenType(), tokens.currentTokenOffset(), lexer_1.Lexer.TOKEN_IDENTIFIER, null, tokens.currentTokenLine());
if (this.constExprParser === null) {
throw exception;
}
if (this.constExprParser === null) {
throw exception;
}
try {
const constExpr = this.constExprParser.parse(tokens, true);
if (constExpr instanceof const_expr_array_node_1.ConstExprArrayNode) {
throw exception;
}
type = new const_type_node_1.ConstTypeNode(constExpr);
if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_OPEN_SQUARE_BRACKET)) {
type = this.tryParseArrayOrOffsetAccess(tokens, this.enrichWithAttributes(tokens, type, startLine, startIndex));
}
return type;
}
catch (e) {
if (e instanceof Error) {
throw exception;
}
else {
throw e;
}
}
}
tryParseCallable(tokens, identifier) {
try {
tokens.pushSavePoint();
const type = this.parseCallable(tokens, identifier);
tokens.dropSavePoint();
return type;
}
catch (e) {
if (e instanceof parser_exception_1.ParserException) {
tokens.rollback();
return identifier;
}
throw e;
}
}
tryParseArrayOrOffsetAccess(tokens, type) {
try {
while (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_OPEN_SQUARE_BRACKET)) {
tokens.pushSavePoint();
const canBeOffsetAccessType = !tokens.isPrecededByHorizontalWhitespace();
tokens.consumeTokenType(lexer_1.Lexer.TOKEN_OPEN_SQUARE_BRACKET);
if (canBeOffsetAccessType &&
!tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_CLOSE_SQUARE_BRACKET)) {
const offset = this.parse(tokens);
tokens.consumeTokenType(lexer_1.Lexer.TOKEN_CLOSE_SQUARE_BRACKET);
tokens.dropSavePoint();
type = new offset_access_type_node_1.OffsetAccessTypeNode(type, offset);
}
else {
tokens.consumeTokenType(lexer_1.Lexer.TOKEN_CLOSE_SQUARE_BRACKET);
tokens.dropSavePoint();
type = new array_type_node_1.ArrayTypeNode(type);
}
}
}
catch (e) {
if (e instanceof parser_exception_1.ParserException) {
tokens.rollback();
}
else {
throw e;
}
}
return type;
}
parseArrayShape(tokens, type, kind) {
tokens.consumeTokenType(lexer_1.Lexer.TOKEN_OPEN_CURLY_BRACKET);
const items = [];
let sealed = true;
do {
tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL);
if (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_CLOSE_CURLY_BRACKET)) {
return new array_shape_node_1.ArrayShapeNode(items, true, kind);
}
if (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_VARIADIC)) {
sealed = false;
tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_COMMA);
break;
}
items.push(this.parseArrayShapeItem(tokens));
tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL);
} while (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_COMMA));
tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL);
tokens.consumeTokenType(lexer_1.Lexer.TOKEN_CLOSE_CURLY_BRACKET);
return new array_shape_node_1.ArrayShapeNode(items, sealed, kind);
}
parseArrayShapeItem(tokens) {
const startLine = tokens.currentTokenLine();
const startIndex = tokens.currentTokenIndex();
try {
tokens.pushSavePoint();
const key = this.parseArrayShapeKey(tokens);
const optional = tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_NULLABLE);
tokens.consumeTokenType(lexer_1.Lexer.TOKEN_COLON);
const value = this.parse(tokens);
tokens.dropSavePoint();
return this.enrichWithAttributes(tokens, new array_shape_item_node_1.ArrayShapeItemNode(key, optional, value), startLine, startIndex);
}
catch (e) {
if (e instanceof parser_exception_1.ParserException) {
tokens.rollback();
const value = this.parse(tokens);
return this.enrichWithAttributes(tokens, new array_shape_item_node_1.ArrayShapeItemNode(null, false, value), startLine, startIndex);
}
throw e;
}
}
parseArrayShapeKey(tokens) {
const startLine = tokens.currentTokenLine();
const startIndex = tokens.currentTokenIndex();
let key;
if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_INTEGER)) {
key = new const_expr_integer_node_1.ConstExprIntegerNode(tokens.currentTokenValue().replaceAll('_', ''));
tokens.next();
}
else if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_SINGLE_QUOTED_STRING)) {
if (this.quoteAwareConstExprString) {
key = new quote_aware_const_expr_string_node_1.QuoteAwareConstExprStringNode(string_unescaper_1.StringUnescaper.unescapeString(tokens.currentTokenValue()), quote_aware_const_expr_string_node_1.QuoteAwareConstExprStringNode.SINGLE_QUOTED);
}
else {
key = new const_expr_string_node_1.ConstExprStringNode(tokens.currentTokenValue().replace(/(^'|'$)/g, ''));
}
tokens.next();
}
else if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_DOUBLE_QUOTED_STRING)) {
if (this.quoteAwareConstExprString) {
key = new quote_aware_const_expr_string_node_1.QuoteAwareConstExprStringNode(string_unescaper_1.StringUnescaper.unescapeString(tokens.currentTokenValue()), quote_aware_const_expr_string_node_1.QuoteAwareConstExprStringNode.DOUBLE_QUOTED);
}
else {
key = new const_expr_string_node_1.ConstExprStringNode(tokens.currentTokenValue().replace(/(^"|"$)/g, ''));
}
tokens.next();
}
else {
key = new identifier_type_node_1.IdentifierTypeNode(tokens.currentTokenValue());
tokens.consumeTokenType(lexer_1.Lexer.TOKEN_IDENTIFIER);
}
return this.enrichWithAttributes(tokens, key, startLine, startIndex);
}
parseObjectShape(tokens) {
tokens.consumeTokenType(lexer_1.Lexer.TOKEN_OPEN_CURLY_BRACKET);
const items = [];
do {
tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL);
if (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_CLOSE_CURLY_BRACKET)) {
return new object_shape_node_1.ObjectShapeNode(items);
}
items.push(this.parseObjectShapeItem(tokens));
tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL);
} while (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_COMMA));
tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL);
tokens.consumeTokenType(lexer_1.Lexer.TOKEN_CLOSE_CURLY_BRACKET);
return new object_shape_node_1.ObjectShapeNode(items);
}
parseObjectShapeItem(tokens) {
const startLine = tokens.currentTokenLine();
const startIndex = tokens.currentTokenIndex();
const key = this.parseObjectShapeKey(tokens);
const optional = tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_NULLABLE);
tokens.consumeTokenType(lexer_1.Lexer.TOKEN_COLON);
const value = this.parse(tokens);
return this.enrichWithAttributes(tokens, new object_shape_item_node_1.ObjectShapeItemNode(key, optional, value), startLine, startIndex);
}
parseObjectShapeKey(tokens) {
const startLine = tokens.currentTokenLine();
const startIndex = tokens.currentTokenIndex();
let key;
if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_SINGLE_QUOTED_STRING)) {
if (this.quoteAwareConstExprString) {
key = new quote_aware_const_expr_string_node_1.QuoteAwareConstExprStringNode(string_unescaper_1.StringUnescaper.unescapeString(tokens.currentTokenValue()), quote_aware_const_expr_string_node_1.QuoteAwareConstExprStringNode.SINGLE_QUOTED);
}
else {
key = new const_expr_string_node_1.ConstExprStringNode(tokens.currentTokenValue().replace(/(^'|'$)/g, ''));
}
tokens.next();
}
else if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_DOUBLE_QUOTED_STRING)) {
if (this.quoteAwareConstExprString) {
key = new quote_aware_const_expr_string_node_1.QuoteAwareConstExprStringNode(string_unescaper_1.StringUnescaper.unescapeString(tokens.currentTokenValue()), quote_aware_const_expr_string_node_1.QuoteAwareConstExprStringNode.DOUBLE_QUOTED);
}
else {
key = new const_expr_string_node_1.ConstExprStringNode(tokens.currentTokenValue().replace(/(^"|"$)/g, ''));
}
tokens.next();
}
else {
key = new identifier_type_node_1.IdentifierTypeNode(tokens.currentTokenValue());
tokens.consumeTokenType(lexer_1.Lexer.TOKEN_IDENTIFIER);
}
return this.enrichWithAttributes(tokens, key, startLine, startIndex);
}
}
exports.TypeParser = TypeParser;