mirror of
https://github.com/fluencelabs/aqua.git
synced 2025-04-24 22:42:13 +00:00
feat: copy structures implementation [fixes LNG-102] (#646)
This commit is contained in:
parent
d0a9db5164
commit
50f0723a32
@ -1,6 +1,6 @@
|
||||
aqua FooBars declares wait
|
||||
aqua FooBars declares getObjAssign
|
||||
|
||||
export wait
|
||||
export getObjAssign
|
||||
|
||||
data Record:
|
||||
relay_id: []string
|
||||
@ -83,11 +83,12 @@ data SomeObj:
|
||||
num: u64
|
||||
inner: InnerObj
|
||||
|
||||
func wait(i: []u32) -> SomeObj:
|
||||
<- SomeObj(str = "some str",
|
||||
num = 4,
|
||||
inner = InnerObj(arr = ["a", "b", "c"], num = i[2])
|
||||
)
|
||||
-- func wait(i: []u32) -> SomeObj:
|
||||
-- obj = SomeObj(str = "some str",
|
||||
-- num = 4,
|
||||
-- inner = InnerObj(arr = ["a", "b", "c"], num = i[2])
|
||||
-- )
|
||||
-- <- obj.copy(str = "ululu")
|
||||
|
||||
-- func a(nums: []u32) -> []u32:
|
||||
-- <- nums
|
||||
@ -95,4 +96,25 @@ func wait(i: []u32) -> SomeObj:
|
||||
-- func some():
|
||||
-- a([1,2,3,4])
|
||||
|
||||
func getObjAssign(arr: []string) -> string:
|
||||
streamJ: *[]string
|
||||
streamJ <<- ["111", "222"]
|
||||
streamJ <<- ["333", "444"]
|
||||
<- streamJ[arr.length][1]
|
||||
|
||||
|
||||
-- func getObjAssign(arr: []string) -> string:
|
||||
-- stream: *[]u32
|
||||
-- stream <<- [0]
|
||||
-- a = stream[arr.length - 1][0]
|
||||
-- b = arr[a]
|
||||
-- <- b
|
||||
-- func getObjAssign() -> SomeObj, SomeObj, u32:
|
||||
-- obj = SomeObj(str = "first str",
|
||||
-- num = 5,
|
||||
-- inner = InnerObj(arr = ["d", "e", "f"], num = 5)
|
||||
-- )
|
||||
-- copiedObj = obj.copy(str = "some str", inner = obj.inner.copy(arr = ["a", "b", "c"])).copy(num = 6)
|
||||
-- <- obj, copiedObj, copiedObj.inner.copy(arr = ["g"]).arr.length
|
||||
|
||||
|
||||
|
@ -231,10 +231,6 @@ class AquaCompilerSpec extends AnyFlatSpec with Matchers {
|
||||
)
|
||||
),
|
||||
join(results, LiteralModel.fromRaw(LiteralRaw.number(2))),
|
||||
ApRes(
|
||||
VarModel("results_gate", ArrayType(ScalarType.string), Chain(IntoIndexModel("2", ScalarType.string))),
|
||||
CallModel.Export("results_gate-0", ScalarType.string)
|
||||
).leaf,
|
||||
CanonRes(results, init, CallModel.Export(canonResult.name, canonResult.`type`)).leaf,
|
||||
ApRes(
|
||||
canonResult,
|
||||
|
@ -6,18 +6,21 @@ import aqua.raw.value.ValueRaw
|
||||
import cats.Monoid
|
||||
import cats.data.Chain
|
||||
|
||||
import scala.collection.immutable.ListMap
|
||||
|
||||
sealed trait MergeMode
|
||||
object SeqMode extends MergeMode
|
||||
object ParMode extends MergeMode
|
||||
|
||||
/**
|
||||
*
|
||||
* @param flattenValues values that need to be resolved before `predo`
|
||||
* @param flattenValues values that need to be resolved before `predo`.
|
||||
* ListMap for keeping order of values (mostly for debugging purposes)
|
||||
* @param predo operations tree
|
||||
* @param mergeMode how `flattenValues` and `predo` must be merged
|
||||
*/
|
||||
private[inline] case class Inline(
|
||||
flattenValues: Map[String, ValueRaw] = Map.empty,
|
||||
flattenValues: ListMap[String, ValueRaw] = ListMap.empty,
|
||||
predo: Chain[OpModel.Tree] = Chain.empty,
|
||||
mergeMode: MergeMode = ParMode
|
||||
)
|
||||
@ -26,7 +29,7 @@ private[inline] case class Inline(
|
||||
private[inline] object Inline {
|
||||
val empty: Inline = Inline()
|
||||
|
||||
def preload(pairs: (String, ValueRaw)*): Inline = Inline(pairs.toMap)
|
||||
def preload(pairs: (String, ValueRaw)*): Inline = Inline(ListMap.from(pairs))
|
||||
|
||||
def tree(tr: OpModel.Tree): Inline = Inline(predo = Chain.one(tr))
|
||||
|
||||
|
@ -33,9 +33,6 @@ object RawValueInliner extends Logging {
|
||||
case alr: ApplyPropertyRaw =>
|
||||
ApplyPropertiesRawInliner(alr, propertiesAllowed)
|
||||
|
||||
case alr: ApplyFunctorRaw =>
|
||||
ApplyFunctorRawInliner(alr, propertiesAllowed)
|
||||
|
||||
case agr: ApplyGateRaw =>
|
||||
ApplyGateRawInliner(agr, propertiesAllowed)
|
||||
|
||||
@ -91,7 +88,8 @@ object RawValueInliner extends Logging {
|
||||
}
|
||||
}.map{ predo =>
|
||||
inline.mergeMode match
|
||||
case SeqMode => SeqModel.wrap((inline.predo.toList ++ predo):_*) :: Nil
|
||||
case SeqMode =>
|
||||
SeqModel.wrap((inline.predo.toList ++ predo):_*) :: Nil
|
||||
case ParMode => inline.predo.toList ::: predo
|
||||
}
|
||||
}
|
||||
|
@ -10,29 +10,29 @@ import aqua.model.{
|
||||
ValueModel,
|
||||
VarModel
|
||||
}
|
||||
import aqua.model.inline.Inline
|
||||
import aqua.model.inline.{Inline, SeqMode}
|
||||
import aqua.model.inline.state.{Arrows, Exports, Mangler}
|
||||
import aqua.raw.value.ApplyFunctorRaw
|
||||
import aqua.raw.value.{FunctorRaw, ValueRaw}
|
||||
import cats.data.State
|
||||
import cats.data.Chain
|
||||
import aqua.model.inline.RawValueInliner.unfold
|
||||
import aqua.types.{BoxType, CanonStreamType, StreamType, ArrayType}
|
||||
import aqua.types.{ArrayType, BoxType, CanonStreamType, StreamType}
|
||||
import cats.syntax.monoid.*
|
||||
import scribe.Logging
|
||||
|
||||
object ApplyFunctorRawInliner extends RawInliner[ApplyFunctorRaw] with Logging {
|
||||
object ApplyFunctorRawInliner extends Logging {
|
||||
|
||||
override def apply[S: Mangler: Exports: Arrows](
|
||||
afr: ApplyFunctorRaw,
|
||||
propertyAllowed: Boolean
|
||||
): State[S, (ValueModel, Inline)] = {
|
||||
val functorModel = FunctorModel(afr.functor.name, afr.functor.`type`)
|
||||
def apply[S: Mangler: Exports: Arrows](
|
||||
value: ValueModel,
|
||||
functor: FunctorRaw
|
||||
): State[S, (VarModel, Inline)] = {
|
||||
val functorModel = FunctorModel(functor.name, functor.`type`)
|
||||
|
||||
unfold(afr.value).flatMap {
|
||||
case (v @ VarModel(name, bt, _), inl) =>
|
||||
value match {
|
||||
case v @ VarModel(name, bt, _) =>
|
||||
for {
|
||||
apName <- Mangler[S].findAndForbidName(name + "_to_functor")
|
||||
resultName <- Mangler[S].findAndForbidName(s"${name}_${afr.functor.name}")
|
||||
resultName <- Mangler[S].findAndForbidName(s"${name}_${functor.name}")
|
||||
(apVar, flat) = {
|
||||
bt match {
|
||||
case StreamType(el) =>
|
||||
@ -46,21 +46,22 @@ object ApplyFunctorRawInliner extends RawInliner[ApplyFunctorRaw] with Logging {
|
||||
}
|
||||
}
|
||||
} yield {
|
||||
val tree = inl |+| Inline.tree(
|
||||
SeqModel.wrap(
|
||||
val tree = Inline(
|
||||
predo = Chain.one(SeqModel.wrap(
|
||||
flat,
|
||||
FlattenModel(apVar, resultName).leaf
|
||||
)
|
||||
)),
|
||||
mergeMode = SeqMode
|
||||
)
|
||||
|
||||
VarModel(resultName, afr.functor.`type`) -> tree
|
||||
VarModel(resultName, functor.`type`) -> tree
|
||||
}
|
||||
case (l @ LiteralModel(_, _), inl) =>
|
||||
ApplyPropertiesRawInliner.flatLiteralWithProperties(l, inl, Chain.one(functorModel), afr.functor.`type`)
|
||||
case v =>
|
||||
// unexpected, properties are prohibited for literals
|
||||
logger.error(s"Unexpected. Properties are prohibited for literals. Literal: '$v'")
|
||||
State.pure(v)
|
||||
case l @ LiteralModel(_, _) =>
|
||||
ApplyPropertiesRawInliner.flatLiteralWithProperties(
|
||||
l,
|
||||
Inline.empty,
|
||||
Chain.one(functorModel)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,31 @@ object ApplyGateRawInliner extends RawInliner[ApplyGateRaw] with Logging {
|
||||
|
||||
val incrVar = VarModel(uniqueIdxIncr, ScalarType.u32)
|
||||
|
||||
// To wait for the element of a stream by the given index, the following model is generated:
|
||||
// (seq
|
||||
// (seq
|
||||
// (seq
|
||||
// (call %init_peer_id% ("math" "add") [0 1] stream_incr)
|
||||
// (fold $stream s
|
||||
// (seq
|
||||
// (seq
|
||||
// (ap s $stream_test)
|
||||
// (canon %init_peer_id% $stream_test #stream_iter_canon)
|
||||
// )
|
||||
// (xor
|
||||
// (match #stream_iter_canon.length stream_incr
|
||||
// (null)
|
||||
// )
|
||||
// (next s)
|
||||
// )
|
||||
// )
|
||||
// (never)
|
||||
// )
|
||||
// )
|
||||
// (canon %init_peer_id% $stream_test #stream_result_canon)
|
||||
// )
|
||||
// (ap #stream_result_canon stream_gate)
|
||||
// )
|
||||
val gate = RestrictionModel(varSTest.name, true).wrap(
|
||||
increment(idxModel, incrVar),
|
||||
ForModel(iter.name, VarModel(afr.name, afr.streamType), Some(ForModel.NeverMode)).wrap(
|
||||
|
@ -0,0 +1,69 @@
|
||||
package aqua.model.inline.raw
|
||||
|
||||
import aqua.model.{
|
||||
CallModel,
|
||||
CallServiceModel,
|
||||
LiteralModel,
|
||||
OpModel,
|
||||
SeqModel,
|
||||
ValueModel,
|
||||
VarModel
|
||||
}
|
||||
import aqua.model.inline.{Inline, SeqMode}
|
||||
import aqua.model.inline.MakeStructRawInliner.createObj
|
||||
import aqua.model.inline.RawValueInliner.unfold
|
||||
import aqua.model.inline.state.{Arrows, Exports, Mangler}
|
||||
import aqua.raw.value.{IntoCopyRaw, LiteralRaw}
|
||||
import aqua.types.ScalarType
|
||||
import cats.data.{Chain, NonEmptyMap, State}
|
||||
import scribe.Logging
|
||||
import cats.syntax.traverse.*
|
||||
import cats.syntax.monoid.*
|
||||
import cats.syntax.functor.*
|
||||
import cats.syntax.flatMap.*
|
||||
import cats.syntax.apply.*
|
||||
|
||||
object ApplyIntoCopyRawInliner extends Logging {
|
||||
|
||||
private def copyObj(
|
||||
value: VarModel,
|
||||
fields: NonEmptyMap[String, ValueModel],
|
||||
result: VarModel
|
||||
): OpModel.Tree = {
|
||||
val args = fields.toSortedMap.toList.flatMap { case (name, value) =>
|
||||
LiteralModel.fromRaw(LiteralRaw.quote(name)) :: value :: Nil
|
||||
}
|
||||
CallServiceModel(
|
||||
LiteralModel("\"json\"", ScalarType.string),
|
||||
"puts",
|
||||
CallModel(
|
||||
value +: args,
|
||||
CallModel.Export(result.name, result.`type`) :: Nil
|
||||
)
|
||||
).leaf
|
||||
}
|
||||
|
||||
def apply[S: Mangler: Exports: Arrows](
|
||||
value: VarModel,
|
||||
intoCopy: IntoCopyRaw
|
||||
): State[S, (VarModel, Inline)] = {
|
||||
for {
|
||||
name <- Mangler[S].findAndForbidName(value.name + "_obj_copy")
|
||||
foldedFields <- intoCopy.fields.nonEmptyTraverse(unfold(_))
|
||||
} yield {
|
||||
val varModel = VarModel(name, value.baseType)
|
||||
val valsInline = foldedFields.toSortedMap.values.map(_._2).fold(Inline.empty)(_ |+| _)
|
||||
val fields = foldedFields.map(_._1)
|
||||
val objCreation = copyObj(value, fields, varModel)
|
||||
(
|
||||
varModel,
|
||||
Inline(
|
||||
valsInline.flattenValues,
|
||||
Chain.one(SeqModel.wrap((valsInline.predo :+ objCreation).toList: _*)),
|
||||
SeqMode
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,28 +1,60 @@
|
||||
package aqua.model.inline.raw
|
||||
|
||||
import aqua.model.{CallModel, CallServiceModel, CanonicalizeModel, FlattenModel, ForModel, FunctorModel, IntoFieldModel, IntoIndexModel, LiteralModel, MatchMismatchModel, NextModel, PropertyModel, PushToStreamModel, RestrictionModel, SeqModel, ValueModel, VarModel, XorModel}
|
||||
import aqua.model.{
|
||||
CallModel,
|
||||
CallServiceModel,
|
||||
CanonicalizeModel,
|
||||
FlattenModel,
|
||||
ForModel,
|
||||
FunctorModel,
|
||||
IntoFieldModel,
|
||||
IntoIndexModel,
|
||||
LiteralModel,
|
||||
MatchMismatchModel,
|
||||
NextModel,
|
||||
OpModel,
|
||||
PropertyModel,
|
||||
PushToStreamModel,
|
||||
RestrictionModel,
|
||||
SeqModel,
|
||||
ValueModel,
|
||||
VarModel,
|
||||
XorModel
|
||||
}
|
||||
import aqua.model.inline.Inline
|
||||
import aqua.model.inline.SeqMode
|
||||
import aqua.model.inline.RawValueInliner.unfold
|
||||
import aqua.model.inline.state.{Arrows, Exports, Mangler}
|
||||
import aqua.raw.value.{ApplyFunctorRaw, ApplyGateRaw, ApplyPropertyRaw, CallArrowRaw, FunctorRaw, IntoFieldRaw, IntoIndexRaw, LiteralRaw, PropertyRaw, ValueRaw, VarRaw}
|
||||
import aqua.raw.value.{
|
||||
ApplyGateRaw,
|
||||
ApplyPropertyRaw,
|
||||
CallArrowRaw,
|
||||
FunctorRaw,
|
||||
IntoCopyRaw,
|
||||
IntoFieldRaw,
|
||||
IntoIndexRaw,
|
||||
LiteralRaw,
|
||||
PropertyRaw,
|
||||
ValueRaw,
|
||||
VarRaw
|
||||
}
|
||||
import aqua.types.{ArrayType, CanonStreamType, ScalarType, StreamType, Type}
|
||||
import cats.Eval
|
||||
import cats.data.{Chain, IndexedStateT, State}
|
||||
import cats.syntax.monoid.*
|
||||
import cats.instances.list.*
|
||||
import scribe.Logging
|
||||
|
||||
object ApplyPropertiesRawInliner extends RawInliner[ApplyPropertyRaw] {
|
||||
object ApplyPropertiesRawInliner extends RawInliner[ApplyPropertyRaw] with Logging {
|
||||
|
||||
// in perspective literals can have properties and functors (like `nil` with length)
|
||||
def flatLiteralWithProperties[S: Mangler: Exports: Arrows](
|
||||
literal: LiteralModel,
|
||||
inl: Inline,
|
||||
properties: Chain[PropertyModel],
|
||||
resultType: Type
|
||||
): State[S, (ValueModel, Inline)] = {
|
||||
properties: Chain[PropertyModel]
|
||||
): State[S, (VarModel, Inline)] = {
|
||||
for {
|
||||
apName <- Mangler[S].findAndForbidName("literal_to_functor")
|
||||
apName <- Mangler[S].findAndForbidName("literal_ap")
|
||||
resultName <- Mangler[S].findAndForbidName(s"literal_props")
|
||||
} yield {
|
||||
val cleanedType = literal.`type` match {
|
||||
@ -37,98 +69,108 @@ object ApplyPropertiesRawInliner extends RawInliner[ApplyPropertyRaw] {
|
||||
FlattenModel(apVar, resultName).leaf
|
||||
)
|
||||
)
|
||||
VarModel(resultName, resultType) -> tree
|
||||
VarModel(resultName, properties.lastOption.map(_.`type`).getOrElse(cleanedType)) -> tree
|
||||
}
|
||||
}
|
||||
|
||||
private[inline] def removeProperty[S: Mangler: Exports: Arrows](
|
||||
vm: ValueModel
|
||||
): State[S, (ValueModel, Inline)] =
|
||||
vm match {
|
||||
case VarModel(nameM, btm, propertyM) if propertyM.nonEmpty =>
|
||||
for {
|
||||
nameMM <- Mangler[S].findAndForbidName(nameM)
|
||||
} yield VarModel(nameMM, vm.`type`, Chain.empty) -> Inline.preload(
|
||||
// TODO use smth more resilient to make VarRaw from a flattened VarModel
|
||||
nameMM -> ApplyPropertyRaw.fromChain(VarRaw(nameM, btm), propertyM.map(_.toRaw))
|
||||
)
|
||||
case _ =>
|
||||
State.pure(vm -> Inline.empty)
|
||||
private def removeProperties[S: Mangler](
|
||||
varModel: VarModel
|
||||
): State[S, (VarModel, Inline)] = {
|
||||
for {
|
||||
nn <- Mangler[S].findAndForbidName(varModel.name + "_flat")
|
||||
} yield {
|
||||
val flatten = VarModel(nn, varModel.`type`)
|
||||
flatten -> Inline.tree(FlattenModel(varModel, flatten.name).leaf)
|
||||
}
|
||||
}
|
||||
|
||||
private[inline] def unfoldProperty[S: Mangler: Exports: Arrows](
|
||||
varModel: VarModel,
|
||||
p: PropertyRaw
|
||||
): State[S, (PropertyModel, Inline)] = // TODO property for collection
|
||||
): State[S, (VarModel, Inline)] =
|
||||
p match {
|
||||
case IntoFieldRaw(field, t) =>
|
||||
State.pure(IntoFieldModel(field, t) -> Inline.empty)
|
||||
case IntoIndexRaw(vm: ApplyPropertyRaw, t) =>
|
||||
for {
|
||||
nn <- Mangler[S].findAndForbidName("ap-prop")
|
||||
} yield IntoIndexModel(nn, t) -> Inline.preload(nn -> vm)
|
||||
|
||||
case IntoIndexRaw(vr: (VarRaw | CallArrowRaw), t) =>
|
||||
unfold(vr, propertiesAllowed = false).map {
|
||||
case (VarModel(name, _, _), inline) =>
|
||||
IntoIndexModel(name, t) -> inline
|
||||
case (LiteralModel(v, _), inline) => IntoIndexModel(v, t) -> inline
|
||||
}
|
||||
State.pure(
|
||||
varModel.copy(properties =
|
||||
varModel.properties :+ IntoFieldModel(field, t)
|
||||
) -> Inline.empty
|
||||
)
|
||||
|
||||
case IntoIndexRaw(LiteralRaw(value, _), t) =>
|
||||
State.pure(IntoIndexModel(value, t) -> Inline.empty)
|
||||
State.pure(
|
||||
varModel.copy(properties =
|
||||
varModel.properties :+ IntoIndexModel(value, t)
|
||||
) -> Inline.empty
|
||||
)
|
||||
|
||||
case IntoIndexRaw(vr, t) =>
|
||||
unfold(vr, propertiesAllowed = false).map {
|
||||
case (VarModel(name, _, _), inline) =>
|
||||
varModel.copy(properties = varModel.properties :+ IntoIndexModel(name, t)) -> inline
|
||||
case (LiteralModel(literal, _), inline) =>
|
||||
varModel.copy(properties = varModel.properties :+ IntoIndexModel(literal, t)) -> inline
|
||||
}
|
||||
|
||||
case f @ FunctorRaw(_, _) =>
|
||||
for {
|
||||
flattenVI <-
|
||||
if (varModel.properties.nonEmpty) removeProperties(varModel)
|
||||
else State.pure(varModel, Inline.empty)
|
||||
(flatten, inline) = flattenVI
|
||||
newVI <- ApplyFunctorRawInliner(flatten, f)
|
||||
} yield {
|
||||
newVI._1 -> Inline(
|
||||
inline.flattenValues ++ newVI._2.flattenValues,
|
||||
inline.predo ++ newVI._2.predo,
|
||||
mergeMode = SeqMode
|
||||
)
|
||||
}
|
||||
|
||||
case ic @ IntoCopyRaw(_, _) =>
|
||||
for {
|
||||
flattenVI <-
|
||||
if (varModel.properties.nonEmpty) removeProperties(varModel)
|
||||
else State.pure(varModel, Inline.empty)
|
||||
(flatten, inline) = flattenVI
|
||||
newVI <- ApplyIntoCopyRawInliner(varModel, ic)
|
||||
} yield {
|
||||
newVI._1 -> Inline(
|
||||
inline.flattenValues ++ newVI._2.flattenValues,
|
||||
inline.predo ++ newVI._2.predo,
|
||||
mergeMode = SeqMode
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
def reachModelWithPropertyModels[S: Mangler: Exports: Arrows](
|
||||
model: ValueModel,
|
||||
propertyModels: Chain[PropertyModel],
|
||||
propertyPrefix: Inline,
|
||||
propertiesAllowed: Boolean,
|
||||
streamGateInline: Option[Inline] = None
|
||||
): State[S, (ValueModel, Inline)] = {
|
||||
Exports[S].exports.flatMap { exports =>
|
||||
model match {
|
||||
case v: VarModel =>
|
||||
{
|
||||
val vm = v.copy(properties = v.properties ++ propertyModels).resolveWith(exports)
|
||||
State.pure((vm, Inline.empty))
|
||||
}.flatMap { case (genV, genInline) =>
|
||||
val prefInline = propertyPrefix |+| genInline
|
||||
if (propertiesAllowed) State.pure(genV -> prefInline)
|
||||
else
|
||||
removeProperty(genV).map { case (vmm, mpp) =>
|
||||
val resultInline = streamGateInline.map { gInline =>
|
||||
Inline(
|
||||
prefInline.flattenValues ++ mpp.flattenValues ++ gInline.flattenValues,
|
||||
Chain.one(
|
||||
SeqModel.wrap((prefInline.predo ++ mpp.predo ++ gInline.predo).toList: _*)
|
||||
),
|
||||
SeqMode
|
||||
)
|
||||
}.getOrElse(prefInline |+| mpp)
|
||||
vmm -> resultInline
|
||||
}
|
||||
}
|
||||
|
||||
case l: LiteralModel if propertyModels.nonEmpty =>
|
||||
flatLiteralWithProperties(l, propertyPrefix, propertyModels, propertyModels.lastOption.map(_.`type`).getOrElse(l.`type`))
|
||||
|
||||
case v =>
|
||||
// What does it mean actually? I've no ides
|
||||
State.pure((v, propertyPrefix))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def unfoldProperties[S: Mangler: Exports: Arrows](
|
||||
properties: Chain[PropertyRaw]
|
||||
): State[S, (Chain[PropertyModel], Inline)] = {
|
||||
prevInline: Inline,
|
||||
vm: VarModel,
|
||||
properties: Chain[PropertyRaw],
|
||||
propertiesAllowed: Boolean
|
||||
): State[S, (VarModel, Inline)] = {
|
||||
properties
|
||||
.foldLeft[State[S, (Chain[PropertyModel], Inline)]](
|
||||
State.pure((Chain.empty[PropertyModel], Inline.empty))
|
||||
) { case (pcm, p) =>
|
||||
pcm.flatMap { case (pc, m) =>
|
||||
unfoldProperty(p).map { case (pm, mm) =>
|
||||
(pc :+ pm, m |+| mm)
|
||||
.foldLeft[State[S, (VarModel, Inline)]](
|
||||
State.pure((vm, prevInline))
|
||||
) { case (state, property) =>
|
||||
state.flatMap { case (vm, leftInline) =>
|
||||
unfoldProperty(vm, property).flatMap {
|
||||
case (v, i) if !propertiesAllowed && v.properties.nonEmpty =>
|
||||
removeProperties(v).map { case (vf, inlf) =>
|
||||
vf -> Inline(
|
||||
leftInline.flattenValues ++ i.flattenValues ++ inlf.flattenValues,
|
||||
leftInline.predo ++ i.predo ++ inlf.predo,
|
||||
mergeMode = SeqMode
|
||||
)
|
||||
}
|
||||
case (v, i) =>
|
||||
State.pure(
|
||||
v -> Inline(
|
||||
leftInline.flattenValues ++ i.flattenValues,
|
||||
leftInline.predo ++ i.predo,
|
||||
mergeMode = SeqMode
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -140,56 +182,47 @@ object ApplyPropertiesRawInliner extends RawInliner[ApplyPropertyRaw] {
|
||||
propertiesAllowed: Boolean
|
||||
): State[S, (ValueModel, Inline)] = {
|
||||
((raw, properties.headOption) match {
|
||||
// To wait for the element of a stream by the given index, the following model is generated:
|
||||
// (seq
|
||||
// (seq
|
||||
// (seq
|
||||
// (call %init_peer_id% ("math" "add") [0 1] stream_incr)
|
||||
// (fold $stream s
|
||||
// (seq
|
||||
// (seq
|
||||
// (ap s $stream_test)
|
||||
// (canon %init_peer_id% $stream_test #stream_iter_canon)
|
||||
// )
|
||||
// (xor
|
||||
// (match #stream_iter_canon.length stream_incr
|
||||
// (null)
|
||||
// )
|
||||
// (next s)
|
||||
// )
|
||||
// )
|
||||
// (never)
|
||||
// )
|
||||
// )
|
||||
// (canon %init_peer_id% $stream_test #stream_result_canon)
|
||||
// )
|
||||
// (ap #stream_result_canon stream_gate)
|
||||
// )
|
||||
case (vr @ VarRaw(_, st @ StreamType(_)), Some(IntoIndexRaw(idx, _))) =>
|
||||
unfold(vr).flatMap {
|
||||
case (VarModel(nameVM, _, _), inl) =>
|
||||
case (vm @ VarModel(nameVM, _, _), inl) =>
|
||||
val gateRaw = ApplyGateRaw(nameVM, st, idx)
|
||||
unfold(gateRaw).flatMap { case (gateResVal, gateResInline) =>
|
||||
unfoldProperties(properties).flatMap { case (propertyModels, map) =>
|
||||
reachModelWithPropertyModels(
|
||||
gateResVal,
|
||||
propertyModels,
|
||||
inl |+| map,
|
||||
false,
|
||||
Some(gateResInline)
|
||||
)
|
||||
}
|
||||
unfold(gateRaw).flatMap {
|
||||
case (gateResVal: VarModel, gateResInline) =>
|
||||
unfoldProperties(gateResInline, gateResVal, properties, propertiesAllowed).map {
|
||||
case (v, i) =>
|
||||
(v: ValueModel) -> Inline(
|
||||
inl.flattenValues ++ i.flattenValues,
|
||||
inl.predo ++ i.predo,
|
||||
mergeMode = SeqMode
|
||||
)
|
||||
}
|
||||
case (v, i) =>
|
||||
// what if pass nil as stream argument?
|
||||
logger.error("Unreachable. Unfolded stream cannot be a literal")
|
||||
State.pure(v -> i)
|
||||
}
|
||||
case l =>
|
||||
// unreachable. Stream cannot be literal
|
||||
logger.error("Unreachable. Unfolded stream cannot be a literal")
|
||||
State.pure(l)
|
||||
}
|
||||
|
||||
case (_, _) =>
|
||||
unfold(raw).flatMap { case (vm, prevInline) =>
|
||||
unfoldProperties(properties).flatMap { case (propertyModels, map) =>
|
||||
reachModelWithPropertyModels(vm, propertyModels, prevInline |+| map, propertiesAllowed)
|
||||
}
|
||||
unfold(raw).flatMap {
|
||||
case (vm: VarModel, prevInline) =>
|
||||
unfoldProperties(prevInline, vm, properties, propertiesAllowed).map { case (v, i) =>
|
||||
(v: ValueModel) -> i
|
||||
}
|
||||
case (l: LiteralModel, inline) =>
|
||||
flatLiteralWithProperties(
|
||||
l,
|
||||
inline,
|
||||
Chain.empty
|
||||
).flatMap { (varModel, prevInline) =>
|
||||
unfoldProperties(prevInline, varModel, properties, propertiesAllowed).map {
|
||||
case (v, i) =>
|
||||
(v: ValueModel) -> i
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@ -198,44 +231,8 @@ object ApplyPropertiesRawInliner extends RawInliner[ApplyPropertyRaw] {
|
||||
override def apply[S: Mangler: Exports: Arrows](
|
||||
apr: ApplyPropertyRaw,
|
||||
propertiesAllowed: Boolean
|
||||
): State[S, (ValueModel, Inline)] =
|
||||
): State[S, (ValueModel, Inline)] = {
|
||||
val (raw, properties) = apr.unwind
|
||||
|
||||
val leftToFunctor = properties.takeWhile {
|
||||
case FunctorRaw(_, _) => false
|
||||
case _ => true
|
||||
}
|
||||
|
||||
if (leftToFunctor.length == properties.length) {
|
||||
unfoldRawWithProperties(raw, properties, propertiesAllowed)
|
||||
} else {
|
||||
// split properties like this:
|
||||
// properties -- functor -- properties with functors
|
||||
// process properties, process functor in ApplyFunctorRawInliner
|
||||
// then process tail recursively
|
||||
(for {
|
||||
ur <- properties.dropWhile {
|
||||
case FunctorRaw(_, _) => false
|
||||
case _ => true
|
||||
}.uncons
|
||||
(functor: FunctorRaw, right) = ur
|
||||
} yield {
|
||||
(leftToFunctor, functor, right)
|
||||
}).map { case (left, functor, right) =>
|
||||
for {
|
||||
vmLeftInline <- unfoldRawWithProperties(raw, left, propertiesAllowed)
|
||||
(leftVM, leftInline) = vmLeftInline
|
||||
// TODO: rewrite without `toRaw`
|
||||
fRaw = ApplyFunctorRaw(leftVM.toRaw, functor)
|
||||
vmFunctorInline <- ApplyFunctorRawInliner(fRaw, false)
|
||||
(fVM, fInline) = vmFunctorInline
|
||||
// TODO: rewrite without `toRaw`
|
||||
vmRightInline <- unfold(ApplyPropertyRaw.fromChain(fVM.toRaw, right), propertiesAllowed)
|
||||
(vm, rightInline) = vmRightInline
|
||||
} yield {
|
||||
vm -> (leftInline |+| fInline |+| rightInline)
|
||||
}
|
||||
}.getOrElse(unfoldRawWithProperties(raw, properties, propertiesAllowed))
|
||||
}
|
||||
|
||||
unfoldRawWithProperties(raw, properties, propertiesAllowed)
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,8 @@ import aqua.raw.value.CallArrowRaw
|
||||
import cats.data.{Chain, State}
|
||||
import scribe.Logging
|
||||
|
||||
import scala.collection.immutable.ListMap
|
||||
|
||||
object CallArrowRawInliner extends RawInliner[CallArrowRaw] with Logging {
|
||||
|
||||
private[inline] def unfoldArrow[S: Mangler: Exports: Arrows](
|
||||
@ -26,7 +28,7 @@ object CallArrowRawInliner extends RawInliner[CallArrowRaw] with Logging {
|
||||
cd <- callToModel(call, true)
|
||||
sd <- valueToModel(serviceId)
|
||||
} yield cd._1.exportTo.map(_.asVar.resolveWith(exports)) -> Inline(
|
||||
Map.empty,
|
||||
ListMap.empty,
|
||||
Chain(
|
||||
SeqModel.wrap(
|
||||
sd._2.toList ++
|
||||
@ -49,7 +51,7 @@ object CallArrowRawInliner extends RawInliner[CallArrowRaw] with Logging {
|
||||
.callArrowRet(fn, cm)
|
||||
.map { case (body, vars) =>
|
||||
vars -> Inline(
|
||||
Map.empty,
|
||||
ListMap.empty,
|
||||
Chain.one(SeqModel.wrap(p.toList :+ body: _*))
|
||||
)
|
||||
}
|
||||
|
@ -330,7 +330,7 @@ class ArrowInlinerSpec extends AnyFlatSpec with Matchers {
|
||||
IntoFieldRaw("field", ScalarType.string)
|
||||
)
|
||||
|
||||
val flattenObject = VarRaw("object-1", ScalarType.string)
|
||||
val flattenObject = VarRaw("object_flat", ScalarType.string)
|
||||
|
||||
// raw object
|
||||
val objectVar = VarRaw(
|
||||
@ -404,7 +404,7 @@ class ArrowInlinerSpec extends AnyFlatSpec with Matchers {
|
||||
CallModel(Nil, CallModel.Export(objectVar.name, objectVar.`type`) :: Nil)
|
||||
).leaf,
|
||||
SeqModel.wrap(
|
||||
FlattenModel(ValueModel.fromRaw(objectVarLambda), "object-1").leaf,
|
||||
FlattenModel(ValueModel.fromRaw(objectVarLambda), flattenObject.name).leaf,
|
||||
CallServiceModel(
|
||||
LiteralModel("\"callbackSrv\"", LiteralType.string),
|
||||
"response",
|
||||
|
@ -2,6 +2,7 @@ package aqua.model.inline
|
||||
|
||||
import aqua.model.inline.raw.ApplyPropertiesRawInliner
|
||||
import aqua.model.{
|
||||
EmptyModel,
|
||||
FlattenModel,
|
||||
FunctorModel,
|
||||
IntoFieldModel,
|
||||
@ -132,7 +133,7 @@ class RawValueInlinerSpec extends AnyFlatSpec with Matchers {
|
||||
"x",
|
||||
ArrayType(ScalarType.string),
|
||||
Chain.one(IntoIndexModel("y", ScalarType.string))
|
||||
) -> None
|
||||
) -> Some(EmptyModel.leaf)
|
||||
)
|
||||
}
|
||||
|
||||
@ -156,24 +157,6 @@ class RawValueInlinerSpec extends AnyFlatSpec with Matchers {
|
||||
)
|
||||
}
|
||||
|
||||
"raw value inliner" should "unfold a PropertyModel" in {
|
||||
import aqua.model.inline.state.Mangler.Simple
|
||||
// [ys!]
|
||||
ApplyPropertiesRawInliner
|
||||
.unfoldProperty[InliningState](`raw ys[0]`)
|
||||
.run(InliningState(noNames = Set("ys")))
|
||||
.value
|
||||
._2 should be(
|
||||
IntoIndexModel("ap-prop", ScalarType.string) -> Inline(
|
||||
Map(
|
||||
"ap-prop" -> VarRaw("ys", ArrayType(ScalarType.i8)).withProperty(
|
||||
IntoIndexRaw(LiteralRaw.number(0), ScalarType.i8)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
"raw value inliner" should "desugarize a single recursive raw value" in {
|
||||
// x[ys!]
|
||||
val (resVal, resTree) = valueToModel[InliningState](
|
||||
@ -187,7 +170,7 @@ class RawValueInlinerSpec extends AnyFlatSpec with Matchers {
|
||||
VarModel(
|
||||
"x",
|
||||
ArrayType(ScalarType.string),
|
||||
Chain.one(IntoIndexModel("ap-prop", ScalarType.string))
|
||||
Chain.one(IntoIndexModel("ys_flat", ScalarType.string))
|
||||
)
|
||||
)
|
||||
|
||||
@ -200,7 +183,7 @@ class RawValueInlinerSpec extends AnyFlatSpec with Matchers {
|
||||
ArrayType(ScalarType.i8),
|
||||
Chain.one(IntoIndexModel("0", ScalarType.i8))
|
||||
),
|
||||
"ap-prop"
|
||||
"ys_flat"
|
||||
).leaf
|
||||
) should be(true)
|
||||
}
|
||||
@ -215,8 +198,8 @@ class RawValueInlinerSpec extends AnyFlatSpec with Matchers {
|
||||
"x",
|
||||
ArrayType(ArrayType(ScalarType.string)),
|
||||
Chain(
|
||||
IntoIndexModel("ap-prop", ArrayType(ScalarType.string)),
|
||||
IntoIndexModel("ap-prop-0", ScalarType.string)
|
||||
IntoIndexModel("xs_flat", ArrayType(ScalarType.string)),
|
||||
IntoIndexModel("xss_flat", ScalarType.string)
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -224,79 +207,57 @@ class RawValueInlinerSpec extends AnyFlatSpec with Matchers {
|
||||
resTree.isEmpty should be(false)
|
||||
|
||||
resTree.get.equalsOrShowDiff(
|
||||
ParModel.wrap(
|
||||
SeqModel.wrap(
|
||||
SeqModel.wrap(
|
||||
SeqModel.wrap(
|
||||
SeqModel.wrap(
|
||||
FlattenModel(
|
||||
VarModel(
|
||||
"ys",
|
||||
ArrayType(ScalarType.u32)
|
||||
),
|
||||
"ys_to_functor"
|
||||
).leaf,
|
||||
FlattenModel(
|
||||
VarModel(
|
||||
"ys_to_functor",
|
||||
ArrayType(ScalarType.u32),
|
||||
Chain.one(FunctorModel("length", ScalarType.u32))
|
||||
),
|
||||
"ys_length"
|
||||
).leaf
|
||||
),
|
||||
FlattenModel(
|
||||
VarModel(
|
||||
"ys_length",
|
||||
ScalarType.u32
|
||||
),
|
||||
"ap-prop-1"
|
||||
).leaf
|
||||
),
|
||||
FlattenModel(
|
||||
VarModel(
|
||||
"xs",
|
||||
ArrayType(ScalarType.u32),
|
||||
Chain.one(IntoIndexModel("ap-prop-1", ScalarType.u32))
|
||||
"ys",
|
||||
ArrayType(ScalarType.u32)
|
||||
),
|
||||
"ap-prop"
|
||||
"ys_to_functor"
|
||||
).leaf,
|
||||
FlattenModel(
|
||||
VarModel(
|
||||
"ys_to_functor",
|
||||
ArrayType(ScalarType.u32),
|
||||
Chain.one(FunctorModel("length", ScalarType.u32))
|
||||
),
|
||||
"ys_length"
|
||||
).leaf
|
||||
),
|
||||
SeqModel.wrap(
|
||||
SeqModel.wrap(
|
||||
SeqModel.wrap(
|
||||
FlattenModel(
|
||||
VarModel(
|
||||
"yss",
|
||||
ArrayType(ScalarType.u32)
|
||||
),
|
||||
"yss_to_functor"
|
||||
).leaf,
|
||||
FlattenModel(
|
||||
VarModel(
|
||||
"yss_to_functor",
|
||||
ArrayType(ScalarType.u32),
|
||||
Chain.one(FunctorModel("length", ScalarType.u32))
|
||||
),
|
||||
"yss_length"
|
||||
).leaf
|
||||
),
|
||||
FlattenModel(
|
||||
VarModel(
|
||||
"yss_length",
|
||||
ScalarType.u32
|
||||
),
|
||||
"ap-prop-2"
|
||||
).leaf
|
||||
FlattenModel(
|
||||
VarModel(
|
||||
"xs",
|
||||
ArrayType(ScalarType.u32),
|
||||
Chain.one(IntoIndexModel("ys_length", ScalarType.u32))
|
||||
),
|
||||
"xs_flat"
|
||||
).leaf,
|
||||
SeqModel.wrap(
|
||||
FlattenModel(
|
||||
VarModel(
|
||||
"xss",
|
||||
ArrayType(ScalarType.u32),
|
||||
Chain.one(IntoIndexModel("ap-prop-2", ScalarType.u32))
|
||||
"yss",
|
||||
ArrayType(ScalarType.u32)
|
||||
),
|
||||
"ap-prop-0"
|
||||
"yss_to_functor"
|
||||
).leaf,
|
||||
FlattenModel(
|
||||
VarModel(
|
||||
"yss_to_functor",
|
||||
ArrayType(ScalarType.u32),
|
||||
Chain.one(FunctorModel("length", ScalarType.u32))
|
||||
),
|
||||
"yss_length"
|
||||
).leaf
|
||||
)
|
||||
),
|
||||
FlattenModel(
|
||||
VarModel(
|
||||
"xss",
|
||||
ArrayType(ScalarType.u32),
|
||||
Chain.one(IntoIndexModel("yss_length", ScalarType.u32))
|
||||
),
|
||||
"xss_flat"
|
||||
).leaf
|
||||
)
|
||||
) should be(true)
|
||||
}
|
||||
@ -314,8 +275,8 @@ class RawValueInlinerSpec extends AnyFlatSpec with Matchers {
|
||||
"x",
|
||||
ArrayType(ArrayType(ScalarType.string)),
|
||||
Chain(
|
||||
IntoIndexModel("ap-prop", ArrayType(ScalarType.string)),
|
||||
IntoIndexModel("ap-prop-0", ScalarType.string)
|
||||
IntoIndexModel("ys_flat", ArrayType(ScalarType.string)),
|
||||
IntoIndexModel("ys_flat-0", ScalarType.string)
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -323,14 +284,14 @@ class RawValueInlinerSpec extends AnyFlatSpec with Matchers {
|
||||
resTree.isEmpty should be(false)
|
||||
|
||||
resTree.get.equalsOrShowDiff(
|
||||
ParModel.wrap(
|
||||
SeqModel.wrap(
|
||||
FlattenModel(
|
||||
VarModel(
|
||||
"ys",
|
||||
ArrayType(ScalarType.i8),
|
||||
Chain.one(IntoIndexModel("0", ScalarType.i8))
|
||||
),
|
||||
"ap-prop"
|
||||
"ys_flat"
|
||||
).leaf,
|
||||
FlattenModel(
|
||||
VarModel(
|
||||
@ -338,7 +299,7 @@ class RawValueInlinerSpec extends AnyFlatSpec with Matchers {
|
||||
ArrayType(ScalarType.i8),
|
||||
Chain.one(IntoIndexModel("1", ScalarType.i8))
|
||||
),
|
||||
"ap-prop-0"
|
||||
"ys_flat-0"
|
||||
).leaf
|
||||
)
|
||||
) should be(true)
|
||||
@ -357,8 +318,11 @@ class RawValueInlinerSpec extends AnyFlatSpec with Matchers {
|
||||
|
||||
resVal should be(
|
||||
VarModel(
|
||||
"x_gate-0",
|
||||
ScalarType.string
|
||||
"x_gate",
|
||||
ArrayType(ScalarType.string),
|
||||
Chain(
|
||||
IntoIndexModel("ys_flat", ScalarType.string)
|
||||
)
|
||||
)
|
||||
)
|
||||
println(resTree)
|
||||
@ -394,8 +358,8 @@ class RawValueInlinerSpec extends AnyFlatSpec with Matchers {
|
||||
"x",
|
||||
ArrayType(ArrayType(ScalarType.string)),
|
||||
Chain(
|
||||
IntoIndexModel("ap-prop", ArrayType(ScalarType.string)),
|
||||
IntoIndexModel("ap-prop-0", ScalarType.string)
|
||||
IntoIndexModel("zs_flat", ArrayType(ScalarType.string)),
|
||||
IntoIndexModel("ys_flat-0", ScalarType.string)
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -403,28 +367,23 @@ class RawValueInlinerSpec extends AnyFlatSpec with Matchers {
|
||||
resTree.isEmpty should be(false)
|
||||
|
||||
resTree.get.equalsOrShowDiff(
|
||||
ParModel.wrap(
|
||||
// Prepare the zs-0 index
|
||||
SeqModel.wrap(
|
||||
// First get ys[0], save as ys-1
|
||||
FlattenModel(
|
||||
VarModel(
|
||||
"ys",
|
||||
ArrayType(ScalarType.i8),
|
||||
Chain.one(IntoIndexModel("0", ScalarType.i8))
|
||||
),
|
||||
"ap-prop-1"
|
||||
).leaf,
|
||||
// Then use that ys-1 as an index of zs
|
||||
FlattenModel(
|
||||
VarModel(
|
||||
"zs",
|
||||
ArrayType(ScalarType.i8),
|
||||
Chain.one(IntoIndexModel("ap-prop-1", ScalarType.i8))
|
||||
),
|
||||
"ap-prop"
|
||||
).leaf
|
||||
),
|
||||
SeqModel.wrap(
|
||||
FlattenModel(
|
||||
VarModel(
|
||||
"ys",
|
||||
ArrayType(ScalarType.i8),
|
||||
Chain.one(IntoIndexModel("0", ScalarType.i8))
|
||||
),
|
||||
"ys_flat"
|
||||
).leaf,
|
||||
FlattenModel(
|
||||
VarModel(
|
||||
"zs",
|
||||
ArrayType(ScalarType.i8),
|
||||
Chain.one(IntoIndexModel("ys_flat", ScalarType.i8))
|
||||
),
|
||||
"zs_flat"
|
||||
).leaf,
|
||||
// Now prepare ys-0
|
||||
FlattenModel(
|
||||
VarModel(
|
||||
@ -432,7 +391,7 @@ class RawValueInlinerSpec extends AnyFlatSpec with Matchers {
|
||||
ArrayType(ScalarType.i8),
|
||||
Chain.one(IntoIndexModel("1", ScalarType.i8))
|
||||
),
|
||||
"ap-prop-0"
|
||||
"ys_flat-0"
|
||||
).leaf
|
||||
)
|
||||
) should be(true)
|
||||
|
@ -1,6 +1,7 @@
|
||||
package aqua.raw.value
|
||||
|
||||
import aqua.types.Type
|
||||
import aqua.types.{StructType, Type}
|
||||
import cats.data.NonEmptyMap
|
||||
|
||||
sealed trait PropertyRaw {
|
||||
def `type`: Type
|
||||
@ -18,6 +19,14 @@ case class IntoFieldRaw(name: String, `type`: Type) extends PropertyRaw {
|
||||
override def varNames: Set[String] = Set.empty
|
||||
}
|
||||
|
||||
case class IntoCopyRaw(`type`: StructType, fields: NonEmptyMap[String, ValueRaw]) extends PropertyRaw {
|
||||
override def map(f: ValueRaw => ValueRaw): IntoCopyRaw = copy(fields = fields.map(f))
|
||||
|
||||
override def varNames: Set[String] = Set.empty
|
||||
|
||||
override def renameVars(vals: Map[String, String]): IntoCopyRaw = this
|
||||
}
|
||||
|
||||
case class FunctorRaw(name: String, `type`: Type) extends PropertyRaw {
|
||||
override def map(f: ValueRaw => ValueRaw): FunctorRaw = this
|
||||
|
||||
|
@ -72,21 +72,6 @@ case class ApplyPropertyRaw(value: ValueRaw, property: PropertyRaw) extends Valu
|
||||
override def varNames: Set[String] = value.varNames ++ property.varNames
|
||||
}
|
||||
|
||||
case class ApplyFunctorRaw(value: ValueRaw, functor: FunctorRaw) extends ValueRaw {
|
||||
override def baseType: Type = value.baseType
|
||||
|
||||
override def `type`: Type = functor.`type`
|
||||
|
||||
override def renameVars(map: Map[String, String]): ValueRaw =
|
||||
ApplyFunctorRaw(value.renameVars(map), functor.renameVars(map))
|
||||
|
||||
override def map(f: ValueRaw => ValueRaw): ValueRaw = f(ApplyFunctorRaw(f(value), functor.map(f)))
|
||||
|
||||
override def toString: String = s"$value.$functor"
|
||||
|
||||
override def varNames: Set[String] = value.varNames ++ functor.varNames
|
||||
}
|
||||
|
||||
object ApplyPropertyRaw {
|
||||
|
||||
def fromChain(value: ValueRaw, properties: Chain[PropertyRaw]): ValueRaw =
|
||||
|
@ -3,7 +3,7 @@ package aqua.parser.lexer
|
||||
import aqua.parser.lexer.Token.*
|
||||
import aqua.parser.lift.LiftParser
|
||||
import aqua.parser.lift.LiftParser.*
|
||||
import cats.data.NonEmptyList
|
||||
import cats.data.{NonEmptyList, NonEmptyMap}
|
||||
import cats.parse.{Numbers, Parser as P, Parser0 as P0}
|
||||
import cats.syntax.comonad.*
|
||||
import cats.syntax.functor.*
|
||||
@ -36,11 +36,24 @@ case class IntoIndex[F[_]: Comonad](point: F[Unit], idx: Option[ValueToken[F]])
|
||||
override def mapK[K[_]: Comonad](fk: F ~> K): IntoIndex[K] = copy(fk(point), idx.map(_.mapK(fk)))
|
||||
}
|
||||
|
||||
case class IntoCopy[F[_]: Comonad](point: F[Unit], fields: NonEmptyMap[String, ValueToken[F]])
|
||||
extends PropertyOp[F] {
|
||||
override def as[T](v: T): F[T] = point.as(v)
|
||||
|
||||
override def mapK[K[_]: Comonad](fk: F ~> K): IntoCopy[K] =
|
||||
copy(fk(point), fields.map(_.mapK(fk)))
|
||||
}
|
||||
|
||||
object PropertyOp {
|
||||
|
||||
private val parseField: P[PropertyOp[Span.S]] =
|
||||
(`.` *> `name`).lift.map(IntoField(_))
|
||||
|
||||
val parseCopy: P[PropertyOp[Span.S]] =
|
||||
(`.` *> (`copy`.lift ~ namedArgs)).map { case (point, fields) =>
|
||||
IntoCopy(point, NonEmptyMap.of(fields.head, fields.tail: _*))
|
||||
}
|
||||
|
||||
private val parseIdx: P[PropertyOp[Span.S]] =
|
||||
(P.defer(
|
||||
(ValueToken.`value`.between(`[`, `]`).lift | (exclamation *> ValueToken.num).lift)
|
||||
@ -55,7 +68,7 @@ object PropertyOp {
|
||||
}
|
||||
|
||||
private val parseOp: P[PropertyOp[Span.S]] =
|
||||
P.oneOf(parseField.backtrack :: parseIdx :: Nil)
|
||||
P.oneOf(parseCopy.backtrack :: parseField.backtrack :: parseIdx :: Nil)
|
||||
|
||||
val ops: P[NonEmptyList[PropertyOp[Span.S]]] =
|
||||
parseOp.rep
|
||||
|
@ -25,9 +25,9 @@ object Token {
|
||||
private val upperAnum_ = upperAnum ++ f_
|
||||
private val nl = Set('\n', '\r')
|
||||
|
||||
val inAZ = P.charIn(AZ)
|
||||
val inaz = P.charIn(az)
|
||||
val whileAnum = P.charsWhile(anum_)
|
||||
private val inAZ = P.charIn(AZ)
|
||||
private val inaz = P.charIn(az)
|
||||
private val whileAnum = P.charsWhile(anum_)
|
||||
|
||||
val ` *` : P0[String] = P.charsWhile0(fSpaces)
|
||||
val ` ` : P[String] = P.charsWhile(fSpaces)
|
||||
@ -63,6 +63,7 @@ object Token {
|
||||
val `par`: P[Unit] = P.string("par")
|
||||
val `co`: P[Unit] = P.string("co")
|
||||
val `join`: P[Unit] = P.string("join")
|
||||
val `copy`: P[Unit] = P.string("copy")
|
||||
val `:` : P[Unit] = P.char(':')
|
||||
val ` : ` : P[Unit] = P.char(':').surroundedBy(` `.?)
|
||||
val `anum_*` : P[Unit] = whileAnum.void
|
||||
@ -116,6 +117,12 @@ object Token {
|
||||
val `<-` : P[Unit] = P.string("<-")
|
||||
val `/s*` : P0[Any] = ` \n+` | ` *`
|
||||
|
||||
val namedArgs = P.defer(
|
||||
comma(
|
||||
((`name` <* (` `.?.with1 *> `=` *> ` `.?)).with1 ~ ValueToken.`value`).surroundedBy(`/s*`)
|
||||
).between(` `.?.with1 *> `(` <* `/s*`, `/s*` *> `)`)
|
||||
)
|
||||
|
||||
case class LiftToken[F[_]: Functor, A](point: F[A]) extends Token[F] {
|
||||
override def as[T](v: T): F[T] = Functor[F].as(point, v)
|
||||
|
||||
|
@ -108,11 +108,7 @@ case class StructValueToken[F[_]: Comonad](
|
||||
object StructValueToken {
|
||||
|
||||
val dataValue: P[StructValueToken[Span.S]] =
|
||||
(`Class`.lift
|
||||
~ comma(
|
||||
((`name` <* (` `.?.with1 *> `=` *> ` `.?)).with1 ~ ValueToken.`value`).surroundedBy(`/s*`)
|
||||
)
|
||||
.between(` `.?.with1 *> `(` <* `/s*`, `/s*` *> `)`))
|
||||
(`Class`.lift ~ namedArgs)
|
||||
.withContext(
|
||||
"Missing braces '()' after the struct type"
|
||||
)
|
||||
|
@ -1,8 +1,9 @@
|
||||
package aqua.parser.lexer
|
||||
|
||||
import aqua.parser.lift.LiftParser.Implicits.idLiftParser
|
||||
import aqua.types.LiteralType
|
||||
import cats.Id
|
||||
import cats.data.NonEmptyList
|
||||
import cats.data.{NonEmptyList, NonEmptyMap}
|
||||
import org.scalatest.EitherValues
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
@ -17,9 +18,44 @@ class PropertyOpSpec 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")))
|
||||
|
||||
PropertyOp.ops.parseAll("[-1]").isLeft shouldBe true
|
||||
PropertyOp.ops.parseAll("!-1").isLeft shouldBe true
|
||||
PropertyOp.ops.parseAll("[-1]").isLeft shouldBe true
|
||||
PropertyOp.ops.parseAll("!-1").isLeft shouldBe true
|
||||
|
||||
}
|
||||
|
||||
"copy ops" should "parse" in {
|
||||
val opsP = (s: String) => PropertyOp.ops.parseAll(s).value.map(_.mapK(spanToId))
|
||||
|
||||
opsP(".copy(a = \"str\", b = 12)") should be(
|
||||
NonEmptyList.of(
|
||||
IntoCopy[Id](
|
||||
(),
|
||||
NonEmptyMap.of(
|
||||
"a" -> LiteralToken("\"str\"", LiteralType.string),
|
||||
"b" -> LiteralToken("12", LiteralType.number)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
opsP(".copy(a = \"str\", b = 12).copy(c = 54, d = someVar)") should be(
|
||||
NonEmptyList.of(
|
||||
IntoCopy[Id](
|
||||
(),
|
||||
NonEmptyMap.of(
|
||||
"a" -> LiteralToken("\"str\"", LiteralType.string),
|
||||
"b" -> LiteralToken("12", LiteralType.number)
|
||||
)
|
||||
),
|
||||
IntoCopy[Id](
|
||||
(),
|
||||
NonEmptyMap.of(
|
||||
"c" -> LiteralToken("54", LiteralType.number),
|
||||
"d" -> VarToken("someVar")
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ import aqua.raw.Raw
|
||||
import aqua.raw.arrow.ArrowRaw
|
||||
import aqua.raw.ops.{SeqTag, *}
|
||||
import aqua.raw.value.{
|
||||
ApplyFunctorRaw,
|
||||
ApplyGateRaw,
|
||||
ApplyPropertyRaw,
|
||||
CallArrowRaw,
|
||||
@ -143,7 +142,6 @@ class ArrowSem[S[_]](val expr: ArrowExpr[S]) extends AnyVal {
|
||||
idx + 1
|
||||
)
|
||||
// assign and change return value for all `Apply*Raw`
|
||||
case (v: ApplyFunctorRaw, _) => assignRaw(v, idx, bodyAcc, returnAcc)
|
||||
case (v: ApplyGateRaw, _) => assignRaw(v, idx, bodyAcc, returnAcc)
|
||||
case (v: ApplyPropertyRaw, _) => assignRaw(v, idx, bodyAcc, returnAcc)
|
||||
case (v: CallArrowRaw, _) => assignRaw(v, idx, bodyAcc, returnAcc)
|
||||
|
@ -46,6 +46,15 @@ class ValuesAlgebra[S[_], Alg[_]: Monad](implicit
|
||||
op match {
|
||||
case op: IntoField[S] =>
|
||||
T.resolveField(rootType, op)
|
||||
case op: IntoCopy[S] =>
|
||||
op.fields
|
||||
.map(valueToRaw)
|
||||
.sequence
|
||||
.map(_.sequence)
|
||||
.flatMap {
|
||||
case None => None.pure[Alg]
|
||||
case Some(values) => T.resolveCopy(rootType, op, values)
|
||||
}
|
||||
case op: IntoIndex[S] =>
|
||||
op.idx
|
||||
.fold[Alg[Option[ValueRaw]]](Option(LiteralRaw.Zero).pure[Alg])(
|
||||
@ -53,7 +62,7 @@ class ValuesAlgebra[S[_], Alg[_]: Monad](implicit
|
||||
)
|
||||
.flatMap {
|
||||
case None => None.pure[Alg]
|
||||
case Some(vv) => T.resolveIndex(rootType, op, vv)
|
||||
case Some(values) => T.resolveIndex(rootType, op, values)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@ trait TypesAlgebra[S[_], Alg[_]] {
|
||||
def defineAlias(name: CustomTypeToken[S], target: Type): Alg[Boolean]
|
||||
|
||||
def resolveIndex(rootT: Type, op: IntoIndex[S], idx: ValueRaw): Alg[Option[PropertyRaw]]
|
||||
def resolveCopy(rootT: Type, op: IntoCopy[S], fields: NonEmptyMap[String, ValueRaw]): Alg[Option[PropertyRaw]]
|
||||
def resolveField(rootT: Type, op: IntoField[S]): Alg[Option[PropertyRaw]]
|
||||
|
||||
def ensureValuesComparable(token: Token[S], left: Type, right: Type): Alg[Boolean]
|
||||
|
@ -1,7 +1,7 @@
|
||||
package aqua.semantics.rules.types
|
||||
|
||||
import aqua.parser.lexer.*
|
||||
import aqua.raw.value.{FunctorRaw, IntoFieldRaw, IntoIndexRaw, PropertyRaw, ValueRaw}
|
||||
import aqua.raw.value.{FunctorRaw, IntoCopyRaw, IntoFieldRaw, IntoIndexRaw, PropertyRaw, ValueRaw}
|
||||
import aqua.semantics.lsp.{TokenDef, TokenTypeInfo}
|
||||
import aqua.semantics.rules.{ReportError, StackInterpreter}
|
||||
import aqua.types.{
|
||||
@ -158,6 +158,26 @@ class TypesInterpreter[S[_], X](implicit lens: Lens[X, TypesState[S]], error: Re
|
||||
}
|
||||
}
|
||||
|
||||
// TODO actually it's stateless, exists there just for reporting needs
|
||||
override def resolveCopy(
|
||||
rootT: Type,
|
||||
op: IntoCopy[S],
|
||||
fields: NonEmptyMap[String, ValueRaw]
|
||||
): State[X, Option[PropertyRaw]] =
|
||||
rootT match {
|
||||
case st: StructType =>
|
||||
fields.toSortedMap.toList.traverse { case (fieldName, value) =>
|
||||
st.fields.lookup(fieldName) match {
|
||||
case Some(t) =>
|
||||
ensureTypeMatches(op.fields.lookup(fieldName).getOrElse(op), t, value.`type`)
|
||||
case None => report(op, s"No field with name '$fieldName' in $rootT").as(false)
|
||||
}
|
||||
}.map(res => if (res.toList.fold(true)(_ && _)) Some(IntoCopyRaw(st, fields)) else None)
|
||||
|
||||
case _ =>
|
||||
report(op, s"Expected $rootT to be a data type").as(None)
|
||||
}
|
||||
|
||||
// TODO actually it's stateless, exists there just for reporting needs
|
||||
override def resolveIndex(
|
||||
rootT: Type,
|
||||
|
Loading…
x
Reference in New Issue
Block a user