diff --git a/model/inline/src/main/scala/aqua/model/inline/raw/CollectionRawInliner.scala b/model/inline/src/main/scala/aqua/model/inline/raw/CollectionRawInliner.scala index e591344f..440fe0b2 100644 --- a/model/inline/src/main/scala/aqua/model/inline/raw/CollectionRawInliner.scala +++ b/model/inline/src/main/scala/aqua/model/inline/raw/CollectionRawInliner.scala @@ -20,18 +20,20 @@ import cats.data.{Chain, State} object CollectionRawInliner extends RawInliner[CollectionRaw] { - override def apply[S: Mangler : Exports : Arrows]( - raw: CollectionRaw, - lambdaAllowed: Boolean - ): State[S, (ValueModel, Inline)] = + override def apply[S: Mangler: Exports: Arrows]( + raw: CollectionRaw, + lambdaAllowed: Boolean + ): State[S, (ValueModel, Inline)] = for { - streamName <- Mangler[S].findAndForbidName(( - raw.boxType match { - case _: StreamType => "stream" - case _: ArrayType => "array" - case _: OptionType => "option" - } - ) + "-inline") + streamName <- Mangler[S].findAndForbidName( + ( + raw.boxType match { + case _: StreamType => "stream" + case _: ArrayType => "array" + case _: OptionType => "option" + } + ) + "-inline" + ) stream = VarModel(streamName, StreamType(raw.elementType)) streamExp = CallModel.Export(stream.name, stream.`type`) diff --git a/parser/src/main/scala/aqua/parser/lexer/LambdaOp.scala b/parser/src/main/scala/aqua/parser/lexer/LambdaOp.scala index 788e2e8e..2f154c6f 100644 --- a/parser/src/main/scala/aqua/parser/lexer/LambdaOp.scala +++ b/parser/src/main/scala/aqua/parser/lexer/LambdaOp.scala @@ -13,6 +13,7 @@ import scala.language.postfixOps import cats.~> import aqua.parser.lift.Span import aqua.parser.lift.Span.{P0ToSpan, PToSpan} +import aqua.types.LiteralType sealed trait LambdaOp[F[_]] extends Token[F] { def mapK[K[_]: Comonad](fk: F ~> K): LambdaOp[K] @@ -39,16 +40,18 @@ object LambdaOp { private val parseField: P[LambdaOp[Span.S]] = (`.` *> `name`).lift.map(IntoField(_)) - private val nonNegativeIntP0: P0[Int] = - Numbers.nonNegativeIntString.map(_.toInt).?.map(_.getOrElse(0)) - private val parseIdx: P[LambdaOp[Span.S]] = - P.defer( + (P.defer( (ValueToken.`value`.between(`[`, `]`) | (exclamation *> ValueToken.num)) .map(v => IntoIndex(v, Some(v))) .backtrack - ) | - exclamation.lift.map(e => IntoIndex(Token.lift[Span.S, Unit](e), None)) + ) | exclamation.lift.map(e => IntoIndex(Token.lift[Span.S, Unit](e), None))).flatMap { ii => + ii.idx match { + case Some(LiteralToken(_, lt)) if lt == LiteralType.signed => + P.fail.withContext("Collection indexes must be non-negative") + case _ => P.pure(ii) + } + } private val parseOp: P[LambdaOp[Span.S]] = P.oneOf(parseField.backtrack :: parseIdx :: Nil) diff --git a/parser/src/test/scala/aqua/parser/lexer/LambdaOpSpec.scala b/parser/src/test/scala/aqua/parser/lexer/LambdaOpSpec.scala index 33896eac..7c89c35b 100644 --- a/parser/src/test/scala/aqua/parser/lexer/LambdaOpSpec.scala +++ b/parser/src/test/scala/aqua/parser/lexer/LambdaOpSpec.scala @@ -17,6 +17,9 @@ class LambdaOpSpec extends AnyFlatSpec with Matchers with EitherValues { opsP(".field") should be(NonEmptyList.of(IntoField[Id]("field"))) opsP(".field.sub") should be(NonEmptyList.of(IntoField[Id]("field"), IntoField[Id]("sub"))) + LambdaOp.ops.parseAll("[-1]").isLeft shouldBe true + LambdaOp.ops.parseAll("!-1").isLeft shouldBe true + } }