mirror of
https://github.com/fluencelabs/aqua.git
synced 2024-12-04 22:50:18 +00:00
fix(compiler): Nested abilities [fixes LNG-214] (#816)
This commit is contained in:
parent
dba12b8277
commit
4e3e70f4fc
@ -1,11 +1,87 @@
|
||||
aqua Main
|
||||
|
||||
export a
|
||||
use DECLARE_CONST, decl_bar from "declare.aqua" as Declare
|
||||
|
||||
alias CL: string -> ()
|
||||
export SomeService, handleAb, bug214, checkAbCalls
|
||||
|
||||
func a(cl: string -> ()) -> CL:
|
||||
<- cl
|
||||
service SomeService("wed"):
|
||||
getStr(s: string) -> string
|
||||
|
||||
func b(c: u32, d: u32) -> u32:
|
||||
<- c + d
|
||||
ability SomeAb:
|
||||
someArrow(s: string) -> string, string
|
||||
str: string
|
||||
|
||||
ability SecondAb:
|
||||
arrow(s: string) -> string
|
||||
num: u32
|
||||
|
||||
func funcStr(s: string) -> string, string:
|
||||
strInFunc <- SomeService.getStr(Declare.DECLARE_CONST)
|
||||
strInFunc2 <- SomeService.getStr(s)
|
||||
<- strInFunc, strInFunc2
|
||||
|
||||
func handleSecAb {SomeAb, SecondAb}() -> string, string, string, u32:
|
||||
SomeAb.someArrow("eferfrfrf")
|
||||
b, c <- SomeAb.someArrow("efre")
|
||||
d <- SecondAb.arrow(SomeAb.str)
|
||||
<- b, c, d, SecondAb.num
|
||||
|
||||
func returnAb(s: string) -> SomeAb:
|
||||
SomeAb = SomeAb(someArrow = funcStr, str = s)
|
||||
<- SomeAb
|
||||
|
||||
func handleAb(fff: string) -> string, string, string, u32:
|
||||
SomeAb = returnAb(fff)
|
||||
SecondAb = SecondAb(arrow = funcStr, num = 12)
|
||||
res1, res2, res3, res4 <- handleSecAb{SomeAb, SecondAb}()
|
||||
<- res1, res2, res3, res4
|
||||
|
||||
data Struct:
|
||||
int: i8
|
||||
|
||||
ability Simple:
|
||||
st: Struct
|
||||
arrow(x: i8) -> bool
|
||||
|
||||
ability Complex:
|
||||
simple: Simple
|
||||
field: string
|
||||
|
||||
func foo{Complex, Simple}() -> bool, bool:
|
||||
closure = () -> bool:
|
||||
<- Simple.st.int >= 0
|
||||
res <- closure()
|
||||
<- Complex.simple.arrow(
|
||||
Complex.simple.st.int
|
||||
), res
|
||||
|
||||
func bug214() -> bool, bool:
|
||||
closure = (x: i8) -> bool:
|
||||
<- x > 0
|
||||
|
||||
MyComplex = Complex(
|
||||
simple = Simple(
|
||||
st = Struct(int = 0),
|
||||
arrow = closure
|
||||
),
|
||||
field = "complex"
|
||||
)
|
||||
|
||||
res1, res2 <- foo{MyComplex, MyComplex.simple}()
|
||||
<- res1, res2
|
||||
|
||||
ability SSS:
|
||||
arrow(x: i8) -> bool
|
||||
|
||||
ability CCCC:
|
||||
arrow(x: i8) -> bool
|
||||
simple: SSS
|
||||
|
||||
func checkAbCalls() -> bool, bool:
|
||||
closure = (x: i8) -> bool:
|
||||
<- x > 20
|
||||
|
||||
MySSS = SSS(arrow = closure)
|
||||
MyCCCC = CCCC(simple = MySSS, arrow = MySSS.arrow)
|
||||
|
||||
<- MySSS.arrow(42), MyCCCC.arrow(12)
|
||||
|
@ -2,7 +2,7 @@ aqua Main
|
||||
|
||||
use DECLARE_CONST, decl_bar from "imports_exports/declare.aqua" as Declare
|
||||
|
||||
export handleAb, SomeService
|
||||
export handleAb, SomeService, bug214, checkAbCalls
|
||||
|
||||
service SomeService("wed"):
|
||||
getStr(s: string) -> string
|
||||
@ -35,3 +35,53 @@ func handleAb(fff: string) -> string, string, string, u32:
|
||||
SecondAb = SecondAb(arrow = funcStr, num = 12)
|
||||
res1, res2, res3, res4 <- handleSecAb{SomeAb, SecondAb}()
|
||||
<- res1, res2, res3, res4
|
||||
|
||||
data Struct:
|
||||
int: i8
|
||||
|
||||
ability Simple:
|
||||
st: Struct
|
||||
arrow(x: i8) -> bool
|
||||
|
||||
ability Complex:
|
||||
simple: Simple
|
||||
field: string
|
||||
|
||||
func foo{Complex, Simple}() -> bool, bool:
|
||||
closure = () -> bool:
|
||||
<- Simple.st.int >= 0
|
||||
res <- closure()
|
||||
<- Complex.simple.arrow(
|
||||
Complex.simple.st.int
|
||||
), res
|
||||
|
||||
func bug214() -> bool, bool:
|
||||
closure = (x: i8) -> bool:
|
||||
<- x > 0
|
||||
|
||||
MyComplex = Complex(
|
||||
simple = Simple(
|
||||
st = Struct(int = 0),
|
||||
arrow = closure
|
||||
),
|
||||
field = "complex"
|
||||
)
|
||||
|
||||
res1, res2 <- foo{MyComplex, MyComplex.simple}()
|
||||
<- res1, res2
|
||||
|
||||
ability SSS:
|
||||
arrow(x: i8) -> bool
|
||||
|
||||
ability CCCC:
|
||||
arrow(x: i8) -> bool
|
||||
simple: SSS
|
||||
|
||||
func checkAbCalls() -> bool, bool:
|
||||
closure = (x: i8) -> bool:
|
||||
<- x > 20
|
||||
|
||||
MySSS = SSS(arrow = closure)
|
||||
MyCCCC = CCCC(simple = MySSS, arrow = MySSS.arrow)
|
||||
|
||||
<- MySSS.arrow(42), MyCCCC.arrow(12)
|
||||
|
@ -13,6 +13,7 @@ import { bugNG69Call, ifCall, ifWrapCall } from '../examples/ifCall.js';
|
||||
import { parCall, testTimeoutCall } from '../examples/parCall.js';
|
||||
import { complexCall } from '../examples/complex.js';
|
||||
import { constantsCall, particleTtlAndTimestampCall } from '../examples/constantsCall.js';
|
||||
import { abilityCall, complexAbilityCall, checkAbCallsCall } from '../examples/abilityCall.js';
|
||||
import {
|
||||
nilLengthCall,
|
||||
nilLiteralCall,
|
||||
@ -77,7 +78,6 @@ export const relay2 = config.relays[1];
|
||||
const relayPeerId2 = relay2.peerId;
|
||||
|
||||
import log from 'loglevel';
|
||||
import { abilityCall } from '../examples/abilityCall';
|
||||
// log.setDefaultLevel("debug")
|
||||
|
||||
async function start() {
|
||||
@ -354,6 +354,16 @@ describe('Testing examples', () => {
|
||||
expect(result).toStrictEqual(['declare_const123', 'efre123', 'declare_const123', 12]);
|
||||
});
|
||||
|
||||
it('ability.aqua complex', async () => {
|
||||
let result = await complexAbilityCall();
|
||||
expect(result).toStrictEqual([false, true]);
|
||||
});
|
||||
|
||||
it('ability.aqua complex', async () => {
|
||||
let result = await checkAbCallsCall();
|
||||
expect(result).toStrictEqual([true, false]);
|
||||
});
|
||||
|
||||
it('functors.aqua LNG-119 bug', async () => {
|
||||
let result = await bugLng119Call();
|
||||
expect(result).toEqual([1]);
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {handleAb, registerSomeService} from "../compiled/examples/abilities";
|
||||
import {handleAb, registerSomeService, bug214, checkAbCalls} from "../compiled/examples/abilities";
|
||||
|
||||
export async function abilityCall(): Promise<[string, string, string, number]> {
|
||||
registerSomeService({
|
||||
@ -9,3 +9,11 @@ export async function abilityCall(): Promise<[string, string, string, number]> {
|
||||
|
||||
return await handleAb("some_string")
|
||||
}
|
||||
|
||||
export async function complexAbilityCall(): Promise<[boolean, boolean]> {
|
||||
return await bug214()
|
||||
}
|
||||
|
||||
export async function checkAbCallsCall(): Promise<[boolean, boolean]> {
|
||||
return await checkAbCalls()
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import aqua.model.*
|
||||
import aqua.raw.ops.RawTag
|
||||
import aqua.types.{AbilityType, ArrowType, BoxType, DataType, StreamType, Type}
|
||||
import aqua.raw.value.{ValueRaw, VarRaw}
|
||||
import cats.Eval
|
||||
import cats.{Eval, Monoid}
|
||||
import cats.data.{Chain, IndexedStateT, State}
|
||||
import cats.syntax.traverse.*
|
||||
import cats.syntax.apply.*
|
||||
@ -91,59 +91,50 @@ object ArrowInliner extends Logging {
|
||||
// Apply a callable function, get its fully resolved body & optional value, if any
|
||||
private def inline[S: Mangler: Arrows: Exports](
|
||||
fn: FuncArrow,
|
||||
call: CallModel
|
||||
call: CallModel,
|
||||
outsideDeclaredStreams: Set[String]
|
||||
): State[S, InlineResult] =
|
||||
(Exports[S].exports, getOutsideStreamNames).flatMapN {
|
||||
case (oldExports, outsideDeclaredStreams) =>
|
||||
// Function's internal variables will not be available outside, hence the scope
|
||||
Exports[S].scope(
|
||||
for {
|
||||
// Process renamings, prepare environment
|
||||
tr <- prelude[S](fn, call, oldExports)
|
||||
(tree, results) = tr
|
||||
for {
|
||||
// Register captured values as available exports
|
||||
_ <- Exports[S].resolved(fn.capturedValues)
|
||||
_ <- Mangler[S].forbid(fn.capturedValues.keySet)
|
||||
|
||||
// Register captured values as available exports
|
||||
_ <- Exports[S].resolved(fn.capturedValues)
|
||||
_ <- Mangler[S].forbid(fn.capturedValues.keySet)
|
||||
// Now, substitute the arrows that were received as function arguments
|
||||
// Use the new op tree (args are replaced with values, names are unique & safe)
|
||||
callableFuncBodyNoTopology <- TagInliner.handleTree(fn.body, fn.funcName)
|
||||
callableFuncBody =
|
||||
fn.capturedTopology
|
||||
.fold[OpModel](SeqModel)(ApplyTopologyModel.apply)
|
||||
.wrap(callableFuncBodyNoTopology)
|
||||
|
||||
// Now, substitute the arrows that were received as function arguments
|
||||
// Use the new op tree (args are replaced with values, names are unique & safe)
|
||||
callableFuncBodyNoTopology <- TagInliner.handleTree(tree, fn.funcName)
|
||||
callableFuncBody =
|
||||
fn.capturedTopology
|
||||
.fold[OpModel](SeqModel)(ApplyTopologyModel.apply)
|
||||
.wrap(callableFuncBodyNoTopology)
|
||||
opsAndRets <- pushStreamResults(
|
||||
outsideDeclaredStreams,
|
||||
call.exportTo,
|
||||
fn.ret,
|
||||
callableFuncBody
|
||||
)
|
||||
(ops, rets) = opsAndRets
|
||||
|
||||
opsAndRets <- pushStreamResults(
|
||||
outsideDeclaredStreams,
|
||||
call.exportTo,
|
||||
results,
|
||||
callableFuncBody
|
||||
)
|
||||
(ops, rets) = opsAndRets
|
||||
exports <- Exports[S].exports
|
||||
arrows <- Arrows[S].arrows
|
||||
// gather all arrows and variables from abilities
|
||||
returnedFromAbilities = rets.collect { case VarModel(name, st @ AbilityType(_, _), _) =>
|
||||
getVarsAndArrowsFromAbilities(name, None, st, exports, arrows)
|
||||
}.foldMapA(_.bimap(_.toList, _.toList)).bimap(_.toMap, _.toMap)
|
||||
|
||||
exports <- Exports[S].exports
|
||||
arrows <- Arrows[S].arrows
|
||||
// gather all arrows and variables from abilities
|
||||
returnedFromAbilities = rets.collect { case VarModel(name, st @ AbilityType(_, _), _) =>
|
||||
getVarsAndArrowsFromAbilities(name, None, st, exports, arrows)
|
||||
}.foldMapA(_.bimap(_.toList, _.toList)).bimap(_.toMap, _.toMap)
|
||||
|
||||
// find and get resolved arrows if we return them from the function
|
||||
returnedArrows = rets.collect { case VarModel(name, ArrowType(_, _), _) =>
|
||||
name
|
||||
}.toSet
|
||||
arrowsToSave <- Arrows[S].pickArrows(returnedArrows)
|
||||
} yield {
|
||||
val (valsFromAbilities, arrowsFromAbilities) = returnedFromAbilities
|
||||
InlineResult(
|
||||
SeqModel.wrap(ops.reverse: _*),
|
||||
rets.reverse,
|
||||
valsFromAbilities,
|
||||
arrowsFromAbilities ++ arrowsToSave
|
||||
)
|
||||
}
|
||||
)
|
||||
// find and get resolved arrows if we return them from the function
|
||||
returnedArrows = rets.collect { case VarModel(name, ArrowType(_, _), _) =>
|
||||
name
|
||||
}.toSet
|
||||
arrowsToSave <- Arrows[S].pickArrows(returnedArrows)
|
||||
} yield {
|
||||
val (valsFromAbilities, arrowsFromAbilities) = returnedFromAbilities
|
||||
InlineResult(
|
||||
SeqModel.wrap(ops.reverse: _*),
|
||||
rets.reverse,
|
||||
valsFromAbilities,
|
||||
arrowsFromAbilities ++ arrowsToSave
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -243,32 +234,47 @@ object ArrowInliner extends Logging {
|
||||
renamedArrows: Map[String, FuncArrow]
|
||||
)
|
||||
|
||||
given Monoid[AbilityResolvingResult] with
|
||||
|
||||
override val empty: AbilityResolvingResult =
|
||||
AbilityResolvingResult(Map.empty, Map.empty, Map.empty)
|
||||
|
||||
override def combine(
|
||||
a: AbilityResolvingResult,
|
||||
b: AbilityResolvingResult
|
||||
): AbilityResolvingResult =
|
||||
AbilityResolvingResult(
|
||||
a.namesToRename ++ b.namesToRename,
|
||||
a.renamedExports ++ b.renamedExports,
|
||||
a.renamedArrows ++ b.renamedArrows
|
||||
)
|
||||
|
||||
/**
|
||||
* Generate new names for all ability fields and arrows if necessary.
|
||||
* Gather all fields and arrows from Arrows and Exports states
|
||||
* @param name ability name in state
|
||||
* @param vm ability variable
|
||||
* @param t ability type
|
||||
* @param oldExports previous Exports
|
||||
* @param oldArrows previous Arrows
|
||||
* @param exports previous Exports
|
||||
* @param arrows previous Arrows
|
||||
* @return names to rename, Exports and Arrows with all ability fields and arrows
|
||||
*/
|
||||
private def renameAndResolveAbilities[S: Mangler: Arrows: Exports](
|
||||
name: String,
|
||||
vm: VarModel,
|
||||
t: AbilityType,
|
||||
oldExports: Map[String, ValueModel],
|
||||
oldArrows: Map[String, FuncArrow]
|
||||
exports: Map[String, ValueModel],
|
||||
arrows: Map[String, FuncArrow]
|
||||
): State[S, AbilityResolvingResult] = {
|
||||
for {
|
||||
newName <- Mangler[S].findNewName(name)
|
||||
newFieldsName = t.fields.mapBoth { case (n, t) =>
|
||||
s"$name.$n" -> s"$newName.$n"
|
||||
AbilityType.fullName(name, n) -> AbilityType.fullName(newName, n)
|
||||
}
|
||||
allNewNames = newFieldsName.add((name, newName)).toSortedMap
|
||||
} yield {
|
||||
val (allVars, allArrows) =
|
||||
getVarsAndArrowsFromAbilities(vm.name, Option(newName), t, oldExports, oldArrows)
|
||||
getVarsAndArrowsFromAbilities(vm.name, Option(newName), t, exports, arrows)
|
||||
AbilityResolvingResult(allNewNames, allVars, allArrows)
|
||||
}
|
||||
}
|
||||
@ -281,58 +287,50 @@ object ArrowInliner extends Logging {
|
||||
* @param topOldName old name to find all fields in states
|
||||
* @param topNewName new name to rename all fields in states
|
||||
* @param abilityType type of current ability
|
||||
* @param oldExports where to get values
|
||||
* @param oldArrows where to get arrows
|
||||
* @param valAcc accumulator for values
|
||||
* @param arrowsAcc accumulator for arrows
|
||||
* @param exports where to get values
|
||||
* @param arrows where to get arrows
|
||||
* @return
|
||||
*/
|
||||
private def getVarsAndArrowsFromAbilities(
|
||||
topOldName: String,
|
||||
topNewName: Option[String],
|
||||
abilityType: AbilityType,
|
||||
oldExports: Map[String, ValueModel],
|
||||
oldArrows: Map[String, FuncArrow],
|
||||
valAcc: Map[String, ValueModel] = Map.empty,
|
||||
arrowsAcc: Map[String, FuncArrow] = Map.empty
|
||||
exports: Map[String, ValueModel],
|
||||
arrows: Map[String, FuncArrow]
|
||||
): (Map[String, ValueModel], Map[String, FuncArrow]) = {
|
||||
abilityType.fields.toSortedMap.toList.map { case (fName, fValue) =>
|
||||
val currentOldName = s"$topOldName.$fName"
|
||||
val currentOldName = AbilityType.fullName(topOldName, fName)
|
||||
// for all nested fields, arrows and abilities only left side must be renamed
|
||||
val currentNewName = topNewName.map(_ + s".$fName")
|
||||
val currentNewName = topNewName.map(AbilityType.fullName(_, fName))
|
||||
fValue match {
|
||||
case nestedAbilityType @ AbilityType(_, _) =>
|
||||
getVarsAndArrowsFromAbilities(
|
||||
currentOldName,
|
||||
currentNewName,
|
||||
nestedAbilityType,
|
||||
oldExports,
|
||||
oldArrows,
|
||||
valAcc,
|
||||
arrowsAcc
|
||||
exports,
|
||||
arrows
|
||||
)
|
||||
case ArrowType(_, _) =>
|
||||
oldExports
|
||||
.get(currentOldName)
|
||||
.flatMap {
|
||||
case vm @ VarModel(name, _, _) =>
|
||||
oldArrows
|
||||
.get(name)
|
||||
.map(fa =>
|
||||
(
|
||||
valAcc.updated(currentNewName.getOrElse(currentOldName), vm),
|
||||
arrowsAcc.updated(name, fa)
|
||||
)
|
||||
Exports
|
||||
.getLastValue(currentOldName, exports)
|
||||
.flatMap { case vm @ VarModel(name, _, _) =>
|
||||
arrows
|
||||
.get(name)
|
||||
.map(fa =>
|
||||
(
|
||||
Map(currentNewName.getOrElse(currentOldName) -> vm),
|
||||
Map(name -> fa)
|
||||
)
|
||||
case _ => None
|
||||
)
|
||||
}
|
||||
.getOrElse((valAcc, arrowsAcc))
|
||||
.getOrElse((Map.empty, Map.empty))
|
||||
|
||||
case _ =>
|
||||
oldExports
|
||||
.get(currentOldName)
|
||||
.map(vm => (valAcc.updated(currentNewName.getOrElse(currentOldName), vm), arrowsAcc))
|
||||
.getOrElse((valAcc, arrowsAcc))
|
||||
Exports
|
||||
.getLastValue(currentOldName, exports)
|
||||
.map(vm => (Map(currentNewName.getOrElse(currentOldName) -> vm), Map.empty))
|
||||
.getOrElse((Map.empty, Map.empty))
|
||||
}
|
||||
}.foldMapA(_.bimap(_.toList, _.toList)).bimap(_.toMap, _.toMap)
|
||||
}
|
||||
@ -352,7 +350,8 @@ object ArrowInliner extends Logging {
|
||||
private def prelude[S: Mangler: Arrows: Exports](
|
||||
fn: FuncArrow,
|
||||
call: CallModel,
|
||||
oldExports: Map[String, ValueModel]
|
||||
oldExports: Map[String, ValueModel],
|
||||
arrows: Map[String, FuncArrow]
|
||||
): State[S, (RawTag.Tree, List[ValueRaw])] =
|
||||
for {
|
||||
// Collect all arguments: what names are used inside the function, what values are received
|
||||
@ -360,24 +359,47 @@ object ArrowInliner extends Logging {
|
||||
|
||||
abArgs = args.abilityArgs
|
||||
|
||||
// Going to resolve arrows: collect them all. Names should never collide: it's semantically checked
|
||||
previousArrowsState <- Arrows[S].arrows
|
||||
|
||||
_ <- Arrows[S].purge
|
||||
|
||||
abilityResolvingResult <- abArgs.toList.traverse { case (str, (vm, sct)) =>
|
||||
renameAndResolveAbilities(str, vm, sct, oldExports, previousArrowsState)
|
||||
}
|
||||
renameAndResolveAbilities(str, vm, sct, oldExports, arrows)
|
||||
}.map(_.combineAll)
|
||||
|
||||
absRenames = abilityResolvingResult.map(_.namesToRename).fold(Map.empty)(_ ++ _)
|
||||
absVars = abilityResolvingResult.map(_.renamedExports).fold(Map.empty)(_ ++ _)
|
||||
absArrows = abilityResolvingResult.map(_.renamedArrows).fold(Map.empty)(_ ++ _)
|
||||
absRenames = abilityResolvingResult.namesToRename
|
||||
absVars = abilityResolvingResult.renamedExports
|
||||
absArrows = abilityResolvingResult.renamedArrows
|
||||
|
||||
arrowArgs = args.arrowArgs(previousArrowsState)
|
||||
arrowArgs = args.arrowArgs(arrows)
|
||||
// Update states and rename tags
|
||||
renamedArrows <- updateArrowsAndRenameArrowArgs(arrowArgs ++ absArrows, fn, absRenames)
|
||||
|
||||
argsToDataShouldRename <- updateExportsAndRenameDataArgs(args.dataArgs ++ absVars, absRenames)
|
||||
allShouldRename = argsToDataShouldRename ++ renamedArrows ++ absRenames
|
||||
|
||||
// rename variables that store arrows
|
||||
_ <- Exports[S].renameVariables(renamedArrows)
|
||||
|
||||
/*
|
||||
* Don't rename arrows from abilities in a body, because we link arrows by VarModel
|
||||
* and they won't be called directly.
|
||||
* They could intersect with arrows defined inside the body
|
||||
*
|
||||
* ability Simple:
|
||||
* arrow() -> bool
|
||||
*
|
||||
* func foo{Simple}() -> bool, bool:
|
||||
* closure = () -> bool:
|
||||
* <- true
|
||||
* <- closure(), Simple.arrow()
|
||||
*
|
||||
* func main() -> bool, bool:
|
||||
* closure = () -> bool:
|
||||
* <- false
|
||||
* MySimple = Simple(arrow = closure)
|
||||
* -- here we will rename arrow in Arrows[S] to 'closure-0'
|
||||
* -- and link to arrow as 'Simple.arrow' -> VarModel('closure-0')
|
||||
* -- and it will work well with closure with the same name 'closure' inside 'foo'
|
||||
* foo{MySimple}()
|
||||
*/
|
||||
allShouldRename = argsToDataShouldRename ++ (renamedArrows -- absArrows.keySet) ++ absRenames
|
||||
|
||||
// Rename all renamed arguments in the body
|
||||
treeRenamed = fn.body.rename(allShouldRename)
|
||||
treeStreamsRenamed = renameStreams(treeRenamed, args.streamArgs)
|
||||
@ -415,8 +437,7 @@ object ArrowInliner extends Logging {
|
||||
} yield {
|
||||
sc.fields.toSortedMap.toList.flatMap {
|
||||
case (n, ArrowType(_, _)) =>
|
||||
val fullName = s"$name.$n"
|
||||
exports.get(fullName).flatMap {
|
||||
exports.get(AbilityType.fullName(name, n)).flatMap {
|
||||
case VarModel(n, _, _) => arrows.get(n).map(n -> _)
|
||||
case _ => None
|
||||
}
|
||||
@ -435,11 +456,22 @@ object ArrowInliner extends Logging {
|
||||
.traverse(getAllArrowsFromAbility)
|
||||
.map(_.fold(Map.empty)(_ ++ _))
|
||||
|
||||
inlineResult <- Arrows[S].scope(
|
||||
for {
|
||||
_ <- Arrows[S].resolved(passArrows ++ arrowsFromAbilities)
|
||||
inlineResult <- ArrowInliner.inline(arrow, call)
|
||||
} yield inlineResult
|
||||
exports <- Exports[S].exports
|
||||
streams <- getOutsideStreamNames
|
||||
|
||||
inlineResult <- Exports[S].scope(
|
||||
Arrows[S].scope(
|
||||
for {
|
||||
// Process renamings, prepare environment
|
||||
tr <- prelude[S](arrow, call, exports, passArrows ++ arrowsFromAbilities)
|
||||
(tree, results) = tr
|
||||
inlineResult <- ArrowInliner.inline(
|
||||
arrow.copy(body = tree, ret = results),
|
||||
call,
|
||||
streams
|
||||
)
|
||||
} yield inlineResult
|
||||
)
|
||||
)
|
||||
|
||||
_ <- Arrows[S].resolved(inlineResult.arrowsToSave)
|
||||
|
@ -329,19 +329,19 @@ object TagInliner extends Logging {
|
||||
}
|
||||
|
||||
case AssignmentTag(value, assignTo) =>
|
||||
(value match {
|
||||
// if we assign collection to a stream, we must use it's name, because it is already created with 'new'
|
||||
case c @ CollectionRaw(_, _: StreamType) =>
|
||||
collectionToModel(c, Some(assignTo))
|
||||
case v =>
|
||||
valueToModel(v, false)
|
||||
}).flatMap { case (model, prefix) =>
|
||||
for {
|
||||
// NOTE: Name <assignTo> should not exist yet
|
||||
_ <- Mangler[S].forbidName(assignTo)
|
||||
_ <- Exports[S].resolved(assignTo, model)
|
||||
} yield TagInlined.Empty(prefix = prefix)
|
||||
}
|
||||
for {
|
||||
// NOTE: Name <assignTo> should not exist yet
|
||||
_ <- Mangler[S].forbidName(assignTo)
|
||||
modelAndPrefix <- value match {
|
||||
// if we assign collection to a stream, we must use it's name, because it is already created with 'new'
|
||||
case c @ CollectionRaw(_, _: StreamType) =>
|
||||
collectionToModel(c, Some(assignTo))
|
||||
case v =>
|
||||
valueToModel(v, false)
|
||||
}
|
||||
(model, prefix) = modelAndPrefix
|
||||
_ <- Exports[S].resolved(assignTo, model)
|
||||
} yield TagInlined.Empty(prefix = prefix)
|
||||
|
||||
case ClosureTag(arrow, detach) =>
|
||||
if (detach) Arrows[S].resolved(arrow, None).as(TagInlined.Empty())
|
||||
|
@ -1,62 +1,21 @@
|
||||
package aqua.model.inline.raw
|
||||
|
||||
import aqua.model.{
|
||||
CallModel,
|
||||
CallServiceModel,
|
||||
FlattenModel,
|
||||
ForModel,
|
||||
FunctorModel,
|
||||
IntoFieldModel,
|
||||
IntoIndexModel,
|
||||
LiteralModel,
|
||||
MatchMismatchModel,
|
||||
NextModel,
|
||||
OpModel,
|
||||
PropertyModel,
|
||||
PushToStreamModel,
|
||||
SeqModel,
|
||||
ValueModel,
|
||||
VarModel,
|
||||
XorModel
|
||||
}
|
||||
import aqua.model.*
|
||||
import aqua.model.ValueModel.Ability
|
||||
import aqua.model.inline.Inline
|
||||
import aqua.model.inline.Inline.MergeMode.*
|
||||
import aqua.model.inline.RawValueInliner.unfold
|
||||
import aqua.model.inline.state.{Arrows, Exports, Mangler}
|
||||
import aqua.raw.value.{
|
||||
ApplyGateRaw,
|
||||
ApplyPropertyRaw,
|
||||
CallArrowRaw,
|
||||
FunctorRaw,
|
||||
IntoArrowRaw,
|
||||
IntoCopyRaw,
|
||||
IntoFieldRaw,
|
||||
IntoIndexRaw,
|
||||
LiteralRaw,
|
||||
PropertyRaw,
|
||||
ValueRaw,
|
||||
VarRaw
|
||||
}
|
||||
import aqua.types.{
|
||||
AbilityType,
|
||||
ArrayType,
|
||||
ArrowType,
|
||||
BottomType,
|
||||
CanonStreamType,
|
||||
NilType,
|
||||
ScalarType,
|
||||
StreamType,
|
||||
Type
|
||||
}
|
||||
|
||||
import aqua.raw.value.*
|
||||
import aqua.types.*
|
||||
import cats.Eval
|
||||
import cats.syntax.bifunctor.*
|
||||
import cats.data.{Chain, IndexedStateT, State}
|
||||
import cats.instances.list.*
|
||||
import cats.syntax.applicative.*
|
||||
import cats.syntax.bifunctor.*
|
||||
import cats.syntax.foldable.*
|
||||
import cats.syntax.monoid.*
|
||||
import cats.syntax.traverse.*
|
||||
import cats.syntax.foldable.*
|
||||
import cats.Id
|
||||
import cats.instances.list.*
|
||||
import scribe.Logging
|
||||
|
||||
object ApplyPropertiesRawInliner extends RawInliner[ApplyPropertyRaw] with Logging {
|
||||
@ -100,12 +59,12 @@ object ApplyPropertiesRawInliner extends RawInliner[ApplyPropertyRaw] with Loggi
|
||||
|
||||
private def unfoldAbilityProperty[S: Mangler: Exports: Arrows](
|
||||
varModel: VarModel,
|
||||
scopeType: AbilityType,
|
||||
abilityType: AbilityType,
|
||||
p: PropertyRaw
|
||||
): State[S, (VarModel, Inline)] = {
|
||||
p match {
|
||||
case IntoArrowRaw(arrowName, t, arguments) =>
|
||||
val arrowType = scopeType.fields
|
||||
val arrowType = abilityType.fields
|
||||
.lookup(arrowName)
|
||||
.collect { case at @ ArrowType(_, _) =>
|
||||
at
|
||||
@ -116,7 +75,13 @@ object ApplyPropertiesRawInliner extends RawInliner[ApplyPropertyRaw] with Loggi
|
||||
}
|
||||
for {
|
||||
callArrow <- CallArrowRawInliner(
|
||||
CallArrowRaw(None, s"${varModel.name}.$arrowName", arguments, arrowType, None)
|
||||
CallArrowRaw(
|
||||
None,
|
||||
AbilityType.fullName(varModel.name, arrowName),
|
||||
arguments,
|
||||
arrowType,
|
||||
None
|
||||
)
|
||||
)
|
||||
result <- callArrow match {
|
||||
case (vm: VarModel, inl) =>
|
||||
@ -129,21 +94,25 @@ object ApplyPropertiesRawInliner extends RawInliner[ApplyPropertyRaw] with Loggi
|
||||
} yield {
|
||||
result
|
||||
}
|
||||
|
||||
case IntoFieldRaw(fieldName, at @ AbilityType(abName, fields)) =>
|
||||
(VarModel(AbilityType.fullName(varModel.name, fieldName), at), Inline.empty).pure
|
||||
case IntoFieldRaw(fieldName, t) =>
|
||||
for {
|
||||
exports <- Exports[S].exports
|
||||
fullName = s"${varModel.name}.$fieldName"
|
||||
result <- exports.get(fullName) match {
|
||||
abilityField <- Exports[S].getAbilityField(varModel.name, fieldName)
|
||||
result <- abilityField match {
|
||||
case Some(vm: VarModel) =>
|
||||
State.pure((vm, Inline.empty))
|
||||
case Some(lm: LiteralModel) =>
|
||||
flatLiteralWithProperties(lm, Inline.empty, Chain.empty)
|
||||
case _ =>
|
||||
logger.error(
|
||||
s"Inlining, cannot find field $fullName in ability $varModel. Available: ${exports.keySet}"
|
||||
)
|
||||
flatLiteralWithProperties(LiteralModel.quote(""), Inline.empty, Chain.empty)
|
||||
Exports[S].getKeys.flatMap { keys =>
|
||||
logger.error(
|
||||
s"Inlining, cannot find field ${AbilityType
|
||||
.fullName(varModel.name, fieldName)} in ability $varModel. Available: $keys"
|
||||
)
|
||||
flatLiteralWithProperties(LiteralModel.quote(""), Inline.empty, Chain.empty)
|
||||
}
|
||||
|
||||
}
|
||||
} yield {
|
||||
result
|
||||
@ -246,8 +215,8 @@ object ApplyPropertiesRawInliner extends RawInliner[ApplyPropertyRaw] with Loggi
|
||||
State.pure((vm, prevInline.mergeWith(optimizationInline, SeqMode)))
|
||||
) { case (state, property) =>
|
||||
state.flatMap {
|
||||
case (vm @ VarModel(name, st @ AbilityType(_, _), _), leftInline) =>
|
||||
unfoldAbilityProperty(vm, st, property.raw).map { case (vm, inl) =>
|
||||
case (vm @ Ability(name, at, _), leftInline) =>
|
||||
unfoldAbilityProperty(vm, at, property.raw).map { case (vm, inl) =>
|
||||
(
|
||||
vm,
|
||||
Inline(
|
||||
|
@ -76,16 +76,12 @@ object CallArrowRawInliner extends RawInliner[CallArrowRaw] with Logging {
|
||||
): State[S, (List[ValueModel], Inline)] = for {
|
||||
arrows <- Arrows[S].arrows
|
||||
exports <- Exports[S].exports
|
||||
lastArrow <- Exports[S].getLast(funcName)
|
||||
arrow = arrows
|
||||
.get(funcName)
|
||||
.orElse(
|
||||
// if there is no arrow, check if it is stored in Exports as variable and try to resolve it
|
||||
exports
|
||||
.get(funcName)
|
||||
.collect { case VarModel(name, _: ArrowType, _) =>
|
||||
name
|
||||
}
|
||||
.flatMap(arrows.get)
|
||||
lastArrow.flatMap(arrows.get)
|
||||
)
|
||||
result <- arrow.fold {
|
||||
logger.error(
|
||||
|
@ -1,31 +1,33 @@
|
||||
package aqua.model.inline.raw
|
||||
|
||||
import aqua.model.{
|
||||
CallModel,
|
||||
CallServiceModel,
|
||||
LiteralModel,
|
||||
OpModel,
|
||||
SeqModel,
|
||||
ValueModel,
|
||||
VarModel
|
||||
}
|
||||
import aqua.model.inline.raw.RawInliner
|
||||
import cats.data.Chain
|
||||
import aqua.model.inline.state.{Arrows, Exports, Mangler}
|
||||
import aqua.raw.value.{AbilityRaw, LiteralRaw, MakeStructRaw}
|
||||
import cats.data.{NonEmptyList, NonEmptyMap, State}
|
||||
import aqua.model.inline.Inline
|
||||
import aqua.model.inline.RawValueInliner.{unfold, valueToModel}
|
||||
import aqua.types.{ArrowType, ScalarType}
|
||||
import cats.syntax.traverse.*
|
||||
import cats.syntax.monoid.*
|
||||
import cats.syntax.functor.*
|
||||
import cats.syntax.flatMap.*
|
||||
import cats.syntax.apply.*
|
||||
import aqua.model.inline.RawValueInliner.unfold
|
||||
import aqua.model.inline.state.{Arrows, Exports, Mangler}
|
||||
import aqua.model.{SeqModel, ValueModel, VarModel}
|
||||
import aqua.raw.value.AbilityRaw
|
||||
import aqua.types.AbilityType
|
||||
import aqua.model.ValueModel.Ability
|
||||
import cats.Eval
|
||||
import cats.data.{Chain, IndexedStateT, NonEmptyMap, State}
|
||||
import cats.syntax.foldable.*
|
||||
|
||||
object MakeAbilityRawInliner extends RawInliner[AbilityRaw] {
|
||||
|
||||
private def updateFields[S: Mangler: Exports: Arrows](
|
||||
name: String,
|
||||
fields: NonEmptyMap[String, (ValueModel, Inline)]
|
||||
): State[S, Unit] = {
|
||||
for {
|
||||
res <- fields.toNel.traverse {
|
||||
case (n, (Ability(abilityName, _, _), _)) =>
|
||||
val leftName = AbilityType.fullName(name, n)
|
||||
Exports[S].copyWithAbilityPrefix(abilityName, leftName)
|
||||
case (n, (vm, _)) =>
|
||||
Exports[S].resolveAbilityField(name, n, vm)
|
||||
}
|
||||
} yield ()
|
||||
}
|
||||
|
||||
override def apply[S: Mangler: Exports: Arrows](
|
||||
raw: AbilityRaw,
|
||||
propertiesAllowed: Boolean
|
||||
@ -35,9 +37,7 @@ object MakeAbilityRawInliner extends RawInliner[AbilityRaw] {
|
||||
foldedFields <- raw.fieldsAndArrows.nonEmptyTraverse(unfold(_))
|
||||
varModel = VarModel(name, raw.baseType)
|
||||
valsInline = foldedFields.toList.foldMap { case (_, inline) => inline }.desugar
|
||||
_ <- foldedFields.toNel.traverse { case (n, (vm, _)) =>
|
||||
Exports[S].resolved(s"$name.$n", vm)
|
||||
}
|
||||
_ <- updateFields(name, foldedFields)
|
||||
} yield {
|
||||
(
|
||||
varModel,
|
||||
|
@ -1,9 +1,9 @@
|
||||
package aqua.model.inline.state
|
||||
|
||||
import aqua.model.ValueModel
|
||||
import aqua.raw.ops.Call
|
||||
import aqua.raw.value.ValueRaw
|
||||
import cats.data.State
|
||||
import aqua.model.{ValueModel, VarModel}
|
||||
import aqua.model.ValueModel.Ability
|
||||
import aqua.types.AbilityType
|
||||
import cats.data.{NonEmptyList, State}
|
||||
|
||||
/**
|
||||
* Exports – trace values available in the scope
|
||||
@ -22,6 +22,37 @@ trait Exports[S] extends Scoped[S] {
|
||||
*/
|
||||
def resolved(exportName: String, value: ValueModel): State[S, Unit]
|
||||
|
||||
/**
|
||||
* [[value]] is accessible as [[abilityExportName]].[[fieldName]]
|
||||
*
|
||||
* @param abilityExportName
|
||||
* Ability Name
|
||||
* @param fieldName
|
||||
* Field Name
|
||||
* @param value
|
||||
* Value
|
||||
*/
|
||||
def resolveAbilityField(
|
||||
abilityExportName: String,
|
||||
fieldName: String,
|
||||
value: ValueModel
|
||||
): State[S, Unit]
|
||||
|
||||
/**
|
||||
* Rename ability prefix to new one
|
||||
*/
|
||||
def copyWithAbilityPrefix(prefix: String, newPrefix: String): State[S, Unit]
|
||||
|
||||
/**
|
||||
* Get name of last linked VarModel
|
||||
*/
|
||||
def getLast(name: String): State[S, Option[String]]
|
||||
|
||||
/**
|
||||
* Rename names in variables
|
||||
*/
|
||||
def renameVariables(renames: Map[String, String]): State[S, Unit]
|
||||
|
||||
/**
|
||||
* Resolve the whole map of exports
|
||||
* @param exports
|
||||
@ -29,6 +60,18 @@ trait Exports[S] extends Scoped[S] {
|
||||
*/
|
||||
def resolved(exports: Map[String, ValueModel]): State[S, Unit]
|
||||
|
||||
/**
|
||||
* Get all export keys
|
||||
*/
|
||||
def getKeys: State[S, Set[String]]
|
||||
|
||||
/**
|
||||
* Get ability field from export
|
||||
* @param name variable ability name
|
||||
* @param field ability field
|
||||
*/
|
||||
def getAbilityField(name: String, field: String): State[S, Option[ValueModel]]
|
||||
|
||||
/**
|
||||
* Get all the values available in the scope
|
||||
*/
|
||||
@ -45,6 +88,28 @@ trait Exports[S] extends Scoped[S] {
|
||||
override def resolved(exports: Map[String, ValueModel]): State[R, Unit] =
|
||||
self.resolved(exports).transformS(f, g)
|
||||
|
||||
override def resolveAbilityField(
|
||||
abilityExportName: String,
|
||||
fieldName: String,
|
||||
value: ValueModel
|
||||
): State[R, Unit] =
|
||||
self.resolveAbilityField(abilityExportName, fieldName, value).transformS(f, g)
|
||||
|
||||
override def copyWithAbilityPrefix(prefix: String, newPrefix: String): State[R, Unit] =
|
||||
self.copyWithAbilityPrefix(prefix, newPrefix).transformS(f, g)
|
||||
|
||||
override def getLast(name: String): State[R, Option[String]] =
|
||||
self.getLast(name).transformS(f, g)
|
||||
|
||||
override def renameVariables(renames: Map[String, String]): State[R, Unit] =
|
||||
self.renameVariables(renames).transformS(f, g)
|
||||
|
||||
override def getKeys: State[R, Set[String]] =
|
||||
self.getKeys.transformS(f, g)
|
||||
|
||||
override def getAbilityField(name: String, field: String): State[R, Option[ValueModel]] =
|
||||
self.getAbilityField(name, field).transformS(f, g)
|
||||
|
||||
override val exports: State[R, Map[String, ValueModel]] =
|
||||
self.exports.transformS(f, g)
|
||||
|
||||
@ -59,18 +124,91 @@ trait Exports[S] extends Scoped[S] {
|
||||
object Exports {
|
||||
def apply[S](implicit exports: Exports[S]): Exports[S] = exports
|
||||
|
||||
// Get last linked VarModel
|
||||
def getLastValue(name: String, state: Map[String, ValueModel]): Option[VarModel] = {
|
||||
state.get(name) match {
|
||||
case Some(vm@VarModel(n, _, _)) =>
|
||||
if (name == n) Option(vm)
|
||||
else getLastValue(n, state).orElse(Option(vm))
|
||||
case n =>
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
object Simple extends Exports[Map[String, ValueModel]] {
|
||||
|
||||
// Exports[Map[NonEmptyList[String], ValueModel]]
|
||||
// Make links from one set of abilities to another (for ability assignment)
|
||||
private def getAbilityPairs(oldName: String, newName: String, at: AbilityType, state: Map[String, ValueModel]): NonEmptyList[(String, VarModel)] = {
|
||||
at.fields.toNel.flatMap {
|
||||
case (n, at@AbilityType(_, _)) =>
|
||||
val newFullName = AbilityType.fullName(newName, n)
|
||||
val oldFullName = AbilityType.fullName(oldName, n)
|
||||
getAbilityPairs(oldFullName, newFullName, at, state)
|
||||
case (n, t) =>
|
||||
val newFullName = AbilityType.fullName(newName, n)
|
||||
val oldFullName = AbilityType.fullName(oldName, n)
|
||||
// put link on last variable in chain
|
||||
val lastVar = Exports.getLastValue(oldFullName, state)
|
||||
NonEmptyList.of((newFullName, lastVar.getOrElse(VarModel(oldFullName, t))))
|
||||
}
|
||||
}
|
||||
|
||||
override def resolved(
|
||||
exportName: String,
|
||||
value: ValueModel
|
||||
): State[Map[String, ValueModel], Unit] = State.modify(_ + (exportName -> value))
|
||||
): State[Map[String, ValueModel], Unit] = State.modify { state =>
|
||||
value match {
|
||||
case vm@Ability(name, at, property) if property.isEmpty =>
|
||||
val pairs = getAbilityPairs(name, exportName, at, state)
|
||||
state ++ pairs.toList.toMap
|
||||
case _ => state + (exportName -> value)
|
||||
}
|
||||
}
|
||||
|
||||
override def getLast(name: String): State[Map[String, ValueModel], Option[String]] =
|
||||
State.get.map(st => getLastValue(name, st).map(_.name))
|
||||
|
||||
override def resolved(exports: Map[String, ValueModel]): State[Map[String, ValueModel], Unit] =
|
||||
State.modify(_ ++ exports)
|
||||
|
||||
override def resolveAbilityField(
|
||||
abilityExportName: String,
|
||||
fieldName: String,
|
||||
value: ValueModel
|
||||
): State[Map[String, ValueModel], Unit] =
|
||||
State.modify(_ + (AbilityType.fullName(abilityExportName, fieldName) -> value))
|
||||
|
||||
override def copyWithAbilityPrefix(
|
||||
prefix: String,
|
||||
newPrefix: String
|
||||
): State[Map[String, ValueModel], Unit] =
|
||||
State.modify { state =>
|
||||
state.flatMap {
|
||||
case (k, v) if k.startsWith(prefix) =>
|
||||
List(k.replaceFirst(prefix, newPrefix) -> v, k -> v)
|
||||
case (k, v) => List(k -> v)
|
||||
}
|
||||
}
|
||||
|
||||
override def renameVariables(
|
||||
renames: Map[String, String]
|
||||
): State[Map[String, ValueModel], Unit] =
|
||||
State.modify {
|
||||
_.map {
|
||||
case (k, vm @ VarModel(name, _, _)) if renames.contains(name) =>
|
||||
k -> vm.copy(name = renames.getOrElse(name, name))
|
||||
case (k, v) => k -> v
|
||||
}
|
||||
}
|
||||
|
||||
override def getKeys: State[Map[String, ValueModel], Set[String]] = State.get.map(_.keySet)
|
||||
|
||||
override def getAbilityField(
|
||||
name: String,
|
||||
field: String
|
||||
): State[Map[String, ValueModel], Option[ValueModel]] =
|
||||
State.get.map(_.get(AbilityType.fullName(name, field)))
|
||||
|
||||
override val exports: State[Map[String, ValueModel], Map[String, ValueModel]] =
|
||||
State.get
|
||||
|
||||
|
@ -51,6 +51,15 @@ object ValueModel {
|
||||
case _ => ???
|
||||
}
|
||||
|
||||
object Ability {
|
||||
|
||||
def unapply(vm: VarModel): Option[(String, AbilityType, Chain[PropertyModel])] =
|
||||
vm match {
|
||||
case VarModel(name, t@AbilityType(_, _), properties) =>
|
||||
(name, t, properties).some
|
||||
case _ => none
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case class LiteralModel(value: String, `type`: Type) extends ValueModel {
|
||||
|
@ -66,6 +66,7 @@ object OptionTypeToken {
|
||||
|
||||
case class NamedTypeToken[F[_]: Comonad](name: F[String]) extends DataTypeToken[F] {
|
||||
override def as[T](v: T): F[T] = name.as(v)
|
||||
def asName: Name[F] = Name[F](name)
|
||||
|
||||
override def mapK[K[_]: Comonad](fk: F ~> K): NamedTypeToken[K] = copy(fk(name))
|
||||
|
||||
|
@ -36,9 +36,9 @@ class AbilitySem[S[_]](val expr: AbilityExpr[S]) extends AnyVal {
|
||||
t
|
||||
): Raw
|
||||
case false =>
|
||||
Raw.error("Scope types unresolved")
|
||||
Raw.error("Ability types unresolved")
|
||||
}
|
||||
case None => Raw.error("Scope types unresolved").pure[Alg]
|
||||
case None => Raw.error("Ability types unresolved").pure[Alg]
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -300,6 +300,7 @@ class ValuesAlgebra[S[_], Alg[_]: Monad](implicit
|
||||
}
|
||||
|
||||
// Generate CallArrowRaw for arrow in ability
|
||||
// WARNING: arguments are resolved at the end of the function and added to CallArrowRaw
|
||||
def callAbType(
|
||||
ab: String,
|
||||
abType: AbilityType,
|
||||
@ -307,7 +308,7 @@ class ValuesAlgebra[S[_], Alg[_]: Monad](implicit
|
||||
): Alg[Option[CallArrowRaw]] =
|
||||
abType.arrows.get(ca.funcName.value) match {
|
||||
case Some(arrowType) =>
|
||||
Option(CallArrowRaw(None, s"$ab.${ca.funcName.value}", Nil, arrowType, None)).pure[Alg]
|
||||
Option(CallArrowRaw(None, AbilityType.fullName(ab, ca.funcName.value), Nil, arrowType, None)).pure[Alg]
|
||||
case None => None.pure[Alg]
|
||||
}
|
||||
|
||||
@ -328,32 +329,38 @@ class ValuesAlgebra[S[_], Alg[_]: Monad](implicit
|
||||
)
|
||||
)
|
||||
)(ab =>
|
||||
// TODO: Hack. Check that we have registered ability type.
|
||||
// If it exists - this is ability type in file, if not - imported ability
|
||||
T.getType(ab.value).flatMap {
|
||||
case Some(abType: AbilityType) =>
|
||||
callAbType(ab.value, abType, ca)
|
||||
// Check that we have variable as ability
|
||||
N.read(ab.asName, false).flatMap {
|
||||
case Some(at@AbilityType(_, _)) =>
|
||||
callAbType(ab.value, at, ca)
|
||||
case _ =>
|
||||
(A.getArrow(ab, ca.funcName), A.getServiceId(ab)).mapN {
|
||||
case (Some(at), Right(sid)) =>
|
||||
// Service call, actually
|
||||
CallArrowRaw(
|
||||
ability = Some(ab.value),
|
||||
name = ca.funcName.value,
|
||||
arguments = Nil,
|
||||
baseType = at,
|
||||
serviceId = Some(sid)
|
||||
).some
|
||||
case (Some(at), Left(true)) =>
|
||||
// Ability function call, actually
|
||||
CallArrowRaw(
|
||||
ability = Some(ab.value),
|
||||
name = ca.funcName.value,
|
||||
arguments = Nil,
|
||||
baseType = at,
|
||||
serviceId = None
|
||||
).some
|
||||
case _ => none
|
||||
// Check that we have registered ability type.
|
||||
// If it exists - this is ability type in file, if not - imported ability
|
||||
T.getType(ab.value).flatMap {
|
||||
case Some(abType: AbilityType) =>
|
||||
callAbType(ab.value, abType, ca)
|
||||
case t =>
|
||||
(A.getArrow(ab, ca.funcName), A.getServiceId(ab)).mapN {
|
||||
case (Some(at), Right(sid)) =>
|
||||
// Service call, actually
|
||||
CallArrowRaw(
|
||||
ability = Some(ab.value),
|
||||
name = ca.funcName.value,
|
||||
arguments = Nil,
|
||||
baseType = at,
|
||||
serviceId = Some(sid)
|
||||
).some
|
||||
case (Some(at), Left(true)) =>
|
||||
// Ability function call, actually
|
||||
CallArrowRaw(
|
||||
ability = Some(ab.value),
|
||||
name = ca.funcName.value,
|
||||
arguments = Nil,
|
||||
baseType = at,
|
||||
serviceId = None
|
||||
).some
|
||||
case _ => none
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@ -267,7 +267,11 @@ case class AbilityType(name: String, fields: NonEmptyMap[String, Type]) extends
|
||||
}
|
||||
|
||||
override def toString: String =
|
||||
s"scope $name{${fields.map(_.toString).toNel.toList.map(kv => kv._1 + ": " + kv._2).mkString(", ")}}"
|
||||
s"ability $name{${fields.map(_.toString).toNel.toList.map(kv => kv._1 + ": " + kv._2).mkString(", ")}}"
|
||||
}
|
||||
|
||||
object AbilityType {
|
||||
def fullName(name: String, field: String) = s"$name.$field"
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user