Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
core.pure.lineage.scanProperties.pure Maven / Gradle / Ivy
// Copyright 2020 Goldman Sachs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import meta::pure::milestoning::*;
import meta::pure::metamodel::serialization::grammar::*;
import meta::pure::lineage::scanExecutes::*;
import meta::pure::mapping::*;
import meta::pure::lineage::scanProperties::propertyTree::*;
import meta::pure::metamodel::path::*;
import meta::pure::lineage::scanProperties::*;
import meta::pure::graphFetch::*;
import meta::pure::router::metamodel::*;
Class meta::pure::lineage::scanProperties::PropertyPathNode
{
<> class : Class[1];
<> property : AbstractProperty[1];
nestedQualifier : List[*];
parameters : ValueSpecification[*];
nestedQualifierReturn : List[0..1];
}
Class meta::pure::lineage::scanProperties::Res
{
current : List[1];
result : List[*];
}
Class meta::pure::lineage::scanProperties::ScanPropertiesState
{
current : List[1];
result : List[*];
visitedFunctions:Map[1];
}
Class meta::pure::lineage::scanProperties::DummyPropertyPathNode extends PropertyPathNode
{
<> id : Integer[1];
}
Class meta::pure::lineage::scanProperties::propertyTree::PropertyPathTree
{
display : String[1];
value : Any[1];
children : PropertyPathTree[*];
qualifierSubTree : PropertyPathTree[0..1];
}
Class meta::pure::lineage::scanProperties::ScanConfig
{
scanClasses:Boolean[1];
explodeMilestonedProperties:Boolean[1];
}
function meta::pure::lineage::scanProperties::defaultScanConfig(): ScanConfig[1]
{
^ScanConfig(scanClasses=false, explodeMilestonedProperties= true);
}
// embedd dummyProp for every classOnlyAccess as a hack not to alter current structure of propertyPathTree
Class meta::pure::lineage::scanProperties::DummyClass
{
dummyProp : String[1];
}
function meta::pure::lineage::scanProperties::getDummyProperty():AbstractProperty[1]
{
meta::pure::lineage::scanProperties::DummyClass->propertyByName('dummyProp')->toOne()
}
function <> meta::pure::lineage::scanProperties::dummyNodeForClass(c:Class[1]):PropertyPathNode[1]
{
^PropertyPathNode( class = $c, property= getDummyProperty());
}
function <> meta::pure::lineage::scanProperties::findAndAddChildrenAtTheEnd(tree: PropertyPathTree[1], path: PropertyPathNode[*], toAdd: PropertyPathTree[*]):PropertyPathTree[1]
{
if($path->isEmpty(),
| ^$tree(children += $toAdd),
| let first = $path->at(0);
let correctTree = $tree.children->filter(x | $x.value->instanceOf(PropertyPathNode) && ($x.value->cast(@PropertyPathNode).property == $first.property))->toOne();
let otherTrees = $tree.children->remove($correctTree);
^$tree(
children = $otherTrees->concatenate($correctTree->findAndAddChildrenAtTheEnd($path->tail(), $toAdd))
);
)
}
function <> meta::pure::lineage::scanProperties::test::dummy():Any[*]
{
'To ensure integration build does not fail on meta::pure::lineage::scanProperties::test package'
}
function meta::pure::lineage::scanProperties::getVisitedFunctions(maybeRes:ScanPropertiesState[0..1]):Map[1]
{
$maybeRes->match([
r0:ScanPropertiesState[0] | ^Map(),
r1:ScanPropertiesState[1] | $r1.visitedFunctions
]);
}
function meta::pure::lineage::scanProperties::makeScanPropertiesState(current:List[1], result:List[*], visitedFunctions:Map[1]):ScanPropertiesState[1]
{
^ScanPropertiesState( current= $current,
result = $result->removeDuplicates(),
visitedFunctions = $visitedFunctions
);
}
function <> {doc.doc = 'Use scanProperties_ValueSpecification_1__List_MANY_ instead'}
meta::pure::lineage::scanProperties::scanProperties(vs:ValueSpecification[1], list:List[1], processed:Function[*], vars:Map>[0..1]):Res[0..1]
{
let res = scanProperties($vs, $list, $processed, $vars, defaultScanConfig(), noDebug())->orElseEmptyPath();
^Res(current = $res.current, result = $res.result);
}
function <> {doc.doc = 'Use scanProperties_ValueSpecification_1__List_MANY_ instead'}
meta::pure::lineage::scanProperties::scanProperties(vs:ValueSpecification[1], list:List[1], processed:Function[*], vars:Map>[0..1], config:ScanConfig[1]):ScanPropertiesState[0..1]
{
scanProperties($vs, $list, $processed, $vars, $config, noDebug());
}
function <> {doc.doc = 'Use scanProperties_ValueSpecification_1__DebugContext_1__List_MANY_ instead'}
meta::pure::lineage::scanProperties::scanProperties(vs:ValueSpecification[1], list:List[1], processed:Function[*], vars:Map>[0..1] , debug: meta::pure::tools::DebugContext[1]):ScanPropertiesState[0..1]
{
scanProperties($vs, $list, $processed, $vars, defaultScanConfig(), $debug);
}
function <> {doc.doc = 'Use scanProperties_ValueSpecification_1__DebugContext_1__List_MANY_ instead'}
meta::pure::lineage::scanProperties::scanProperties(vs:ValueSpecification[1], list:List[1], processed:Function[*], vars:Map>[0..1], config:ScanConfig[1], debug: meta::pure::tools::DebugContext[1]):ScanPropertiesState[0..1]
{
assert($list.values->isEmpty(), |'Do not supply base path. Use scanProperties_ValueSpecification_1__List_MANY_ instead');
assert($processed->isEmpty(), |'Do not supply processed. Use scanProperties_ValueSpecification_1__List_MANY_ instead');
assert($vars->isEmpty() || $vars->toOne()->keys()->isEmpty(), |'Do not supply vars. Use scanProperties_ValueSpecification_1__List_MANY_ instead');
$vs->scanProperties($debug, $config);
}
function meta::pure::lineage::scanProperties::scanProperties(vs:ValueSpecification[1]):ScanPropertiesState[0..1]
{
scanProperties($vs, noDebug(), defaultScanConfig());
}
function meta::pure::lineage::scanProperties::scanProperties(vs:ValueSpecification[1],config:ScanConfig[1]):ScanPropertiesState[0..1]
{
scanProperties($vs, noDebug(), $config);
}
function meta::pure::lineage::scanProperties::scanProperties(vs:ValueSpecification[1], debug:DebugContext[1]):ScanPropertiesState[0..1]
{
scanProperties($vs, $debug, defaultScanConfig());
}
function meta::pure::lineage::scanProperties::scanProperties(vs:ValueSpecification[1], debug:DebugContext[1], config:ScanConfig[1]):ScanPropertiesState[0..1]
{
print(if($debug.debug,|$debug.space+'>>> ScanProperties in : ' +$vs->printValueSpecification('') + ' \n',|''));
internal_scanProperties($vs, [], noVars(), $config, ^Map(), ^$debug(space=$debug.space+' '));
}
function meta::pure::lineage::scanProperties::scanProperties(vs:ValueSpecification[1], debug:DebugContext[1], config:ScanConfig[1], visitedFunctions:Map[1]):ScanPropertiesState[0..1]
{
internal_scanProperties($vs, [], noVars(), $config, $visitedFunctions, ^$debug(space=$debug.space+' '));
}
function <> meta::pure::lineage::scanProperties::internal_scanProperties(vs:ValueSpecification[1], processed:Function[*], vars:Map>[1], config:ScanConfig[1], visitedFunctions:Map[1], debug: meta::pure::tools::DebugContext[1]):ScanPropertiesState[0..1]
{
print(if($debug.debug,|$vars->keyValues()->map(kv | '{' + $kv.first + ' : ' + $kv.second->printPropertyNodeLists('') + '}')->makeString($debug.space + 'Context : ', ', ', '\n'),|''));
let res = $vs->match([
fe:FunctionExpression[1] | print(if($debug.debug,|$debug.space+'Processing Function Expression\n',|''));
let params = $fe.parametersValues->evaluateAndDeactivate();
$fe.func->match([
p:Property[1]|print(if($debug.debug,|$debug.space+' property:'+$p.name->toOne()+'\n', |''));
let leftSide = $params->at(0)->internal_scanProperties($processed, $vars, $config, $visitedFunctions, ^$debug(space=$debug.space+' '));
if($params->at(0)->extractType()->instanceOf(Class),
{|
let srcClass = $params->at(0)->extractType()->cast(@Class);
let nlist = $p->processProperty($srcClass, $leftSide.current->orElseEmptyPath(), true);
makeScanPropertiesState(
$nlist->at(0),
$nlist->concatenate($leftSide.result->filter(x | $x.values->isNotEmpty())),
$leftSide->getVisitedFunctions()
);
},
| $leftSide
);,
q:QualifiedProperty[1]|print(if($debug.debug,|$debug.space+' qualifier:'+$q.name->toOne()+'\n', |''));
let srcClass = $params->at(0)->extractType()->cast(@Class);
let leftSide = $params->at(0)->map(v|$v->internal_scanProperties($processed->concatenate($q), $vars, $config, $visitedFunctions, ^$debug(space=$debug.space+' ')));
if(!$processed->contains($q),
{|
let nlist = $q->processQualifier($srcClass, $params->tail(), $leftSide.current->orElseEmptyPath(), $processed, $vars, true, $config, $leftSide->getVisitedFunctions(), $debug);
makeScanPropertiesState($nlist, $nlist, $leftSide->getVisitedFunctions());
},
| makeScanPropertiesState(emptyPath(), [], $leftSide->getVisitedFunctions())
);,
z:Any[1]|print(if($debug.debug,|$debug.space+' function: \''+$fe.func.name->toOne()+'\'\n',|''));
if($fe.func.name->in(['eval_Function_1__T_n__V_m_']),
{|
print(if($debug.debug,|$debug.space+' - param 1\n',|''));
let collectionPath = $params->at(1)->internal_scanProperties($processed, $vars, $config, $visitedFunctions,^$debug(space=$debug.space+' '))->orElseEmptyPath();
$params->at(0)->findFunction()->processFunction($collectionPath, $vars, $processed, $config, $collectionPath.visitedFunctions, ^$debug(space=$debug.space+' '));
},
|
if($fe.func.name == 'sort_T_m__Function_$0_1$__T_m_',
{|
let collectionPath = $params->at(0)->internal_scanProperties($processed, $vars, $config, $visitedFunctions, ^$debug(space=$debug.space+' '))->orElseEmptyPath();
let func = $params->at(1)->findFunction();
let funcResult = $func->processFunction([$collectionPath, $collectionPath], $vars, $processed, $config, $collectionPath.visitedFunctions, ^$debug(space=$debug.space+' '));
^$funcResult(current=$collectionPath.current, visitedFunctions = $funcResult.visitedFunctions);
},
|
if($fe.func.name == 'sort_T_m__Function_$0_1$__Function_$0_1$__T_m_',
{|
let collectionPath = $params->at(0)->internal_scanProperties($processed, $vars, $config, $visitedFunctions, ^$debug(space=$debug.space+' '))->orElseEmptyPath();
let keyFunc = $params->at(1)->findFunction();
let comparator = $params->at(2)->findFunction();
let keyFuncResult = $keyFunc->processFunction($collectionPath, $vars, $processed, $config, $collectionPath.visitedFunctions, ^$debug(space=$debug.space+' '));
let compResult = $comparator->processFunction([$keyFuncResult, $keyFuncResult], $vars, $processed, $config, $keyFuncResult.visitedFunctions, ^$debug(space=$debug.space+' '));
makeScanPropertiesState(
$collectionPath.current,
$compResult.result->concatenate($keyFuncResult.result),
$compResult.visitedFunctions
);
},
|
if($fe.func.name == 'removeDuplicates_T_MANY__Function_$0_1$__Function_$0_1$__T_MANY_',
{|
let collectionPath = $params->at(0)->internal_scanProperties($processed, $vars, $config, $visitedFunctions, ^$debug(space=$debug.space+' '))->orElseEmptyPath();
let keyFunc = $params->at(1)->findFunction();
let predicate = $params->at(2)->findFunction();
let keyFuncResult = $keyFunc->processFunction($collectionPath, $vars, $processed, $config, $collectionPath.visitedFunctions, ^$debug(space=$debug.space+' '));
let predResult = $predicate->processFunction($keyFuncResult, $vars, $processed, $config, $keyFuncResult.visitedFunctions,^$debug(space=$debug.space+' '));
makeScanPropertiesState(
$collectionPath.current,
$predResult.result->concatenate($keyFuncResult.result),
$predResult.visitedFunctions
);
},
|
if($fe.func.name == 'letFunction_String_1__T_m__T_m_',
{|
print(if($debug.debug,|$debug.space+' - param 1\n',|''));
$params->at(1)->internal_scanProperties($processed, $vars, $config, $visitedFunctions, ^$debug(space=$debug.space+' '));
},
|
if($fe.func.name == 'if_Boolean_1__Function_1__Function_1__T_m_',
{|
print(if($debug.debug,|$debug.space+' - param 0\n',|''));
let testPath = $params->at(0)->internal_scanProperties($processed, $vars, $config, $visitedFunctions, ^$debug(space=$debug.space+' '))->orElseEmptyPath();
print(if($debug.debug,|$debug.space+' - param 1\n',|''));
let thenPath = $params->at(1)->findFunction()->processFunction([], $vars, $processed, $config, $testPath.visitedFunctions, ^$debug(space=$debug.space+' '));
print(if($debug.debug,|$debug.space+' - param 2\n',|''));
let elsePath = $params->at(2)->findFunction()->processFunction([], $vars, $processed, $config, $thenPath.visitedFunctions, ^$debug(space=$debug.space+' '));
makeScanPropertiesState(
$thenPath.current->concatenate($elsePath.current)->removeEmptyPaths()->first()->orElseEmptyPath(), // TODO handle when both paths are relevant
$testPath.result->concatenate($thenPath.result)->concatenate($elsePath.result),
$elsePath.visitedFunctions
);
},
|
if($fe.func.name == 'match_Any_MANY__Function_$1_MANY$__T_m_',
{|
print(if($debug.debug,|$debug.space+' - param 0\n',|''));
print(if($debug.debug,|$debug.space+' match function expression \n',|''));
print(if(!$debug.debug,|'', | ^$debug(space=$debug.space+' ').space+'processing match input expression \n'));
let inputPath = $params->at(0)->internal_scanProperties($processed, $vars, $config, $visitedFunctions, ^$debug(space=$debug.space+' '+' '))->orElseEmptyPath();
let addMatchConditionClasses = $config.scanClasses;
print(if(!$debug.debug,|'', |^$debug(space=$debug.space+' ').space+'processing match conditions: \n'));
let matchLambdas= $params->at(1)->findFunctions();
let funcResults = $matchLambdas->fold({f, r|
let res = $f->processFunction($inputPath, $vars, $processed, $config, $r.visitedFunctions, ^$debug(space=$debug.space+' '+' '), $addMatchConditionClasses);
makeScanPropertiesState($r.current->concatenate($res.current)->removeEmptyPaths()->first()->orElseEmptyPath(),
$r.result->concatenate($res.result),
$res.visitedFunctions
);
},
makeScanPropertiesState(emptyPath(), [], $inputPath.visitedFunctions)
);
$funcResults;
},
|
if($fe.func.name->in(['assert_Boolean_1__Function_1__Boolean_1_',
'exists_T_MANY__Function_1__Boolean_1_',
'forAll_T_MANY__Function_1__Boolean_1_']),
{|
// Unary function, result is primitive
print(if($debug.debug,|$debug.space+' - param 0\n',|''));
let collectionPath = $params->at(0)->internal_scanProperties($processed, $vars, $config, $visitedFunctions, ^$debug(space=$debug.space+' '))->orElseEmptyPath();
let funcResult = $params->at(1)->findFunction()->processFunction($collectionPath, $vars, $processed, $config, $collectionPath.visitedFunctions, ^$debug(space=$debug.space+' '));
^$funcResult(current=emptyPath());
},
|
if($fe.func.name->in(['fold_T_MANY__Function_1__V_m__V_m_',
'map_T_MANY__Function_1__V_MANY_',
'map_T_m__Function_1__V_m_',
'map_T_$0_1$__Function_1__V_$0_1$_']),
{|
// Unary function, return is that function's return
print(if($debug.debug,|$debug.space+' - param 0\n',|''));
let collectionPath = $params->at(0)->internal_scanProperties($processed, $vars, $config, $visitedFunctions, ^$debug(space=$debug.space+' '))->orElseEmptyPath();
$params->at(1)->findFunction()->processFunction($collectionPath, $vars, $processed, $config, $collectionPath.visitedFunctions, ^$debug(space=$debug.space+' '));
},
|
if($fe.func.name->in(['filter_T_MANY__Function_1__T_MANY_',
'removeDuplicates_T_MANY__Function_1__T_MANY_',
'removeDuplicatesBy_T_MANY__Function_1__T_MANY_',
'sortBy_T_m__Function_$0_1$__T_m_']),
{|
// Unary function, return is same as collection in
let collectionPath = $params->at(0)->internal_scanProperties($processed, $vars, $config, $visitedFunctions, ^$debug(space=$debug.space+' '))->orElseEmptyPath();
let func = $params->at(1)->findFunction();
let funcResult = $func->processFunction($collectionPath, $vars, $processed, $config, $collectionPath.visitedFunctions, ^$debug(space=$debug.space+' '));
^$funcResult(current=$collectionPath.current);
},
|
if($fe.func.name->in(['at_T_MANY__Integer_1__T_1_',
'cast_Any_m__T_1__T_m_',
'distinct_T_MANY__T_MANY_',
'drop_T_MANY__Integer_1__T_MANY_',
'first_T_MANY__T_$0_1$_',
'init_T_MANY__T_MANY_',
'last_T_MANY__T_$0_1$_',
'limit_T_MANY__Integer_1__T_MANY_',
'removeDuplicates_T_MANY__T_MANY_',
'reverse_T_m__T_m_',
'slice_T_MANY__Integer_1__Integer_1__T_MANY_',
'subType_Any_m__T_1__T_m_',
'whenSubType_Any_1__T_1__T_$0_1$_',
'whenSubType_Any_$0_1$__T_1__T_$0_1$_',
'whenSubType_Any_MANY__T_1__T_MANY_',
'sort_T_m__T_m_',
'tail_T_MANY__T_MANY_',
'take_T_MANY__Integer_1__T_MANY_',
'toOne_T_MANY__T_1_',
'toOneMany_T_MANY__T_$1_MANY$_']),
{|
// No function, return is same as collection in
print(if($debug.debug,|$debug.space+' - param 0\n',|''));
$params->at(0)->internal_scanProperties($processed, $vars, $config, $visitedFunctions, ^$debug(space=$debug.space+' '))->orElseEmptyPath();
},
|
if($fe.func.name->in(['add_T_MANY__T_1__T_$1_MANY$_',
'concatenate_T_MANY__T_MANY__T_MANY_',
'union_T_MANY__T_MANY__T_MANY_']),
{|
// Combine 2 collections
print(if($debug.debug,|$debug.space+' - param 0\n',|''));
let col1 = $params->at(0)->internal_scanProperties($processed, $vars, $config, $visitedFunctions, ^$debug(space=$debug.space+' '))->orElseEmptyPath();
print(if($debug.debug,|$debug.space+' - param 1\n',|''));
let col2 = $params->at(1)->internal_scanProperties($processed, $vars, $config, $col1.visitedFunctions, ^$debug(space=$debug.space+' '))->orElseEmptyPath();
makeScanPropertiesState(
$col1.current->concatenate($col2.current)->removeEmptyPaths()->first()->orElseEmptyPath(), // TODO handle when both paths are relevant
$col1.result->concatenate($col2.result),
$col2.visitedFunctions
);
},
{|
print(if($debug.debug,|$debug.space+'processing params \n',|''));
let pp = $params->map(v|$v->internal_scanProperties($processed, $vars, $config, $visitedFunctions, ^$debug(space=$debug.space+' '))->orElseEmptyPath());
print(if($debug.debug,|$debug.space+'checking if func should be processed further \n',|''));
let func = $fe.func->filter(f| $f->shouldBeProcessed($processed))->first();
$func->processFunction($pp, $vars, $processed, $config, $visitedFunctions, ^$debug(space=$debug.space+' '));
}
))))))))))));
]);,
i:InstanceValue[1] | print(if($debug.debug,|$debug.space+'Processing Instance\n',|''));
let instanceRes = $i.values->evaluateAndDeactivate()->map( v |
$v->match([
a: ValueSpecification[1] | $a->internal_scanProperties($processed, $vars, $config, $visitedFunctions, ^$debug(space=$debug.space+' '));,
k: KeyExpression[1] | $k.expression->internal_scanProperties($processed, $vars, $config, $visitedFunctions, ^$debug(space=$debug.space+' '));,
a: meta::pure::functions::collection::AggregateValue[1] | makeScanPropertiesState(emptyPath(), $a.mapFn.expressionSequence->map(e | $e->internal_scanProperties($processed, $vars, $config, $visitedFunctions, ^$debug(space=$debug.space+' '))).result, $visitedFunctions),
a: meta::pure::tds::BasicColumnSpecification[1] | makeScanPropertiesState(emptyPath(), $a.func->cast(@FunctionDefinition).expressionSequence->map(e | $e->internal_scanProperties($processed, $vars, $config, $visitedFunctions, ^$debug(space=$debug.space+' '))).result,$visitedFunctions),
l: LambdaFunction[1] | $l.expressionSequence->map(e | $e->internal_scanProperties($processed, $vars, $config, $visitedFunctions, ^$debug(space=$debug.space+' ')));,
l: ConcreteFunctionDefinition[1] | $l.expressionSequence->map(e | $e->internal_scanProperties($processed, $vars, $config, $visitedFunctions, ^$debug(space=$debug.space+' ')));,
a: String[1] | makeScanPropertiesState(emptyPath(), [], $visitedFunctions),
p: Path[1] | makeScanPropertiesState(emptyPath(), $p->scanPath(emptyPath(), $processed, $vars, $config, $visitedFunctions, $debug), $visitedFunctions),
r: RootGraphFetchTree[1] | makeScanPropertiesState(emptyPath(), $r->scanGraphFetchTree($r->typeFromGraphFetchTree()->cast(@Class), emptyPath(), $processed, $vars, $config, $visitedFunctions, $debug), $visitedFunctions),
c: Class[1] | if($config.scanClasses->toOne(),
| print(if($debug.debug,|$debug.space+' Class : '+ $c.name->toOne()+ '\n',|''));
let v= list(meta::pure::lineage::scanProperties::dummyNodeForClass($c));
makeScanPropertiesState($v, $v, $visitedFunctions); ,
| []
);,
a: Any[1] | print(if($debug.debug,|$debug.space+' Unknown\n',|''));[];
]));
makeScanPropertiesState(
$instanceRes.current->removeEmptyPaths()->first()->orElseEmptyPath(),
$instanceRes.result,
$visitedFunctions
);,
ve:VariableExpression[1] | print(if($debug.debug,|$debug.space+'Processing Variable '+$ve.name+'\n',|''));
let v = $vars->get($ve.name)->orElseEmptyPath();
makeScanPropertiesState($v, $v, $visitedFunctions);,
ervs:ExtendedRoutedValueSpecification[1] | print(if($debug.debug,|$debug.space+'Bypassing ExtendedRoutedValueSpecification\n',|''));
$ervs.value->internal_scanProperties($processed, $vars, $config,$visitedFunctions, ^$debug(space=$debug.space+' '));,
frvs:FunctionRoutedValueSpecification[1] | print(if($debug.debug,|$debug.space+'Bypassing FunctionRoutedValueSpecification\n',|''));
$frvs.value->internal_scanProperties($processed, $vars, $config, $visitedFunctions, ^$debug(space=$debug.space+' '));
]
)->removeEmptyResults();
print(if($debug.debug,|$debug.space+'Current:'+$res.current->printPropertyNodeLists($debug.space+' ')+'\n',|''));
print(if($debug.debug,|$debug.space+'Results:'+$res.result->printPropertyNodeLists($debug.space+' ')+'\n',|''));
$res;
}
function <> meta::pure::lineage::scanProperties::isPackageOk(f:Function[1]):Boolean[1]
{
!$f->isWithinPackage(meta) || $f->meta::alloy::isMetaAlloyTestDependency() || $f->isWithinPackage(meta::pure::lineage::scanProperties::test);
}
function <> meta::pure::lineage::scanProperties::shouldBeProcessed(f:Function[1], processed:Function[*]):Boolean[1]
{
isPackageOk($f) && !$processed->contains($f);
}
function <> meta::pure::lineage::scanProperties::extractType(vs:ValueSpecification[1]):Type[1]
{
$vs->match([
ervs :ExtendedRoutedValueSpecification[1] | $ervs.value->extractType(),
frvs :FunctionRoutedValueSpecification[1] | $frvs.value->extractType(),
other:ValueSpecification[1] | $other.genericType.rawType->toOne()
]);
}
function <> meta::pure::lineage::scanProperties::processFunction(fn:Function[0..1], paramPaths:ScanPropertiesState[*], vars:Map>[1], processed:Function[*], config:ScanConfig[1], visitedFunctions:Map[1], debug:DebugContext[1]):ScanPropertiesState[1]
{
processFunction($fn, $paramPaths, $vars, $processed, $config, $visitedFunctions, $debug, false);
}
function <> meta::pure::lineage::scanProperties::processLambdaFunction(fn:Function[1], paramPaths:ScanPropertiesState[*], vars:Map>[1], processed:Function[*], config:ScanConfig[1],visitedFunctions:Map[1], debug:DebugContext[1] , addFunctionParamClasses : Boolean[1]):ScanPropertiesState[1]
{
let fromParams = makeScanPropertiesState(emptyPath(), $paramPaths.result, $visitedFunctions);
let funcParamNodes= if($addFunctionParamClasses,
| let funcParamClasses = $fn->functionType().parameters.genericType.rawType ->cast(@Class);
list($funcParamClasses -> map(c|$c->dummyNodeForClass()));,
| []
);
let newVars = $fn->functionType().parameters.name->zip($paramPaths.current)->newMap();
let allVars = $vars->putAll($newVars);
let expressions = $fn->match([l:FunctionDefinition[1]| $l.expressionSequence, n:NativeFunction[1]| []]);
let body = $expressions->processExpressionSequence($allVars, $processed->concatenate($fn), $config, $visitedFunctions, $debug);
^$body(result=$fromParams.result->concatenate($body.result)->concatenate($funcParamNodes));
}
function <> meta::pure::lineage::scanProperties::processFunction(fn:Function[0..1], paramPaths:ScanPropertiesState[*], vars:Map>[1], processed:Function[*], config:ScanConfig[1], visitedFunctions:Map[1], debug:DebugContext[1] , addFunctionParamClasses : Boolean[1]):ScanPropertiesState[1]
{
print(if($debug.debug,|$debug.space+' - func '+ if($fn->isEmpty(), |'not found or excuded', |if($fn.name->isEmpty(), |$fn->toOne()->type().name->toOne(), |$fn.name->toOne()))+'\n',|''));
let fromParams = makeScanPropertiesState(emptyPath(), $paramPaths.result, $visitedFunctions);
$fn->match([
{f0:Function[0] | $fromParams},
{f:Function[1] |
if($f.name->isEmpty() || !isPackageOk($f),
|
processLambdaFunction($f, $paramPaths, $vars, $processed, $config, $visitedFunctions, $debug, $addFunctionParamClasses);,
|
let funcParamNodes = if($addFunctionParamClasses,
| let funcParamClasses = $f->functionType().parameters.genericType.rawType ->cast(@Class);
list($funcParamClasses -> map(c|$c->dummyNodeForClass()));,
| []
);
if($visitedFunctions->get($f->meta::pure::functions::meta::elementToPath())->isNotEmpty(),
|
let acutalBodyResult = resolveDummyNodes($visitedFunctions->get($f->meta::pure::functions::meta::elementToPath())->toOne(), $paramPaths);
makeScanPropertiesState($acutalBodyResult.current, $paramPaths.result->concatenate($acutalBodyResult.result)->concatenate($funcParamNodes), $visitedFunctions);,
|
let dummyPaths = range($paramPaths->size())->map(ind | list(^DummyPropertyPathNode(id = $ind, class = meta::pure::lineage::scanProperties::DummyClass, property = getDummyProperty())->cast(@PropertyPathNode)));
let newVars = $f->functionType().parameters.name->zip($dummyPaths)->newMap();
let allVars = $vars->putAll($newVars)->cast(@Map>);
let expressions = $f->match([l:FunctionDefinition[1]| $l.expressionSequence, n:NativeFunction[1]| []]);
let body = $expressions->processExpressionSequence($allVars, $processed->concatenate($f), $config, $visitedFunctions, $debug);
let updatedMap = $visitedFunctions->put($f->meta::pure::functions::meta::elementToPath(), ^$body(visitedFunctions = ^Map()));
let acutalResult = resolveDummyNodes($body, $paramPaths);
makeScanPropertiesState($acutalResult.current, $paramPaths.result->concatenate($acutalResult.result)->concatenate($funcParamNodes), $updatedMap);
);
);
}
]);
}
function <> meta::pure::lineage::scanProperties::replaceDummyNodesWithParamsPropertyPathNodes(propertyPathNode: PropertyPathNode[0..1], paramPaths:ScanPropertiesState[*]):PropertyPathNode[*]
{
if(!$propertyPathNode->isEmpty() && $propertyPathNode->toOne()->instanceOf(DummyPropertyPathNode),
|
let paramIndex = $propertyPathNode->toOne()->cast(@DummyPropertyPathNode).id;
$paramPaths->at($paramIndex).current.values;,
| $propertyPathNode;
);
}
function <> meta::pure::lineage::scanProperties::resolveDummyNodes(dummyRes:ScanPropertiesState[1], paramPaths:ScanPropertiesState[*]):ScanPropertiesState[1]
{
let currentPropertyPathNodes = $dummyRes.current.values;
let current = list(replaceDummyNodesWithParamsPropertyPathNodes($currentPropertyPathNodes->first(), $paramPaths)->concatenate($currentPropertyPathNodes->slice(1, $currentPropertyPathNodes->size())));
let result = $dummyRes.result->map(list | list(replaceDummyNodesWithParamsPropertyPathNodes($list.values->first(), $paramPaths)->concatenate($list.values->slice(1,$list.values->size()))););
makeScanPropertiesState($current, $result, ^Map());
}
function <> meta::pure::lineage::scanProperties::processExpressionSequence(expressions:ValueSpecification[*], vars:Map>[1], processed:Function[*], config:ScanConfig[1], visitedFunctions:Map[1], debug:DebugContext[1]):ScanPropertiesState[1]
{
print(if($debug.debug,|$debug.space+' - vars '+$vars->varsToString()+'\n',|''));
$expressions->fold(
{e, p |
let r = $p.first;
let v = $p.second;
let ePaths = $e->internal_scanProperties($processed, $v, $config, $r.visitedFunctions, ^$debug(space=$debug.space+' '));
let newVars = if($e->instanceOf(FunctionExpression) && $e->cast(@FunctionExpression).func == letFunction_String_1__T_m__T_m_,
{|
let varName = $e->cast(@FunctionExpression).parametersValues->evaluateAndDeactivate()->at(0)->cast(@InstanceValue).values->at(0)->cast(@String);
let varValue = $ePaths.current->orElseEmptyPath();
print(if($debug.debug,|$debug.space+' - +var '+varToString($varName, $varValue)+'\n',|''));
$v->put($varName, $varValue);
},
| $v
);
let newRes = makeScanPropertiesState(
if($ePaths->isEmpty(), |emptyPath(), |$ePaths->toOne().current),
$r.result->concatenate($ePaths.result),
$ePaths->getVisitedFunctions()
);
pair($newRes, $newVars);
},
pair(makeScanPropertiesState(emptyPath(), [], $visitedFunctions), $vars)
).first;
}
function <> meta::pure::lineage::scanProperties::varsToString(vars:Map>[1]):String[1]
{
$vars->keyValues()->map(kv| varToString($kv.first, $kv.second))->joinStrings('[', ' , ', ']')
}
function <> meta::pure::lineage::scanProperties::varToString(name:String[1], value:List[1]):String[1]
{
$name+':'+$value->printPropertyNodeLists()->replace('\n', ';');
}
function <> meta::pure::lineage::scanProperties::processProperty(p:Property[1], srcClass:Class[1], list:List[1], append:Boolean[1]):List[1]
{
let property = ^PropertyPathNode(
class = $srcClass,
property=$p
);
if($append,|^$list(values = $list.values->concatenate($property)),|^$list(values = $property->concatenate($list.values)));
}
function <> meta::pure::lineage::scanProperties::processQualifier(q:QualifiedProperty[1], srcClass:Class[1], parameters:ValueSpecification[*], list:List[1], processed:Function[*], vars:Map>[1], append:Boolean[1], config:ScanConfig[1], visitedFunctions:Map[1], debug:DebugContext[1]):List[1]
{
let paramPaths = $parameters->map(v|$v->internal_scanProperties($processed, $vars, $config, $visitedFunctions, ^$debug(space=$debug.space+' ')));
let qualifierVars = $q->functionType().parameters->tail().name->zip($paramPaths.current)->newMap();
let property = if($q->isMilestonedGeneratedQualifiedProperty() && $config.explodeMilestonedProperties==false,
| if(hasSufficientValuesForPropertyParameters( $q,$parameters),
| ^PropertyPathNode(
class = $srcClass,
property = $q,
nestedQualifier = [],
parameters = $parameters,
nestedQualifierReturn = []
),
| ^PropertyPathNode(
class = $srcClass,
property = $q->switchToNoArgMilestonedGeneratedQualifiedProperty()->toOne(),
nestedQualifier = [],
parameters = [],
nestedQualifierReturn = []
)
),
| let qualifierBody = $q.expressionSequence->processExpressionSequence($qualifierVars, $processed->concatenate($q), $config, $visitedFunctions, $debug);
^PropertyPathNode(
class = $srcClass,
property = $q,
nestedQualifier = $qualifierBody.result,
parameters = $parameters,
nestedQualifierReturn = $qualifierBody->last().current
);
);
if($append,|^$list(values = $list.values->concatenate($property)),|^$list(values = $property->concatenate($list.values)));
}
function <> meta::pure::lineage::scanProperties::hasSufficientValuesForPropertyParameters(q:QualifiedProperty[1], parameters:ValueSpecification[*]):Boolean[1]
{
$q->functionType().parameters->evaluateAndDeactivate()->tail()->size() == $parameters->size();
}
function <> meta::pure::lineage::scanProperties::scanPath(p:Path[1], list:List[1], processed:Function[*], vars:Map>[1], config:ScanConfig[1], visitedFunctions:Map[1], debug:DebugContext[1]):List[*]
{
$p.path->fold({pe,s|$pe->match([
p:PropertyPathElement[1]|pair($p.property->functionReturnType().rawType->toOne(),
$p.property->match(
[
p:Property[1]| processProperty($p, $s.first->cast(@Class), $s.second, true),
q:QualifiedProperty[1]| processQualifier($q, $s.first->cast(@Class), $p.parameters, $s.second, $processed, $vars, true, $config, $visitedFunctions,$debug)
]
)
),
c:CastPathElement[1]| pair($c.type.rawType->toOne(), $s.second)
]
)
}, pair($p.start.rawType->toOne(), $list)
).second;
}
function <> meta::pure::lineage::scanProperties::scanGraphFetchTree(g:GraphFetchTree[1], type: Class[1], list:List[1], processed:Function[*], vars:Map>[1],config:ScanConfig[1], visitedFunctions:Map[1], debug:DebugContext[1]):List[*]
{
$g.subTrees->cast(@PropertyGraphFetchTree)->map({st |
let res = $st.property->match([
p:Property[1]| processProperty($p, $type, $list, true),
q:QualifiedProperty[1]| processQualifier($q, $type, $st.parameters, $list, $processed, $vars, true, $config, $visitedFunctions, $debug)
]);
if($st.subTrees->isNotEmpty(),
| scanGraphFetchTree($st, $st->typeFromGraphFetchTree()->cast(@Class), $res, $processed, $vars, $config, $visitedFunctions, $debug),
| $res
);
});
}
function <> meta::pure::lineage::scanProperties::findFunction(vs:ValueSpecification[1]):Function[0..1]
{
$vs->findFunctions()->first();
}
function <> meta::pure::lineage::scanProperties::findFunctions(vs:ValueSpecification[1]):Function[*]
{
$vs->match([
ervs:ExtendedRoutedValueSpecification[1] | $ervs.value->findFunction(),
frvs:FunctionRoutedValueSpecification[1] | $frvs.value->findFunction(),
iv :InstanceValue[1] | $iv.values->map(v | $v->match([f:Function[1]|$f, a:Any[*]|[]])),
a :Any[*] | []
]);
}
function <> meta::pure::lineage::scanProperties::noVars():Map>[1]
{
^Map>();
}
function <> meta::pure::lineage::scanProperties::removeEmptyResults(res:ScanPropertiesState[0..1]):ScanPropertiesState[0..1]
{
$res->map(r| ^$r(result=$r.result->removeEmptyPaths()));
}
function <> meta::pure::lineage::scanProperties::removeEmptyPaths(paths:List[*]):List[*]
{
$paths->filter(l| $l.values->isNotEmpty());
}
function <> meta::pure::lineage::scanProperties::orElseEmptyPath(maybeRes:ScanPropertiesState[0..1]):ScanPropertiesState[1]
{
$maybeRes->match([
r0:ScanPropertiesState[0] | makeScanPropertiesState(emptyPath(), [], ^Map()),
r1:ScanPropertiesState[1] | $r1
]);
}
function <> meta::pure::lineage::scanProperties::orElseEmptyPath(maybePath:List[0..1]):List[1]
{
$maybePath->match([
l0:List[0] | emptyPath(),
l1:List[1] | $l1
]);
}
function meta::pure::lineage::scanProperties::emptyPath():List[1]
{
^List();
}
function meta::pure::lineage::scanProperties::printPropertyNodeLists(properyLists:List[*]):String[1]
{
$properyLists->printPropertyNodeLists('');
}
function meta::pure::lineage::scanProperties::printPropertyNodeLists(properyLists:List[*], space:String[1]):String[1]
{
$properyLists->map(l|$l.values->map(v|$v.class.name->toOne()+'->'+$v.property.name->toOne())->joinStrings(', '))->sort()->removeDuplicates()->joinStrings('\n'+$space);
}
function <> meta::pure::lineage::scanProperties::propertyTree::recurseBuildTree(list:List[*]):PropertyPathTree[*]
{
let m = $list->filter(l|!$l.values->isEmpty())->groupBy(l|$l.values->at(0));
$m->keys()->map(
k|^PropertyPathTree(display = $k.property->match([p:Property[1]|'',q:QualifiedProperty[1]|'(Q)'])+$k.property.name->toOne(),
value = $k,
children = $m->get($k).values->map(l|^$l(values=$l.values->slice(1, $l.values->size())))->recurseBuildTree(),
qualifierSubTree = $k.nestedQualifier->buildPropertyTree()
)
);
}
function <> meta::pure::lineage::scanProperties::propertyTree::srcClass(property:AbstractProperty[1]):Type[1]
{
$property->match([
q:QualifiedProperty[1]|$q->functionType().parameters->evaluateAndDeactivate()->at(0).genericType.rawType->toOne(),
p:Property[1]|$p.classifierGenericType.typeArguments->at(0).rawType->toOne()
]);
}
function meta::pure::lineage::scanProperties::propertyTree::buildPropertyTree(executes:Execute[*]):PropertyPathTree[1]
{
let properyLists = $executes->map(exec|$exec.funcEntryPoint->scanProperties(emptyPath(), [], []););
$properyLists.result->buildPropertyTree();
}
function meta::pure::lineage::scanProperties::propertyTree::buildPropertyTree(properyLists:List[*]):PropertyPathTree[1]
{
let filteredPropertyLists = $properyLists->filter(f|$f.values->isNotEmpty());
let grpByClass = $filteredPropertyLists->groupBy(v|$v.values->at(0).class);
let propertyTree = ^PropertyPathTree(display='root',
value='root',
children = $grpByClass->keys()->map(c|^PropertyPathTree(display=$c.name->toOne(), value=$c, children=$grpByClass->get($c).values->recurseBuildTree()))//filteredPropertyLists->recurse()
);
}
function meta::pure::lineage::scanProperties::propertyTree::printTree(t:PropertyPathTree[1], space:String[1]):String[1]
{
$space+$t.value->match([c:Class[1]|'c_'+$c.name->toOne()+'\n',
a:String[1]|$a+'\n',
p:PropertyPathNode[1]|'p_'+$p.class.name->toOne()+'.'+$p.property.name->toOne()+'\n'+if($p.nestedQualifier->isEmpty(),|'',|$p.nestedQualifier->buildPropertyTree()->printTree($space+' __ '));
])+
$t.children->sort({a,b| if($a.value->instanceOf(PropertyPathNode) && $b.value->instanceOf(PropertyPathNode),
|let c = $a.value->cast(@PropertyPathNode);
let d = $b.value->cast(@PropertyPathNode);
let e = $c.class.name->toOne()+'.'+$c.property.name->toOne();
let f = $d.class.name->toOne()+'.'+$d.property.name->toOne();
$e->compare($f);,
|0
);
})
->map(c|$c->printTree($space+' '))->joinStrings('');
}
function meta::pure::lineage::scanProperties::inlineQualifiedPropertyNodes(p: PropertyPathTree[1]):PropertyPathTree[1]
{
meta::pure::lineage::scanProperties::inlineQualifiedPropertyNodes($p, defaultScanConfig());
}
function meta::pure::lineage::scanProperties::inlineQualifiedPropertyNodes(p: PropertyPathTree[1], config:ScanConfig[1]):PropertyPathTree[1]
{
$p->recurse_inlineQualifiedPropertyNodes($config)->toOne();
}
function <> meta::pure::lineage::scanProperties::recurse_inlineQualifiedPropertyNodes(p: PropertyPathTree[1], config:ScanConfig[1]):PropertyPathTree[*]
{
let newTrees = if($p.value->instanceOf(PropertyPathNode) && $p.value->cast(@PropertyPathNode).property->instanceOf(QualifiedProperty)
&& ! $p.value->cast(@PropertyPathNode).property->isMilestonedGeneratedQualifiedProperty(),
{|
if($p.children->isEmpty(),
| $p.qualifierSubTree.children.children,
{|
let qual = $p.value->cast(@PropertyPathNode).property->cast(@QualifiedProperty);
let qualifierTreeCurrent = $qual.expressionSequence->evaluateAndDeactivate()->toOne()->internal_scanProperties([], noVars(), $config,^Map(), noDebug()).current;
let qualifierTree = $p.qualifierSubTree.children->toOne();
findAndAddChildrenAtTheEnd($qualifierTree, $qualifierTreeCurrent.values, $p.children).children;
}
)->map(nt| $nt->recurse_inlineQualifiedPropertyNodes($config));
},
| $p
);
$newTrees->map(t| ^$t(children=$t.children->map(c| $c->recurse_inlineQualifiedPropertyNodes($config))));
}
function meta::pure::lineage::scanProperties::propertyTree::buildMultiLevelPropertyTrees(vs:ValueSpecification[1], mappings:Mapping[*], extensions:meta::pure::extension::Extension[*]):PropertyPathTree[*]
{
$vs->buildMultiLevelPropertyTrees($mappings, $extensions, noDebug())
}
function meta::pure::lineage::scanProperties::propertyTree::buildMultiLevelPropertyTrees(vs:ValueSpecification[1], mappings:Mapping[*], extensions:meta::pure::extension::Extension[*], debug:DebugContext[1]):PropertyPathTree[*]
{
let res = ^Pair>(first=$vs, second=^List(values=[$vs->scanProperties( $debug).result->buildPropertyTree()]));
$mappings->fold({a, b| let reprocessedQuery = $b.first->cast(@FunctionExpression)->meta::pure::mapping::modelToModel::chain::allReprocess([], $a, $extensions, $debug).res;
let newPropertyTree = $reprocessedQuery->scanProperties($debug).result->buildPropertyTree();
^$b(first = $reprocessedQuery,
second = ^List(values=$b.second.values->concatenate($newPropertyTree)));
},
$res).second.values;
}