Empty collections creation (#447)

This commit is contained in:
Dmitry Kurinskiy 2022-03-04 14:07:30 +03:00 committed by GitHub
parent 6772c1d0fa
commit 2fa3a09548
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 37 additions and 20 deletions

View File

@ -1,5 +1,4 @@
func optionSugar() -> []u32:
str: *u32
for i <- ?[4, 5]:
str <<- i
<- str
func optionSugar(numSome: ?u32, numNone: ?u32) -> []u32:
arr = ?[numNone!, numSome!, "123"]
<- arr

View File

@ -43,6 +43,11 @@ object MakeRes {
private def orInit(currentPeerId: Option[ValueModel]): ValueModel =
currentPeerId.getOrElse(initPeerId)
private def isNillLiteral(vm: ValueModel): Boolean = vm match {
case LiteralModel(value, t) if value == ValueRaw.Nil.value && t == ValueRaw.Nil.`type` => true
case _ => false
}
def resolve(
currentPeerId: Option[ValueModel],
i: Int
@ -51,7 +56,7 @@ object MakeRes {
case _: OnModel => SeqRes.leaf
case MatchMismatchModel(a, b, s) =>
MatchMismatchRes(a, b, s).leaf
case ForModel(item, iter) => FoldRes(item, iter).leaf
case ForModel(item, iter) if !isNillLiteral(iter) => FoldRes(item, iter).leaf
case RestrictionModel(item, isStream) => RestrictionRes(item, isStream).leaf
case ParModel | DetachModel => ParRes.leaf
case XorModel => XorRes.leaf

View File

@ -87,6 +87,8 @@ object Token {
val exclamation: P[Unit] = P.char('!')
val `[]` : P[Unit] = P.string("[]")
val `[` : P[Unit] = P.char('[').surroundedBy(` `.?)
val `*[` : P[Unit] = P.string("*[").surroundedBy(` `.?)
val `?[` : P[Unit] = P.string("?[").surroundedBy(` `.?)
val `]` : P[Unit] = P.char(']').surroundedBy(` `.?)
val `` : P[Unit] = P.char('')
val `⊥` : P[Unit] = P.char('⊥')

View File

@ -34,12 +34,16 @@ case class LiteralToken[F[_]: Comonad](valueToken: F[String], ts: LiteralType)
}
case class CollectionToken[F[_]: Comonad](
values: NonEmptyList[ValueToken[F]],
mode: CollectionToken.Mode
point: F[CollectionToken.Mode],
values: List[ValueToken[F]]
) extends ValueToken[F] {
override def mapK[K[_]: Comonad](fk: F ~> K): ValueToken[K] = copy(values.map(_.mapK(fk)))
override def as[T](v: T): F[T] = values.head.as(v)
override def mapK[K[_]: Comonad](fk: F ~> K): ValueToken[K] =
copy(fk(point), values.map(_.mapK(fk)))
override def as[T](v: T): F[T] = point.as(v)
def mode: CollectionToken.Mode = point.extract
}
object CollectionToken {
@ -48,12 +52,14 @@ object CollectionToken {
case StreamMode, OptionMode, ArrayMode
def collection: P[CollectionToken[Span.S]] =
((`*`.as(Mode.StreamMode: Mode) | `?`.as(Mode.OptionMode: Mode)).?.map(
_.getOrElse(Mode.ArrayMode: Mode)
).with1 ~ (`[` *> P
((
`*[`.as[Mode](Mode.StreamMode) |
`?[`.as[Mode](Mode.OptionMode) |
`[`.as[Mode](Mode.ArrayMode)
).lift ~ (P
.defer(ValueToken.`_value`)
.repSep(`,`) <* `]`)).map { case (mode, vals) =>
CollectionToken(vals, mode)
.repSep0(`,`) <* `]`)).map { case (mode, vals) =>
CollectionToken(mode, vals)
}
}

View File

@ -95,20 +95,25 @@ class ValuesAlgebra[S[_], Alg[_]: Monad](implicit
case None =>
None.pure[Alg]
}
case CollectionToken(values, mode) =>
case ct @ CollectionToken(_, values) =>
values.traverse(valueToRaw).map(_.toList.flatten).map(NonEmptyList.fromList).map {
case Some(raws) if raws.size == values.size =>
val element = raws.map(_.`type`).reduceLeft(_ `∩` _)
// In case we mix values of uncomparable types, intersection returns bottom, meaning "uninhabited type".
// But we want to get to TopType instead: this would mean that intersection is empty, and you cannot
// make any decision about the structure of type, but can push anything inside
val elementNotBottom = if (element == BottomType) TopType else element
Some(
CollectionRaw(
raws,
mode match {
case CollectionToken.Mode.StreamMode => StreamType(element)
case CollectionToken.Mode.ArrayMode => ArrayType(element)
case CollectionToken.Mode.OptionMode => OptionType(element)
ct.mode match {
case CollectionToken.Mode.StreamMode => StreamType(elementNotBottom)
case CollectionToken.Mode.ArrayMode => ArrayType(elementNotBottom)
case CollectionToken.Mode.OptionMode => OptionType(elementNotBottom)
}
)
)
case _ if values.isEmpty => Some(ValueRaw.Nil)
case _ => None
}
}