diff --git a/pom.xml b/pom.xml index b76dcf8b..942d5bbd 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.rascalmpl typepal - 0.15.6-SNAPSHOT + 0.16.1-SNAPSHOT jar diff --git a/src/analysis/typepal/Collector.rsc b/src/analysis/typepal/Collector.rsc index 29a7e4f8..ba7d534a 100644 --- a/src/analysis/typepal/Collector.rsc +++ b/src/analysis/typepal/Collector.rsc @@ -32,6 +32,13 @@ import analysis::typepal::Messenger; extend analysis::typepal::ConfigurableScopeGraph; extend analysis::typepal::ICollector; +// TODO: remove these temporary copies of isContainedIn and isBefore +// (needed to break deployment cycle). They should reside in Location.rsc +private bool isContainedIn(loc inner, loc outer, map[loc,loc] m) + = isContainedIn(inner in m ? m[inner] : inner, outer in m ? m[outer] : outer); +bool isBefore(loc inner, loc outer, map[loc,loc] m) + = isBefore(inner in m ? m[inner] : inner, outer in m ? m[outer] : outer); + // Extract (nested) tree locations and type variables from a list of dependencies list[loc] dependenciesAslocList(list[value] dependencies){ return @@ -194,101 +201,6 @@ Collector newCollector(str modelName, Tree pt, TypePalConfig config){ return newCollector(modelName, (modelName : pt), config); } -// The following function can be written with a single (expensive) visit -// This version avoids visits as much as possible -private TModel convertLocs(TModel tm, map[loc,loc] locMap){ - defines = {}; - definitions = (); - for(d: <- tm.defines){ - defi = visit(defInfo){ case loc l => locMap[l] when l in locMap }; - d1 = d[scope=(scope in locMap ? locMap[scope] : scope)] - [defined=(defined in locMap ? locMap[defined] : defined)] - [defInfo=defi]; - defines += d1; - definitions[d1.defined] = d1; - } - tm.defines = defines; - tm.definitions = definitions; - - tm.scopes = ( (outer in locMap ? locMap[outer] : outer) : (inner in locMap ? locMap[inner] : inner) - | loc outer <- tm.scopes, loc inner := tm.scopes[outer] - ); - tm.paths = { <(from in locMap ? locMap[from] : from), - pathRole, - (to in locMap ? locMap[to] : to)> - | <- tm.paths - }; - - tm.referPaths = visit(tm.referPaths){ case loc l => locMap[l] when l in locMap }; - tm.uses = visit(tm.uses){ case loc l => locMap[l] when l in locMap }; - tm.definesMap = visit(tm.definesMap){ case loc l => locMap[l] when l in locMap }; - tm.moduleLocs = ( key : (l in locMap ? locMap[l] : l) - | key <- tm.moduleLocs, l := tm.moduleLocs[key] - ); - facts = tm.facts; - tm.facts = ((l in locMap ? locMap[l] : l) - : ( (overloadedAType(rel[loc, IdRole, AType] overloads) := atype) - ? overloadedAType({ <(l in locMap ? locMap[l] : l), idr, at> | <- overloads }) - : atype) - | l <- facts, atype := facts[l] - ); - //tm.facts = visit(tm.facts){ case loc l => locMap[l] ? l }; - tm.specializedFacts = - ((l in locMap ? locMap[l] : l) - : ( (overloadedAType(rel[loc, IdRole, AType] overloads) := atype) - ? overloadedAType({ <(l in locMap ? locMap[l] : l), idr, at> | <- overloads }) - : atype) - | l <- tm.specializedFacts, atype := tm.specializedFacts[l] - ); - //tm.specializedFacts = visit(tm.specializedFacts){ case loc l => locMap[l] ? l }; - tm.useDef = { < (f in locMap ? locMap[f] : f), - (t in locMap ? locMap[t] : t) > - | <- tm.useDef }; - // Exlude messages from conversion: otherwise users would see logical locations - //tm.messages = visit(tm.messages){ case loc l => locMap[l] ? l }; - tm.store = visit(tm.store){ case loc l => locMap[l] when l in locMap}; - tm.config = visit(tm.config){ case loc l => locMap[l] when l in locMap}; - return tm; -} - -TModel convertTModel2PhysicalLocs(TModel tm){ - if(!tm.usesPhysicalLocs){ - logical2physical = tm.logical2physical; - tm.logical2physical = (); - tm = convertLocs(tm, logical2physical); - tm.logical2physical = logical2physical; - tm.usesPhysicalLocs = true; - } - return tm; -} - -TModel convertTModel2LogicalLocs(TModel tm, map[str,TModel] tmodels){ - if(tm.usesPhysicalLocs){ - tmodels[tm.modelName] = tm; - physical2logical = (); - try { - physical2logical = invertUnique((() | it + tm1.logical2physical | tm1 <- range(tmodels))); - } catch MultipleKey(value physLoc, value _, value _):{ - where = loc l := physLoc ? l : |unknown:///|; - // find the offending modules - mnames = {}; - for(mname <- domain(tmodels)){ - if(physLoc in range(tmodels[mname].logical2physical)){ - mnames += mname; - } - } - tm.messages += [error("Please recheck modules ; their mapping from physical to logical locations is outdated", where)]; - return tm; - } - logical2physical = tm.logical2physical; - tm.logical2physical = (); - tm = convertLocs(tm, physical2logical); - tm.logical2physical = logical2physical; - tm.usesPhysicalLocs = false; - } - return tm; -} - Collector newCollector(str modelName, map[str,Tree] namedTrees, TypePalConfig config){ str normalizeName(str input) { @@ -296,8 +208,18 @@ Collector newCollector(str modelName, map[str,Tree] namedTrees, TypePalConfig co } loc globalScope = |global-scope:///|; Defines defines = {}; + Defines addedDefines = {}; map[loc,loc] logical2physical = (); + + map[loc,loc] physical2logical = (); + + loc getLogicalLoc(loc l) + = l in physical2logical ? physical2logical[l] : l; + + loc getLogicalLoc(Tree t) + = getLogicalLoc(getLoc(t)); + map[loc, set[Define]] definesPerLubScope = (globalScope: {}); map[loc, set[Define]] lubDefinesPerLubScope = (globalScope: {}); map[loc, rel[str id, str orgId, loc idScope, set[IdRole] idRoles, loc occ]] lubUsesPerLubScope = (globalScope: {}); @@ -305,18 +227,24 @@ Collector newCollector(str modelName, map[str,Tree] namedTrees, TypePalConfig co Scopes scopes = (); map[loc, set[loc]] scopesStar = (globalScope: {}); + Scopes addedScopes = (); Paths paths = {}; + Paths addedPaths = {}; + set[ReferPath] referPaths = {}; Uses uses = []; map[str,value] storeVals = (); map[loc,AType] facts = (); + map[loc,AType] addedFacts = (); + set[Calculator] calculators = {}; set[Requirement] requirements = {}; int ntypevar = 0; list[Message] messages = []; - + list[Message] addedMessages = []; + loc currentScope = globalScope; loc rootScope = globalScope; @@ -334,10 +262,9 @@ Collector newCollector(str modelName, map[str,Tree] namedTrees, TypePalConfig co if(Tree tdef := def) l = getLoc(tdef); else if(loc ldef := def) l = ldef; else throw TypePalUsage("Argument `def` of `define` should be `Tree` or `loc`, found "); - - def_tup = ; nname = normalizeName(orgId); - + Define newDef = ; + logL = buildLogical2physical(newDef); if(info is defTypeLub){ // Look for an outer variable declaration of id that overrules the defTypeLub for(Define def <- defines + definesPerLubScope[currentLubScope]){ @@ -348,9 +275,9 @@ Collector newCollector(str modelName, map[str,Tree] namedTrees, TypePalConfig co } } } - lubDefinesPerLubScope[currentLubScope] += ; + lubDefinesPerLubScope[currentLubScope] += newDef; } else { - definesPerLubScope[currentLubScope] += ; + definesPerLubScope[currentLubScope] += newDef; } } else { throw TypePalUsage("Cannot call `define` on Collector after `run`"); @@ -387,15 +314,14 @@ Collector newCollector(str modelName, map[str,Tree] namedTrees, TypePalConfig co { def | def <- lubDefinesPerLubScope[currentLubScope], def.id == id }; // is there an inferred declaration? - if(!isEmpty(lubdefs) && any(def <- lubdefs, isContainedIn(useOrDefLoc, def.scope))){ + if(!isEmpty(lubdefs) && any(def <- lubdefs, isContainedIn(useOrDefLoc, def.scope, logical2physical))){ //println("isAlreadyDefined , : true"); return true; } // is there a top-level declaration? - - for(def <- defines, def.id == id, config.isInferrable(def.idRole), def.scope in scopes, - (isContainedIn(useOrDefLoc, def.scope) || scopes[def.scope] == |global-scope:///|)){ + for(def <- defines, def.id == id, def.scope in scopes, config.isInferrable(def.idRole), + (isContainedIn(useOrDefLoc, def.scope, logical2physical) || scopes[def.scope] == |global-scope:///|)){ //println("isAlreadyDefined , : true"); return true; } @@ -416,10 +342,12 @@ Collector newCollector(str modelName, map[str,Tree] namedTrees, TypePalConfig co else throw TypePalUsage("Argument `def` of `defineInScope` should be `Tree` or `loc`, found "); nname = normalizeName(orgId); + Define newDef = ; + logL = buildLogical2physical(newDef); if(info is defTypeLub){ throw TypePalUsage("`defLub` cannot be used in combination with `defineInScope`"); } else { - defines += ; + defines += newDef; } } else { throw TypePalUsage("Cannot call `defineInScope` on Collector after `run`"); @@ -565,7 +493,7 @@ Collector newCollector(str modelName, map[str,Tree] namedTrees, TypePalConfig co } } } else { - throw TypePalUsage("Cannot call `leaveScope` with scope that is not the current scope", [innerLoc]); + throw TypePalUsage("Cannot call `leaveScope` with scope that is not the current scope", [innerLoc, currentScope]); } } else { throw TypePalUsage("Cannot call `leaveScope` on Collector after `run`"); @@ -744,8 +672,8 @@ Collector newCollector(str modelName, map[str,Tree] namedTrees, TypePalConfig co if(loc l := fm.src) sloc = l; else if(Tree t := fm.src) sloc = getLoc(t); else throw TypePalUsage("Subject in error should be have type `Tree` or `loc`, found "); - requirements += reqError(sloc, [], fm); - return true; + requirements += reqError(sloc, [], fm); + return true; } else { throw TypePalUsage("Cannot call `report` on Collector after `run`"); } @@ -758,8 +686,8 @@ Collector newCollector(str modelName, map[str,Tree] namedTrees, TypePalConfig co if(loc l := fm.src) sloc = l; else if(Tree t := fm.src) sloc = getLoc(t); else throw TypePalUsage("Subject in error should be have type `Tree` or `loc`, found "); - requirements += reqErrors(sloc, [], fms); - return true; + requirements += reqErrors(sloc, [], fms); + return true; } else { throw TypePalUsage("Cannot call `reports` on Collector after `run`"); } @@ -835,7 +763,7 @@ Collector newCollector(str modelName, map[str,Tree] namedTrees, TypePalConfig co tuple[list[loc] deps, list[loc] defs] computeDepsAndDefs(set[loc] deps, set[loc] defs, set[Use] uses, loc lubDefScope, rel[loc,loc] enclosedScopes){ if(isEmpty(uses)) return ; - depsWithNestedUse = { d | d <- deps, u <- uses, isContainedIn(u.occ, d) }; + depsWithNestedUse = { d | d <- deps, u <- uses, isContainedIn(u.occ, d, logical2physical) }; scopesEnclosedByLubDef = enclosedScopes[lubDefScope]; return ; } @@ -1000,14 +928,19 @@ Collector newCollector(str modelName, map[str,Tree] namedTrees, TypePalConfig co if(!isValidTplVersion(tm.version)){ throw wrongTplVersion("TModel for uses TPL version , but is required"); } - tm = convertTModel2PhysicalLocs(tm); logical2physical += tm.logical2physical; - messages += tm.messages; + addedMessages += tm.messages; + addedScopes += tm.scopes; scopes += tm.scopes; + + addedDefines += tm.defines; defines += tm.defines; + + addedFacts += tm.facts; facts += tm.facts; + addedPaths += tm.paths; paths += tm.paths; } @@ -1022,32 +955,30 @@ Collector newCollector(str modelName, map[str,Tree] namedTrees, TypePalConfig co return l; } - map[loc,loc] buildLogical2physical(Defines defines){ - map[loc,loc] my_logical2physical = logical2physical; - map[loc,loc] my_physical2logical = (); - try { - my_physical2logical = invertUnique(logical2physical); - } catch MultipleKey(value key, value _first, value _second):{ - where = loc l := key ? l : |unknown:///|; - messages += error("Mapping from physical to logical locations is not unique; remove outdated information and try again", where); - return (); - } - for(Define def <- defines){ - logicalLoc = my_physical2logical[def.defined] ? config.createLogicalLoc(def, modelName, config.typepalPathConfig); - if(logicalLoc != def.defined){ - if(logicalLoc in my_logical2physical){ - if(my_logical2physical[logicalLoc] != def.defined){ - causes = [ info("Clone of ``", my_logical2physical[logicalLoc]), - info("Clone of ``", def.defined) - ]; - // restrict clone location to first line for readability - messages += error("Remove code clone for ``", limitLocToFirstLine(def.defined), causes=causes); - } + loc buildLogical2physical(Define def){ + if(def.defined in logical2physical) return logical2physical[def.defined]; + loc logicalLoc = physical2logical[def.defined] ? config.createLogicalLoc(def, modelName, config.typepalPathConfig); + if(logicalLoc != def.defined){ + if(logicalLoc in logical2physical){ + if(logical2physical[logicalLoc] != def.defined){ + causes = [ info("Clone of ``", logical2physical[logicalLoc]), + info("Clone of ``", def.defined) + ]; + // restrict clone location to first line for readability + messages += error("Remove code clone for ``", limitLocToFirstLine(def.defined), causes=causes); } - my_logical2physical[logicalLoc] = def.defined; } + logical2physical[logicalLoc] = def.defined; + physical2logical[def.defined] = logicalLoc; } - return my_logical2physical; + return logicalLoc; + } + + &T toLogicalLocs(&T v){ + return visit(v){ case loc l => physical2logical[l] when l in physical2logical }; + } + &T toPhysicalLocs(&T v){ + return visit(v){ case loc l => logical2physical[l] when l in logical2physical }; } TModel collector_run(){ @@ -1063,36 +994,39 @@ Collector newCollector(str modelName, map[str,Tree] namedTrees, TypePalConfig co throw TypePalUsage("Missing `leaveScope`(s): unclosed scopes "); } - tm = tmodel()[usesPhysicalLocs=true]; + tm = tmodel(); tm.modelName = modelName; + tm.logical2physical = logical2physical; - tm.moduleLocs = (nm : getLoc(namedTrees[nm]) | nm <- namedTrees); + tm.moduleLocs = (nm : getLogicalLoc(namedTrees[nm]) | nm <- namedTrees); - tm.facts = facts; facts = (); + tm.facts = toLogicalLocs(facts - addedFacts) + addedFacts; facts = addedFacts = (); tm.config = config; + defines = finalizeDefines(); - tm.defines = defines; - tm.scopes = scopes; scopes = (); - tm.paths = paths; - tm.referPaths = referPaths; - tm.uses = uses; uses = []; - - tm.calculators = calculators; calculators = {}; - tm.requirements = requirements; requirements = {}; - tm.store = storeVals; storeVals = (); - tm.definitions = ( def.defined : def | Define def <- defines); + + tm.defines = toLogicalLocs(defines - addedDefines) + addedDefines; + tm.definitions = ( def.defined : def | Define def <- tm.defines); map[loc, map[str, rel[IdRole idRole, loc defined]]] definesMap = (); - for( <- defines){ + for( <- tm.defines){ map[str, rel[IdRole idRole, loc defined]] dm = (); if(scope in definesMap) dm = definesMap[scope]; - dm[id] = (dm[id] ? {}) + {}; + dm[id] = (id in dm ? dm[id] : {}) + {}; definesMap[scope] = dm; } tm.definesMap = definesMap; + definesMap = (); defines = addedDefines = {}; + + tm.scopes = toLogicalLocs(scopes - addedScopes) + addedScopes; scopes = addedScopes = (); + tm.paths = toLogicalLocs(paths - addedPaths) + addedPaths; paths = addedPaths = {}; + tm.referPaths = toLogicalLocs(referPaths); referPaths = {}; + tm.uses = toLogicalLocs(uses); uses = []; - tm.logical2physical = buildLogical2physical(defines); - defines = {}; - tm.messages = messages; + tm.calculators = toLogicalLocs(calculators); calculators = {}; + tm.requirements = toLogicalLocs(requirements); requirements = {}; + tm.store = toLogicalLocs(storeVals); storeVals = (); + tm.messages = toList(toSet(toPhysicalLocs(messages) + addedMessages)); messages = addedMessages = []; + physical2logical = logical2physical = (); return tm; } else { @@ -1305,9 +1239,9 @@ default void collect(Tree currentTree, Collector c){ if(currentTree has prod){ switch(getName(currentTree.prod.def)){ case "label": - { p = currentTree.prod; collect(appl(prod(p.def.symbol, p.symbols, p.attributes/*, src=getLoc(currentTree)*/), currentTree.args), c); } + { p = currentTree.prod; collect(appl(prod(p.def.symbol, p.symbols, p.attributes/*, src=getLogicalLoc(currentTree)*/), currentTree.args), c); } case "start": - { p = currentTree.prod; collect(appl(prod(p.def.symbol, p.symbols, p.attributes/*, src=getLoc(currentTree)*/), currentTree.args), c); } + { p = currentTree.prod; collect(appl(prod(p.def.symbol, p.symbols, p.attributes/*, src=getLogicalLoc(currentTree)*/), currentTree.args), c); } case "sort": { args = currentTree.args; nargs = size(args); @@ -1315,7 +1249,7 @@ default void collect(Tree currentTree, Collector c){ else if(nargs > 0) { c.report(info(currentTree, "Missing `collect` for %q", treeAsMessage(currentTree))); collectArgs2(args, c); - //was: throw TypePalUsage("Missing `collect` for ", [getLoc(currentTree)]); + //was: throw TypePalUsage("Missing `collect` for ", [getLogicalLoc(currentTree)]); } } case "parameterized-sort": @@ -1326,7 +1260,7 @@ default void collect(Tree currentTree, Collector c){ else if(nargs > 0) { c.report(info(currentTree, "Missing `collect` for %q", treeAsMessage(currentTree))); collectArgs2(args, c); - //was: throw TypePalUsage("Missing `collect` for ", [getLoc(currentTree)]); + //was: throw TypePalUsage("Missing `collect` for ", [getLogicalLoc(currentTree)]); } } case "lex": @@ -1350,7 +1284,7 @@ default void collect(Tree currentTree, Collector c){ else if(nargs > 0) { c.report(info(currentTree, "Missing `collect` for %q", treeAsMessage(currentTree))); collectArgs2(args, c); - // was throw TypePalUsage("Missing `collect` for ", [getLoc(currentTree)]); + // was throw TypePalUsage("Missing `collect` for ", [getLogicalLoc(currentTree)]); } } } diff --git a/src/analysis/typepal/ConfigurableScopeGraph.rsc b/src/analysis/typepal/ConfigurableScopeGraph.rsc index da8a4d9d..5e61dc84 100644 --- a/src/analysis/typepal/ConfigurableScopeGraph.rsc +++ b/src/analysis/typepal/ConfigurableScopeGraph.rsc @@ -24,6 +24,7 @@ extend analysis::typepal::ISolver; import IO; import Set; +import Relation; import Map; import util::PathConfig; import String; @@ -215,10 +216,34 @@ data ScopeGraph void (Solver s) setSolver ); -bool wdebug = false; + ScopeGraph newScopeGraph(TModel tm, TypePalConfig config){ +// Debug support: prints nicely indented traces of calls. +// It is commented out since it is rather expensive for these +// high-frequency functions + + // bool wdebug = false; + // str dbg_indent = ""; + + // void incr(){ dbg_indent += " "; } + // void decr() { dbg_indent = dbg_indent[..-4]; } + + // void dbgEnter(str s) { if(wdebug) { incr(); println(""); } } + // void dbg(str s) { if(wdebug) println(""); } + // void dbgLeave(str s) { if(wdebug){ println(""); decr(); } } + + // void dbgPaths(){ + // incr(); + // for(p <- tm.paths){ + // dbg("path: "); + // dbg(" "); + // dbg(" "); + // } + // decr(); + // } + /*************************************************************************/ /* At the moment we support "classic" scopes from the Kastens & Waite */ /* article and "wide" scopes as used for Rascal. We still have to settle */ @@ -375,36 +400,35 @@ ScopeGraph newScopeGraph(TModel tm, TypePalConfig config){ /* lookupWide returns all definitions in the current syntactic scope (or its */ /* parents) and definitions that can be reached in a single step via semantic links */ /************************************************************************************/ - + //@memo // Retrieve all bindings for use in given syntactic scope private set[loc] bindWide(loc scope, str id, set[IdRole] idRoles){ - preDefs = (tm.definesMap[scope] ? ())[id] ? {}; - - if(isEmpty(preDefs) || isEmpty(preDefs<0> & idRoles)) return {}; - return preDefs<1>; + idsInScope = (scope in tm.definesMap) ? tm.definesMap[scope] : (); + foundDefs = id in idsInScope ? domainR(idsInScope[id], idRoles)<1> : {}; + // dbg("bindWide: , =\> "); + return foundDefs; } // Lookup use in the given syntactic scope private set[loc] lookupScopeWide(loc scope, Use use){ - //if(wdebug) println("\tlookupScopeWide: in scope "); - - return {def | def <- bindWide(scope, use.id, use.idRoles), isAcceptableSimpleFun(def, use, the_solver) == acceptBinding()}; + // dbgEnter("lookupScopeWide: in scope "); + res = {def | def <- bindWide(scope, use.id, use.idRoles), isAcceptableSimpleFun(def, use, the_solver) == acceptBinding()}; + // dbgLeave("lookupScopeWide: in scope =\> "); + return res; } //@memo // Find all (semantics induced, one-level) bindings for use in given syntactic scope via PathRole private set[loc] lookupPathsWide(loc scope, Use use, PathRole pathRole){ - //if(wdebug) println("\tlookupPathsWide: in scope , role \n\t----

\n<}>"); + // dbgEnter("lookupPathsWide: in scope , role ");; res = {}; seenParents = {}; solve(res, scope) { next_path: - for(loc parent <- ((pathsCache[pathRole] ? {})[scope] - seenParents)){ + for( <- pathsByPathRole[pathRole] ? {}, parent notin seenParents){ seenParents += parent; - //if(wdebug) println("\tlookupPathsWide: scope: , trying semantic path to: "); - for(loc def <- lookupScopeWide(parent, use)){ switch(isAcceptablePathFun(parent, def, use, pathRole, the_solver)){ case acceptBinding(): @@ -417,22 +441,20 @@ ScopeGraph newScopeGraph(TModel tm, TypePalConfig config){ } } } - //if(wdebug) println("\tlookupPathsWide: in scope , ==\> "); + // dbgLeave("lookupPathsWide: in scope , ==\> "); return res; } // Lookup use in given syntactic scope and via all semantic paths private set[loc] lookupQualWide(loc scope, Use u){ - //if(wdebug) println("\tlookupQualWide: in scope "); + // dbgEnter("lookupQualWide: in scope "); res = lookupScopeWide(scope, u); - //if(wdebug) println("\tlookupQualWide: in scope , after lookupScopeWide:\n\t--\> <}>"); - - //if(wdebug) println("\tlookupQualWide: , loop over "); + nextPath: for(PathRole pathRole <- pathRoles){ candidates = lookupPathsWide(scope, u, pathRole); - //if(wdebug) println("\tlookupQualWide: candidates: "); + // dbg("lookupQualWide: candidates: "); for(loc candidate <- candidates){ switch(isAcceptableSimpleFun(candidate, u, the_solver)){ case acceptBinding(): @@ -444,51 +466,56 @@ ScopeGraph newScopeGraph(TModel tm, TypePalConfig config){ } } } - + // dbgLeave("lookupQualWide: in scope =\> "); return res; } // Lookup use in syntactic scope and via all semantic paths, // recur to syntactic parent until found private set[loc] lookupNestWide(loc scope, Use u){ - //if(wdebug) println("\tlookupNestWide: in scope "); + // dbgEnter("lookupNestWide: in scope "); res = lookupQualWide(scope, u); - //if(wdebug) println("\tlookupNestWide: in scope found:\n\t==\> <}>"); - if(!isEmpty(res)) return res; // <<< - if(tm.scopes[scope] ?){ - if(scope == tm.scopes[scope]) { println("Identical scope in lookupNestWide: "); return res; } + if(!isEmpty(res)) { + // dbgLeave("lookupNestWide: in scope =\> "); + return res; // <<< + } + + if(scope in tm.scopes){ + if(scope == tm.scopes[scope]) { + // dbg("Identical scope in lookupNestWide: "); + return res; + } parent = tm.scopes[scope]; - //if(wdebug) println("\tlookupNestWide: in scope move up to "); res += lookupNestWide(parent, u); } - + // dbgLeave("lookupNestWide: in scope =\> "); return res; } public set[loc] lookupWide(Use u){ // Update current paths and pathRoles - current_paths = the_solver.getPaths(); //tm.paths; - if(current_paths != paths){ - paths = current_paths; - updatePathCache(); - pathRoles = paths.pathRole; + current_pathsByPathRole = the_solver.getPathsByPathRole(); + if(current_pathsByPathRole != pathsByPathRole){ + pathsByPathRole = current_pathsByPathRole; + pathRoles = domain(pathsByPathRole); } scope = u.scope; - //if(wdebug) println("lookupWide: "); + // dbg("\nlookupWide: \n"); + // dbgPaths(); if(!(u has qualifierRoles)){ defs = {def | loc def <- lookupNestWide(scope, u), isAcceptableSimpleFun(def, u, the_solver) == acceptBinding()}; - //if(wdebug) println("lookupWide: returns:\n\t==\> <}>"); + // dbg("lookupWide: =\> "); if(isEmpty(defs)) throw NoBinding(); else return defs; } else { startScope = scope; qscopes = {}; for(str id <- u.ids[0..-1]){ - //if(wdebug) println("lookup, search for "); + // dbg("lookup, search for "); qscopes = lookupNestWide(scope, use(id, "", u.occ, scope, u.qualifierRoles)); if(isEmpty(qscopes)) throw NoBinding(); } @@ -499,32 +526,26 @@ ScopeGraph newScopeGraph(TModel tm, TypePalConfig config){ defs += { def | def <- scopeLookups, isAcceptableQualifiedFun(def, u, the_solver) == acceptBinding()}; } if(!isEmpty(defs)){ - //if(wdebug) println("lookupWide: returns:\n\t==\> <}>"); + // dbg("lookupWide: returns:\n\t==\> <}>"); return defs; } } throw NoBinding(); } - private void updatePathCache() { - rel[loc, loc] empty_rel = {}; - pathsCache = (); - for ( <- paths) { - pathsCache[pr] ? empty_rel += {}; - } - } - Paths paths = {}; - map[PathRole, rel[loc,loc]] pathsCache = (); + // Paths paths = {}; set[PathRole] pathRoles = {}; + map[PathRole,rel[loc,loc]] pathsByPathRole = (); Solver the_solver = dummySolver(); void do_setSolver(Solver s){ the_solver = s; - paths = the_solver.getPaths(); - updatePathCache(); - pathRoles = paths.pathRole; + pathsByPathRole = the_solver.getPathsByPathRole(); + pathRoles = domain(pathsByPathRole); + // paths = the_solver.getPaths(); + // pathRoles = paths.pathRole; } // Initialize the ScopeGraph context diff --git a/src/analysis/typepal/ISolver.rsc b/src/analysis/typepal/ISolver.rsc index f3b7aaa0..40992af4 100644 --- a/src/analysis/typepal/ISolver.rsc +++ b/src/analysis/typepal/ISolver.rsc @@ -59,10 +59,13 @@ data Solver /* Global Info */ TypePalConfig () getConfig, map[loc, AType]() getFacts, Paths() getPaths, + map[PathRole,rel[loc,loc]]() getPathsByPathRole, set[Define] (str id, loc scope, set[IdRole] idRoles) getDefinitions, // deprecated set[Define] () getAllDefines, Define(loc) getDefine, rel[loc,loc] () getUseDef, + bool(loc,loc) isContainedIn, + bool(loc,loc) isBefore, /* Nested Info */ void(str key, value val) push, value (str key) pop, diff --git a/src/analysis/typepal/Solver.rsc b/src/analysis/typepal/Solver.rsc index ea27d5ed..da101e39 100644 --- a/src/analysis/typepal/Solver.rsc +++ b/src/analysis/typepal/Solver.rsc @@ -82,6 +82,8 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ map[loc,loc] logical2physical = tm.logical2physical; + map[PathRole, rel[loc,loc]] pathsByPathRole = (); + void configTypePal(TypePalConfig tc){ normalizeName = tc.normalizeName; @@ -119,9 +121,17 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ map[loc, AType] solver_getFacts() = facts; - Paths solver_getPaths() { - res = tm.paths; - return res; + Paths solver_getPaths() = tm.paths; + + map[PathRole,rel[loc,loc]] solver_getPathsByPathRole() = pathsByPathRole; + + loc getLogicalLoc(Tree t){ + l = getLoc(t); + return l in physical2logical ? physical2logical[l] : l; + } + + loc getLogicalLoc(loc l){ + return l in physical2logical ? physical2logical[l] : l; } //value _getStore(str key) = tm.store[key]; @@ -197,9 +207,9 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ list[Message] messages = []; list[FailMessage] failMessages = []; - set[ReferPath] referPaths = tm.referPaths; - + map[loc,loc] physical2logical = invertUnique(tm.logical2physical); + set[ReferPath] referPaths = tm.referPaths; // Error reporting @@ -312,7 +322,7 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ calculators += calcType(defined, atype); } } else if(Tree from := tp){ - fromLoc = getLoc(from); + fromLoc = getLogicalLoc(from); if(fromLoc in facts){ facts[defined] = facts[fromLoc]; } else { @@ -550,11 +560,14 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ AType solver_getType(value v){ try { switch(v){ - case Tree tree: return instantiate(findType(tree@\loc)); - case tvar(loc l): return facts[l]; + case Tree tree: return instantiate(findType(getLogicalLoc(tree))); + case tvar(loc l): return facts[getLogicalLoc(l)]; case AType atype: return instantiate(atype); - case loc l: return l in specializedFacts ? specializedFacts[l] : facts[l]; - case defType(value v) : if(AType atype := v) return atype; else if(Tree tree := v) return instantiate(findType(tree@\loc)); + case loc l: { + l = getLogicalLoc(l); + return l in specializedFacts ? specializedFacts[l] : facts[l]; + } + case defType(value v) : if(AType atype := v) return atype; else if(Tree tree := v) return instantiate(findType(getLogicalLoc(tree))); case Define def: return solver_getType(def.defInfo); case defTypeCall(list[loc] _, AType(Solver s) getAType): return getAType(thisSolver); @@ -593,7 +606,7 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ //@memo AType solver_getTypeInScopeFromName(str name, loc scope, set[IdRole] idRoles){ try { - return getTypeInScopeFromName0(name, scope, idRoles); + return getTypeInScopeFromName0(name, getLogicalLoc(scope), idRoles); } catch NoSuchKey(value _): throw TypeUnavailable(); } @@ -631,7 +644,7 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ //@memo AType solver_getTypeInScope(Tree occ, loc scope, set[IdRole] idRoles){ try { - return getTypeInScope0(occ, scope, idRoles); + return getTypeInScope0(occ, getLogicalLoc(scope), idRoles); } catch NoSuchKey(_): throw TypeUnavailable(); } @@ -654,7 +667,8 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ } AType solver_getTypeInType(AType containerType, Tree selector, set[IdRole] idRolesSel, loc scope){ - selectorLoc = getLoc(selector); + selectorLoc = getLogicalLoc(getLoc(selector)); + scope = getLogicalLoc(scope); selectorOrgName = ""; selectorName = normalizeName(selectorOrgName); @@ -741,6 +755,7 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ } rel[str id, AType atype] solver_getAllDefinedInType(AType containerType, loc scope, set[IdRole] idRoles){ + scope = getLogicalLoc(scope); = getTypeNamesAndRole(containerType); if(!isEmpty(containerNames)){ containerName = containerNames[0]; @@ -764,6 +779,7 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ } set[Define] solver_getDefinitions(str id, loc scope, set[IdRole] idRoles){ + scope = getLogicalLoc(scope); try { foundDefs = scopeGraph.lookup(use(id, id, anonymousOccurrence, scope, idRoles)); if({def} := foundDefs){ @@ -784,11 +800,20 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ set[Define] solver_getAllDefines() = tm.defines; - Define solver_getDefine(loc l) = definitions[l]; + Define solver_getDefine(loc l) = definitions[getLogicalLoc(l)]; rel[loc,loc] solver_getUseDef() = { *{ | loc d <- definedBy[u]} | loc u <- definedBy }; + bool solver_isContainedIn(loc inner, loc outer) + = isContainedIn(inner, outer, logical2physical); + + bool solver_isBefore(loc l, loc r) + = isBefore(l, r, logical2physical); + + loc solver_toPhysicalLoc(loc l) + = l in logical2physical ? logical2physical[l] : l; + // ---- resolvePath ------------------------------------------------------- bool resolvePaths(){ @@ -796,8 +821,7 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ referPaths = tm.referPaths; for(ReferPath rp <- referPaths){ try { - if(referToDef(Use _, PathRole _) := rp){ - u = rp.use; + if(referToDef(Use u, PathRole _) := rp){ foundDefs = scopeGraph.lookup(u); if({loc def} := foundDefs){ definedBy[u.occ] = foundDefs; @@ -838,10 +862,20 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ ;/* ignore until end */ } } - newPaths = { tup | tup: <- newPaths, u != d }; - tm.paths += newPaths; + newPaths = { tup | tup: <- newPaths, u != d }; tm.referPaths = referPaths; - return !isEmpty(newPaths); + newPathFound = !isEmpty(newPaths); + if( newPathFound // we found new paths + || (!isEmpty(tm.paths) && isEmpty(pathsByPathRole)) // pathsByPathRole not yet initialized + ){ + tm.paths += newPaths; + pathsByPathRole = (); + for( <- tm.paths){ + pathsByPathRole[r] ? {} += {}; + } + } + + return newPathFound; } // ---- "equal" and "requireEqual" ---------------------------------------- @@ -1134,9 +1168,9 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ void fact(value v, AType atype){ if(Tree t := v) { - addFact(getLoc(t), atype); + addFact(getLogicalLoc(t), atype); } else if(loc l := v){ - addFact(l, atype); + addFact(getLogicalLoc(l), atype); } else { throw TypePalUsage("First argument of `fact` should be `Tree` or `loc`, found ``"); } @@ -1144,9 +1178,9 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ void solver_specializedFact(value v, AType atype){ if(Tree t := v) { - specializedFacts[getLoc(t)] = atype; + specializedFacts[getLogicalLoc(t)] = atype; } else if(loc l := v){ - specializedFacts[l] = atype; + specializedFacts[getLogicalLoc(l)] = atype; } else { throw TypePalUsage("First argument of `specializedFact` should be `Tree` or `loc`, found ``"); } @@ -1155,18 +1189,23 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ bool allDependenciesKnown(set[loc] deps, bool eager){ if(isEmpty(deps)) return true; if(eager) return all(dep <- deps, dep in facts); - return all(dep <- deps, dep in facts, solver_isFullyInstantiated(facts[dep])); + return all(dep <- deps, + dep in facts, + solver_isFullyInstantiated(facts[dep])); } bool allDependenciesKnown(list[loc] deps, bool eager){ if(isEmpty(deps)) return true; if(eager) return all(dep <- deps, dep in facts); - return all(dep <- deps, dep in facts, solver_isFullyInstantiated(facts[dep])); + return all(dep <- deps, + dep in facts, + solver_isFullyInstantiated(facts[dep])); } bool solver_isFullyInstantiated(AType atype){ visit(atype){ - case tvar(loc tname): { if(tname notin facts) return false; + case tvar(loc tname): { tname = getLogicalLoc(tname); + if(tname notin facts) return false; if(tvar(_) := facts[tname]) return false; } case lazyLub(list[AType] atypes): @@ -1279,7 +1318,7 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ orgId = udef.orgId; idRole = udef.idRole; defined = udef.defined; - if(defined in logical2physical) continue; + //if(defined in logical2physical) defined = logical2physical[defined]; u = use(id, orgId, defined, scope, {idRole}); // turn each unused definition into a use and check for double declarations; try { @@ -1293,7 +1332,7 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ doubleDefs += foundDefs; messages += [error("Double declaration of ``", d1, causes=[info("Other declaration of ``", d2) | d2 <- foundDefs, d2 != d1 ]) - | d1 <- foundDefs, isContainedIn(u.scope, definitions[d1].scope) + | d1 <- foundDefs, isContainedIn(u.scope, definitions[d1].scope, logical2physical) ]; } } @@ -1541,7 +1580,9 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ calcNoLubs = [calc | calc <- calculators, !(calc is calcLub)]; - for(Calculator clc <- sort(calcNoLubs, bool(Calculator a, Calculator b){ return a.src.length < b.src.length; })){ + for(Calculator clc <- sort(calcNoLubs, bool(Calculator a, Calculator b){ + return (a.src in logical2physical ? logical2physical[a.src] : a.src).length + < (b.src in logical2physical ? logical2physical[b.src] : b.src).length; })){ src = clc.src; if(src notin facts, !alreadyReported(messages, src)){ set[loc] cdeps = toSet(dependsOn(clc)); @@ -1597,7 +1638,7 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ ldefines = for(tup: <- tm.defines){ if(defInfo has tree){ - l = getLoc(defInfo.tree); + l = getLogicalLoc(defInfo.tree); if(l in tm.facts){ dt = defType(tm.facts[l]); tup.defInfo = setKeywordParameters(dt, getKeywordParameters(defInfo)); @@ -1617,11 +1658,12 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ tm.defines = toSet(ldefines); for(Define def <- tm.defines){ - if(def.defined notin def2uses && def.defined notin doubleDefs && reportUnused(def.defined, tm)){ - messages += warning("Unused ``", def.defined); + defdefined = solver_toPhysicalLoc(def.defined); + if(defdefined notin def2uses && defdefined notin doubleDefs && reportUnused(defdefined, tm)){ + messages += warning("Unused ``", defdefined); } } - + messages = visit(messages) { case loc l => solver_toPhysicalLoc(l) }; tm.messages = sortMostPrecise(toList(toSet(messages))); checkAllTypesAvailable(tm); @@ -1665,11 +1707,13 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ /* Global Info */ solver_getConfig, solver_getFacts, solver_getPaths, - + solver_getPathsByPathRole, solver_getDefinitions, solver_getAllDefines, solver_getDefine, solver_getUseDef, + solver_isContainedIn, + solver_isBefore, /* Nested Info */ solver_push, solver_pop, diff --git a/src/analysis/typepal/StringSimilarity.rsc b/src/analysis/typepal/StringSimilarity.rsc index 7e3fd9b5..1283a4e2 100644 --- a/src/analysis/typepal/StringSimilarity.rsc +++ b/src/analysis/typepal/StringSimilarity.rsc @@ -12,12 +12,10 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND } module analysis::typepal::StringSimilarity -import List; -import IO; import Location; import Set; import String; -//import analysis::typepal::TModel; +import analysis::typepal::TModel; import analysis::typepal::ConfigurableScopeGraph; @synopsis{Tryadic minimum function on integers} @@ -69,10 +67,15 @@ list[str] similarWords(str w, set[str] vocabulary, int maxDistance) = sort({ | str v <- vocabulary, d := lev(w, v), d <= maxDistance }, bool (WordSim x, WordSim y){ return x.sim < y.sim;}).word; +// TODO: remove this temporary copy of isContainedIn (needed to break deployment cycle) +// should reside in Location.rsc +private bool isContainedIn(loc inner, loc outer, map[loc,loc] m) + = isContainedIn(inner in m ? m[inner] : inner, outer in m ? m[outer] : outer); + @synopsis{Find in TModel tm, names similar to Use u. Max edit distance comes from TypePal Configuration.} list[str] similarNames(Use u, TModel tm){ w = getOrgId(u); idRoles = u.idRoles; - vocabulary = { d.orgId | d <- tm.defines, d.idRole in idRoles, isContainedIn(u.occ, d.scope) }; + vocabulary = { d.orgId | d <- tm.defines, d.idRole in idRoles, isContainedIn(u.occ, d.scope, tm.logical2physical) }; return similarWords(w, vocabulary, tm.config.cutoffForNameSimilarity); } diff --git a/src/analysis/typepal/Version.rsc b/src/analysis/typepal/Version.rsc index 3b6219b3..dddacb10 100644 --- a/src/analysis/typepal/Version.rsc +++ b/src/analysis/typepal/Version.rsc @@ -14,7 +14,7 @@ module analysis::typepal::Version import util::SemVer; -private str currentTplVersion = "2.0.0"; +private str currentTplVersion = "1.1.0"; bool isValidTplVersion(str version){ return equalVersion(version, currentTplVersion); diff --git a/src/examples/dataModel/Checker.rsc b/src/examples/dataModel/Checker.rsc index 61e142e3..3ec5e55b 100644 --- a/src/examples/dataModel/Checker.rsc +++ b/src/examples/dataModel/Checker.rsc @@ -31,8 +31,6 @@ str prettyAType(setType(AType tp)) = "Set\<\>"; str prettyAType(entityType(str name)) = name; str prettyAType(fieldType(str name)) = name; -str prettyAType(functionType(AType from, AType to)) = "fun -\> "; - data IdRole = entityId() | fieldId()