fix(parser): support optional start and end indices in slice ranges

Signed-off-by: erick-alcachofa <erick@artichoke.dev>

Update the SliceAccess postfix operator logic to handle the full variety
of slice range syntaxes. This allows for open-ended slices by making the
start and end expressions optional within the brackets.

- Add logic to detect a leading colon for `[:end]` and `[:]` forms.
- Support trailing colons for `[start:]` forms.
- Differentiate between a single index access and a slice range based on
  the presence of the colon operator.
- Update SliceRangeExprNode construction to handle optional boundaries.
This commit is contained in:
erick-alcachofa 2025-12-28 11:26:27 -06:00
parent c2f37d5702
commit 25486fbace
Signed by: me
GPG Key ID: 6FA5F8643444BAFA

View File

@ -632,16 +632,52 @@ namespace arti::lang {
node = std::move(newNode);
}
else if (op == ast::PostfixOperator::SliceAccess) {
auto idx = parseExpression();
bool isSlice = false;
bool skipSliceEnd = false;
bool skipSliceStart = false;
if (! idx) {
return Unexpected<>{ std::move(idx).error() };
if (auto skipLeft = matchAndConsume(TokenV::opColon); ! skipLeft) {
return Unexpected<>{ std::move(skipLeft).error() };
}
else if (skipLeft.value()) {
isSlice = true;
skipSliceStart = true;
if (auto close = matchAndConsume(TokenV::opRBracket); ! close) {
return Unexpected<>{ std::move(close).error() };
}
else if (close.value()) {
skipSliceEnd = true;
}
}
if (auto range = matchAndConsume(TokenV::opColon); ! range) {
return Unexpected<>{ std::move(range).error() };
auto idxExpr = ast::Optional<ast::ExpressionNode>{};
if (! skipSliceStart) {
auto idx = parseExpression();
if (! idx) {
return Unexpected<>{ std::move(idx).error() };
}
if (auto range = matchAndConsume(TokenV::opColon); ! range) {
return Unexpected<>{ std::move(range).error() };
}
else if (range.value()) {
isSlice = true;
if (auto close = matchAndConsume(TokenV::opRBracket); ! close) {
return Unexpected<>{ std::move(close).error() };
}
else if (close.value()) {
skipSliceEnd = true;
}
}
idxExpr = std::move(idx).value();
}
else if (range.value()) {
if (isSlice) {
auto newNode = ast::MakeNode<ast::SliceRangeExprNode>();
newNode->location = {
@ -649,18 +685,22 @@ namespace arti::lang {
.column = peekToken->column
};
newNode->start = std::move(idx).value();
auto endIdx = parseExpression();
if (! endIdx) {
return Unexpected<>{ std::move(endIdx).error() };
if (! skipSliceStart) {
newNode->start = std::move(idxExpr).value();
}
newNode->end = std::move(endIdx).value();
if (! skipSliceEnd) {
auto endIdx = parseExpression();
if (auto close = consume(TokenV::opRBracket, "']'"); ! close) {
return Unexpected<>{ std::move(close).error() };
if (! endIdx) {
return Unexpected<>{ std::move(endIdx).error() };
}
newNode->end = std::move(endIdx).value();
if (auto close = consume(TokenV::opRBracket, "']'"); ! close) {
return Unexpected<>{ std::move(close).error() };
}
}
newNode->slice = std::move(lhs);
@ -675,7 +715,7 @@ namespace arti::lang {
.column = peekToken->column
};
newNode->index = std::move(idx).value();
newNode->index = std::move(idxExpr).value();
if (auto close = consume(TokenV::opRBracket, "']'"); ! close) {
return Unexpected<>{ std::move(close).error() };