From 14133c6c7a65c7eb19a4dc4488143e7a985ee765 Mon Sep 17 00:00:00 2001 From: paulklint Date: Mon, 5 Jan 2026 15:35:20 +0100 Subject: [PATCH 01/29] New module LogicalLocs Provides most comparison operations on locations with extra map arguments that maps logical locations to physical ones. --- src/LogicalLocation.rsc | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/LogicalLocation.rsc diff --git a/src/LogicalLocation.rsc b/src/LogicalLocation.rsc new file mode 100644 index 0000000..bdc3180 --- /dev/null +++ b/src/LogicalLocation.rsc @@ -0,0 +1,36 @@ +module LogicalLocation + +extend Location; + +bool isLexicallyLess(loc l, loc r, map[loc,loc] m) + = isLexicallyLess(l in m ? m[l] : l, r in m ? m[r] : r); + +bool isStrictlyContainedIn(loc inner, loc outer, map[loc,loc] m) + = isStrictlyContainedIn(inner in m ? m[inner] : inner, outer in m ? m[outer] : outer); + +bool isContainedIn(loc inner, loc outer, map[loc,loc] m) + = isContainedIn(inner in m ? m[inner] : inner, outer in m ? m[outer] : outer); + +// bool beginsBefore(loc inner, loc outer, map[loc,loc] m) +// = beginsBefore(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); + +bool isImmediatelyBefore(loc inner, loc outer, map[loc,loc] m) + = isImmediatelyBefore(inner in m ? m[inner] : inner, outer in m ? m[outer] : outer); + + bool beginsAfter(loc inner, loc outer, map[loc,loc] m) + = beginsAfter(inner in m ? m[inner] : inner, outer in m ? m[outer] : outer); + +bool isAfter(loc inner, loc outer, map[loc,loc] m) + = beginsAfter(inner in m ? m[inner] : inner, outer in m ? m[outer] : outer); + +bool isImmediatelyAfter(loc inner, loc outer, map[loc,loc] m) + = isImmediatelyAfter(inner in m ? m[inner] : inner, outer in m ? m[outer] : outer); + +bool isOverlapping(loc inner, loc outer, map[loc,loc] m) + = isOverlapping(inner in m ? m[inner] : inner, outer in m ? m[outer] : outer); + +loc cover(list[loc] locs, map[loc,loc] m) + = cover([l in m ? m[l] : l | l <- locs]); From 60df6cac9a6d5ac67bba48517cdd51f40750f7f8 Mon Sep 17 00:00:00 2001 From: paulklint Date: Mon, 5 Jan 2026 15:37:25 +0100 Subject: [PATCH 02/29] Changes to support native logical locations - During the collect phase logical locations are computed and collected in a map - All information in TModels that is added via addTModel is remembered. Note that info is already based on logical locations. - At the end of the collect phase, all information gathered (excluded that from added TModels) is converted to logical locations, except locations in error messages. --- src/analysis/typepal/Collector.rsc | 249 ++++++++++------------------- 1 file changed, 88 insertions(+), 161 deletions(-) diff --git a/src/analysis/typepal/Collector.rsc b/src/analysis/typepal/Collector.rsc index 29a7e4f..6455ec7 100644 --- a/src/analysis/typepal/Collector.rsc +++ b/src/analysis/typepal/Collector.rsc @@ -23,7 +23,7 @@ import Set; import Relation; import IO; import Type; -import Location; +import LogicalLocation; import String; import analysis::typepal::Version; @@ -194,101 +194,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 +201,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 +220,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 +255,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 +268,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 +307,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 +335,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 +486,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 +665,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 +679,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 +756,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 +921,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 +948,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 +987,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 = toPhysicalLocs(messages) + addedMessages; messages = addedMessages = []; + physical2logical = logical2physical = (); return tm; } else { @@ -1305,9 +1232,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 +1242,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 +1253,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 +1277,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)]); } } } From 097d90811d460ce0df10559fe4bf2b3de1121247 Mon Sep 17 00:00:00 2001 From: paulklint Date: Mon, 5 Jan 2026 15:42:03 +0100 Subject: [PATCH 03/29] Added support for nicely indented debug output. Some optimizations --- .../typepal/ConfigurableScopeGraph.rsc | 101 +++++++++++------- 1 file changed, 63 insertions(+), 38 deletions(-) diff --git a/src/analysis/typepal/ConfigurableScopeGraph.rsc b/src/analysis/typepal/ConfigurableScopeGraph.rsc index da8a4d9..df31179 100644 --- a/src/analysis/typepal/ConfigurableScopeGraph.rsc +++ b/src/analysis/typepal/ConfigurableScopeGraph.rsc @@ -215,10 +215,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 */ @@ -379,32 +403,37 @@ ScopeGraph newScopeGraph(TModel tm, TypePalConfig config){ //@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>; + idMap = scope in tm.definesMap ? tm.definesMap[scope] : (); + preDefs = id in idMap ? idMap[id] : {}; + res = {}; + if(isEmpty(preDefs) || isEmpty(preDefs<0> & idRoles)){ + res = {}; + } else { + res = preDefs<1>; + } + // dbg("bindWide: , =\> "); + return res; } // 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( <- paths, 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 +446,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,26 +471,31 @@ 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; } @@ -479,16 +511,17 @@ ScopeGraph newScopeGraph(TModel tm, TypePalConfig config){ 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,23 +532,15 @@ 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 = (); set[PathRole] pathRoles = {}; Solver the_solver = dummySolver(); From 0134912c86a0281fe43b14137785446a8de7d583 Mon Sep 17 00:00:00 2001 From: paulklint Date: Mon, 5 Jan 2026 15:43:12 +0100 Subject: [PATCH 04/29] Added isContainedIn and isBefore to ISolver API Both functions work as the standard ones, but take the current logical to physical mapping into account. --- src/analysis/typepal/ISolver.rsc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/analysis/typepal/ISolver.rsc b/src/analysis/typepal/ISolver.rsc index f3b7aaa..ceffe7d 100644 --- a/src/analysis/typepal/ISolver.rsc +++ b/src/analysis/typepal/ISolver.rsc @@ -63,6 +63,8 @@ data Solver 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, From 722997754f65ea67495932d1fa4f0beb44ce30a4 Mon Sep 17 00:00:00 2001 From: paulklint Date: Mon, 5 Jan 2026 15:45:33 +0100 Subject: [PATCH 05/29] Deal with logical locations - Implemented isContainedIn and isBefore - Make sure that all locations entering via the Solver API are first converted to logical form. --- src/analysis/typepal/Solver.rsc | 90 ++++++++++++++++++++++----------- 1 file changed, 60 insertions(+), 30 deletions(-) diff --git a/src/analysis/typepal/Solver.rsc b/src/analysis/typepal/Solver.rsc index ea27d5e..40ea386 100644 --- a/src/analysis/typepal/Solver.rsc +++ b/src/analysis/typepal/Solver.rsc @@ -21,7 +21,7 @@ extend analysis::typepal::Messenger; import Exception; import IO; import List; -import Location; +import LogicalLocation; import Map; import Message; import Node; @@ -119,9 +119,15 @@ 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; + + 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 +203,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 +318,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 +556,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 +602,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 +640,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 +663,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 +751,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 +775,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 +796,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 +817,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; @@ -1134,9 +1154,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 +1164,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 +1175,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 +1304,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 +1318,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 +1566,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 +1624,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,8 +1644,9 @@ 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); } } @@ -1670,6 +1698,8 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ solver_getAllDefines, solver_getDefine, solver_getUseDef, + solver_isContainedIn, + solver_isBefore, /* Nested Info */ solver_push, solver_pop, From 22d29100ca9b8ed804758711648712a5fd42e266 Mon Sep 17 00:00:00 2001 From: paulklint Date: Mon, 5 Jan 2026 15:47:15 +0100 Subject: [PATCH 06/29] Adapted the use of isContainedIn --- src/analysis/typepal/StringSimilarity.rsc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/analysis/typepal/StringSimilarity.rsc b/src/analysis/typepal/StringSimilarity.rsc index 7e3fd9b..bdb6661 100644 --- a/src/analysis/typepal/StringSimilarity.rsc +++ b/src/analysis/typepal/StringSimilarity.rsc @@ -14,10 +14,10 @@ module analysis::typepal::StringSimilarity import List; import IO; -import Location; +import LogicalLocation; import Set; import String; -//import analysis::typepal::TModel; +import analysis::typepal::TModel; import analysis::typepal::ConfigurableScopeGraph; @synopsis{Tryadic minimum function on integers} @@ -73,6 +73,6 @@ list[str] similarWords(str w, set[str] vocabulary, int maxDistance) 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); } From 2cda513933c87e4ecab88d1d16312dde6a65e549 Mon Sep 17 00:00:00 2001 From: paulklint Date: Mon, 5 Jan 2026 16:12:20 +0100 Subject: [PATCH 07/29] Removed calls to obsolete function --- src/analysis/typepal/ConfigurableScopeGraph.rsc | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/analysis/typepal/ConfigurableScopeGraph.rsc b/src/analysis/typepal/ConfigurableScopeGraph.rsc index df31179..ed142a6 100644 --- a/src/analysis/typepal/ConfigurableScopeGraph.rsc +++ b/src/analysis/typepal/ConfigurableScopeGraph.rsc @@ -505,7 +505,6 @@ ScopeGraph newScopeGraph(TModel tm, TypePalConfig config){ current_paths = the_solver.getPaths(); //tm.paths; if(current_paths != paths){ paths = current_paths; - updatePathCache(); pathRoles = paths.pathRole; } @@ -548,7 +547,6 @@ ScopeGraph newScopeGraph(TModel tm, TypePalConfig config){ void do_setSolver(Solver s){ the_solver = s; paths = the_solver.getPaths(); - updatePathCache(); pathRoles = paths.pathRole; } From 254e0b1a5a9a70eb3567401173e4c7d937741d5a Mon Sep 17 00:00:00 2001 From: paulklint Date: Mon, 5 Jan 2026 17:10:21 +0100 Subject: [PATCH 08/29] [maven-release-plugin] prepare release v0.15.6-RC1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b76dcf8..9ff202e 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.rascalmpl typepal - 0.15.6-SNAPSHOT + 0.15.6 jar @@ -22,7 +22,7 @@ scm:git:ssh://git@github.com/usethesource/typepal.git - v0.15.1 + v0.15.6-RC1 From 11fd48e7b3a334edd8f7fae34fbe61d1bc69ed9d Mon Sep 17 00:00:00 2001 From: paulklint Date: Mon, 5 Jan 2026 17:10:25 +0100 Subject: [PATCH 09/29] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 9ff202e..3fcf6d1 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.rascalmpl typepal - 0.15.6 + 0.15.7-SNAPSHOT jar @@ -22,7 +22,7 @@ scm:git:ssh://git@github.com/usethesource/typepal.git - v0.15.6-RC1 + v0.15.1 From e2f41aad974b79aba42b7b43241c984fc9668ace Mon Sep 17 00:00:00 2001 From: paulklint Date: Tue, 6 Jan 2026 17:48:44 +0100 Subject: [PATCH 10/29] [maven-release-plugin] prepare release v0.16.0-RC1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 3fcf6d1..a81290b 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.rascalmpl typepal - 0.15.7-SNAPSHOT + 0.16.0-RC1 jar @@ -22,7 +22,7 @@ scm:git:ssh://git@github.com/usethesource/typepal.git - v0.15.1 + v0.16.0-RC1 From 4a6f5047ec93335250532aadf4881635d0f676e9 Mon Sep 17 00:00:00 2001 From: paulklint Date: Tue, 6 Jan 2026 17:48:48 +0100 Subject: [PATCH 11/29] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index a81290b..8078c99 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.rascalmpl typepal - 0.16.0-RC1 + 0.16.0-RC2-SNAPSHOT jar @@ -22,7 +22,7 @@ scm:git:ssh://git@github.com/usethesource/typepal.git - v0.16.0-RC1 + v0.15.1 From f890d0aeadd272fb83d2a739c15435824d0bc37a Mon Sep 17 00:00:00 2001 From: paulklint Date: Wed, 7 Jan 2026 11:42:43 +0100 Subject: [PATCH 12/29] Solved deployment cycle related to (now obsolete) LogicalLocation module --- src/LogicalLocation.rsc | 36 ----------------------- src/analysis/typepal/Collector.rsc | 9 +++++- src/analysis/typepal/Solver.rsc | 2 +- src/analysis/typepal/StringSimilarity.rsc | 9 ++++-- 4 files changed, 15 insertions(+), 41 deletions(-) delete mode 100644 src/LogicalLocation.rsc diff --git a/src/LogicalLocation.rsc b/src/LogicalLocation.rsc deleted file mode 100644 index bdc3180..0000000 --- a/src/LogicalLocation.rsc +++ /dev/null @@ -1,36 +0,0 @@ -module LogicalLocation - -extend Location; - -bool isLexicallyLess(loc l, loc r, map[loc,loc] m) - = isLexicallyLess(l in m ? m[l] : l, r in m ? m[r] : r); - -bool isStrictlyContainedIn(loc inner, loc outer, map[loc,loc] m) - = isStrictlyContainedIn(inner in m ? m[inner] : inner, outer in m ? m[outer] : outer); - -bool isContainedIn(loc inner, loc outer, map[loc,loc] m) - = isContainedIn(inner in m ? m[inner] : inner, outer in m ? m[outer] : outer); - -// bool beginsBefore(loc inner, loc outer, map[loc,loc] m) -// = beginsBefore(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); - -bool isImmediatelyBefore(loc inner, loc outer, map[loc,loc] m) - = isImmediatelyBefore(inner in m ? m[inner] : inner, outer in m ? m[outer] : outer); - - bool beginsAfter(loc inner, loc outer, map[loc,loc] m) - = beginsAfter(inner in m ? m[inner] : inner, outer in m ? m[outer] : outer); - -bool isAfter(loc inner, loc outer, map[loc,loc] m) - = beginsAfter(inner in m ? m[inner] : inner, outer in m ? m[outer] : outer); - -bool isImmediatelyAfter(loc inner, loc outer, map[loc,loc] m) - = isImmediatelyAfter(inner in m ? m[inner] : inner, outer in m ? m[outer] : outer); - -bool isOverlapping(loc inner, loc outer, map[loc,loc] m) - = isOverlapping(inner in m ? m[inner] : inner, outer in m ? m[outer] : outer); - -loc cover(list[loc] locs, map[loc,loc] m) - = cover([l in m ? m[l] : l | l <- locs]); diff --git a/src/analysis/typepal/Collector.rsc b/src/analysis/typepal/Collector.rsc index 6455ec7..3a30618 100644 --- a/src/analysis/typepal/Collector.rsc +++ b/src/analysis/typepal/Collector.rsc @@ -23,7 +23,7 @@ import Set; import Relation; import IO; import Type; -import LogicalLocation; +import Location; import String; import analysis::typepal::Version; @@ -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 diff --git a/src/analysis/typepal/Solver.rsc b/src/analysis/typepal/Solver.rsc index 40ea386..743b05b 100644 --- a/src/analysis/typepal/Solver.rsc +++ b/src/analysis/typepal/Solver.rsc @@ -21,7 +21,7 @@ extend analysis::typepal::Messenger; import Exception; import IO; import List; -import LogicalLocation; +import Location; import Map; import Message; import Node; diff --git a/src/analysis/typepal/StringSimilarity.rsc b/src/analysis/typepal/StringSimilarity.rsc index bdb6661..1283a4e 100644 --- a/src/analysis/typepal/StringSimilarity.rsc +++ b/src/analysis/typepal/StringSimilarity.rsc @@ -12,9 +12,7 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND } module analysis::typepal::StringSimilarity -import List; -import IO; -import LogicalLocation; +import Location; import Set; import String; import analysis::typepal::TModel; @@ -69,6 +67,11 @@ 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); From 9f6726f8e183f90d5bde914d94d2cd8519a76cd2 Mon Sep 17 00:00:00 2001 From: paulklint Date: Wed, 7 Jan 2026 11:46:59 +0100 Subject: [PATCH 13/29] [maven-release-plugin] prepare release v0.16.0-RC2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 8078c99..d7f7719 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.rascalmpl typepal - 0.16.0-RC2-SNAPSHOT + 0.16.0-RC2 jar @@ -22,7 +22,7 @@ scm:git:ssh://git@github.com/usethesource/typepal.git - v0.15.1 + v0.16.0-RC2 From c0f5e2751612fec3edb5a412999fdf66e8f3c02e Mon Sep 17 00:00:00 2001 From: paulklint Date: Wed, 7 Jan 2026 11:47:03 +0100 Subject: [PATCH 14/29] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d7f7719..8a875f0 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.rascalmpl typepal - 0.16.0-RC2 + 0.16.0-RC3-SNAPSHOT jar @@ -22,7 +22,7 @@ scm:git:ssh://git@github.com/usethesource/typepal.git - v0.16.0-RC2 + v0.15.1 From 7bbf8ffcd7938dc32211231cc2dd80d2119b9158 Mon Sep 17 00:00:00 2001 From: paulklint Date: Thu, 8 Jan 2026 11:22:31 +0100 Subject: [PATCH 15/29] Convert all locs in messages to physical locs --- src/analysis/typepal/Solver.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analysis/typepal/Solver.rsc b/src/analysis/typepal/Solver.rsc index 743b05b..ce20040 100644 --- a/src/analysis/typepal/Solver.rsc +++ b/src/analysis/typepal/Solver.rsc @@ -1649,7 +1649,7 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ messages += warning("Unused ``", defdefined); } } - + messages = visit(messages) { case loc l => solver_toPhysicalLoc(l) }; tm.messages = sortMostPrecise(toList(toSet(messages))); checkAllTypesAvailable(tm); From aa28fa216410ccd81f697fed453467b1160b58d2 Mon Sep 17 00:00:00 2001 From: paulklint Date: Wed, 14 Jan 2026 20:25:41 +0100 Subject: [PATCH 16/29] Some optimizations --- .../typepal/ConfigurableScopeGraph.rsc | 36 +++++++++---------- src/analysis/typepal/ISolver.rsc | 1 + src/analysis/typepal/Solver.rsc | 21 +++++++++-- 3 files changed, 36 insertions(+), 22 deletions(-) diff --git a/src/analysis/typepal/ConfigurableScopeGraph.rsc b/src/analysis/typepal/ConfigurableScopeGraph.rsc index ed142a6..5e61dc8 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; @@ -399,20 +400,14 @@ 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){ - idMap = scope in tm.definesMap ? tm.definesMap[scope] : (); - preDefs = id in idMap ? idMap[id] : {}; - res = {}; - if(isEmpty(preDefs) || isEmpty(preDefs<0> & idRoles)){ - res = {}; - } else { - res = preDefs<1>; - } - // dbg("bindWide: , =\> "); - return res; + 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 @@ -432,7 +427,7 @@ ScopeGraph newScopeGraph(TModel tm, TypePalConfig config){ seenParents = {}; solve(res, scope) { next_path: - for( <- paths, parent notin seenParents){ + for( <- pathsByPathRole[pathRole] ? {}, parent notin seenParents){ seenParents += parent; for(loc def <- lookupScopeWide(parent, use)){ switch(isAcceptablePathFun(parent, def, use, pathRole, the_solver)){ @@ -502,10 +497,10 @@ ScopeGraph newScopeGraph(TModel tm, TypePalConfig config){ 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; - pathRoles = paths.pathRole; + current_pathsByPathRole = the_solver.getPathsByPathRole(); + if(current_pathsByPathRole != pathsByPathRole){ + pathsByPathRole = current_pathsByPathRole; + pathRoles = domain(pathsByPathRole); } scope = u.scope; @@ -539,15 +534,18 @@ ScopeGraph newScopeGraph(TModel tm, TypePalConfig config){ } - Paths paths = {}; + // 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(); - 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 ceffe7d..40992af 100644 --- a/src/analysis/typepal/ISolver.rsc +++ b/src/analysis/typepal/ISolver.rsc @@ -59,6 +59,7 @@ 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, diff --git a/src/analysis/typepal/Solver.rsc b/src/analysis/typepal/Solver.rsc index ce20040..f42b6a3 100644 --- a/src/analysis/typepal/Solver.rsc +++ b/src/analysis/typepal/Solver.rsc @@ -82,6 +82,11 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ map[loc,loc] logical2physical = tm.logical2physical; + map[PathRole, rel[loc,loc]] pathsByPathRole = (); + for( <- tm.paths){ + pathsByPathRole[r] ? {} += {}; + } + void configTypePal(TypePalConfig tc){ normalizeName = tc.normalizeName; @@ -121,6 +126,8 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ 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; @@ -859,9 +866,17 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ } } newPaths = { tup | tup: <- newPaths, u != d }; - tm.paths += newPaths; tm.referPaths = referPaths; - return !isEmpty(newPaths); + pathsFound = !isEmpty(newPaths); + if(pathsFound){ + tm.paths += newPaths; + pathsByPathRole = (); + for( <- tm.paths){ + pathsByPathRole[r] ? {} += {}; + } + } + + return pathsFound; } // ---- "equal" and "requireEqual" ---------------------------------------- @@ -1693,7 +1708,7 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ /* Global Info */ solver_getConfig, solver_getFacts, solver_getPaths, - + solver_getPathsByPathRole, solver_getDefinitions, solver_getAllDefines, solver_getDefine, From 8429a7133e85ed0731d8f3d49f5c4f3137a72bd0 Mon Sep 17 00:00:00 2001 From: paulklint Date: Wed, 14 Jan 2026 20:29:04 +0100 Subject: [PATCH 17/29] [maven-release-plugin] prepare release v0.16.0-RC3 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 8a875f0..e626ef4 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.rascalmpl typepal - 0.16.0-RC3-SNAPSHOT + 0.16.0-RC3 jar @@ -22,7 +22,7 @@ scm:git:ssh://git@github.com/usethesource/typepal.git - v0.15.1 + v0.16.0-RC3 From c128b62f5c4c4f4e6a941ff3213cb7ba2eaa074c Mon Sep 17 00:00:00 2001 From: paulklint Date: Wed, 14 Jan 2026 20:29:08 +0100 Subject: [PATCH 18/29] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index e626ef4..31d6d20 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.rascalmpl typepal - 0.16.0-RC3 + 0.16.0-RC4-SNAPSHOT jar @@ -22,7 +22,7 @@ scm:git:ssh://git@github.com/usethesource/typepal.git - v0.16.0-RC3 + v0.15.1 From 1fd51703a7a1a146ef44019aab5cd49e34dbb263 Mon Sep 17 00:00:00 2001 From: paulklint Date: Thu, 15 Jan 2026 00:10:06 +0100 Subject: [PATCH 19/29] Removed unused pattern variable --- src/analysis/typepal/Solver.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analysis/typepal/Solver.rsc b/src/analysis/typepal/Solver.rsc index f42b6a3..d46ecb2 100644 --- a/src/analysis/typepal/Solver.rsc +++ b/src/analysis/typepal/Solver.rsc @@ -865,7 +865,7 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ ;/* ignore until end */ } } - newPaths = { tup | tup: <- newPaths, u != d }; + newPaths = { tup | tup: <- newPaths, u != d }; tm.referPaths = referPaths; pathsFound = !isEmpty(newPaths); if(pathsFound){ From 840bc392fff3ab9ab7fa84192a743e2487c69fd8 Mon Sep 17 00:00:00 2001 From: paulklint Date: Thu, 15 Jan 2026 00:13:13 +0100 Subject: [PATCH 20/29] [maven-release-plugin] prepare release v0.16.0-RC4 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 31d6d20..bb96bf3 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.rascalmpl typepal - 0.16.0-RC4-SNAPSHOT + 0.16.0-RC4 jar @@ -22,7 +22,7 @@ scm:git:ssh://git@github.com/usethesource/typepal.git - v0.15.1 + v0.16.0-RC4 From 925e084d002b598dee709bed0a25bf5aab03c363 Mon Sep 17 00:00:00 2001 From: paulklint Date: Thu, 15 Jan 2026 00:13:17 +0100 Subject: [PATCH 21/29] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index bb96bf3..1025824 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.rascalmpl typepal - 0.16.0-RC4 + 0.16.0-RC5-SNAPSHOT jar @@ -22,7 +22,7 @@ scm:git:ssh://git@github.com/usethesource/typepal.git - v0.16.0-RC4 + v0.15.1 From 9a9c8e8482343f2153928bcfe346ec76ba08fc1c Mon Sep 17 00:00:00 2001 From: paulklint Date: Fri, 16 Jan 2026 11:29:48 +0100 Subject: [PATCH 22/29] Optimization --- src/analysis/typepal/Solver.rsc | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/analysis/typepal/Solver.rsc b/src/analysis/typepal/Solver.rsc index d46ecb2..da101e3 100644 --- a/src/analysis/typepal/Solver.rsc +++ b/src/analysis/typepal/Solver.rsc @@ -83,9 +83,6 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ map[loc,loc] logical2physical = tm.logical2physical; map[PathRole, rel[loc,loc]] pathsByPathRole = (); - for( <- tm.paths){ - pathsByPathRole[r] ? {} += {}; - } void configTypePal(TypePalConfig tc){ @@ -867,8 +864,10 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ } newPaths = { tup | tup: <- newPaths, u != d }; tm.referPaths = referPaths; - pathsFound = !isEmpty(newPaths); - if(pathsFound){ + 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){ @@ -876,7 +875,7 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ } } - return pathsFound; + return newPathFound; } // ---- "equal" and "requireEqual" ---------------------------------------- From 58815ea28c791c44d09bc6c7059e0b9f53a545cf Mon Sep 17 00:00:00 2001 From: paulklint Date: Fri, 16 Jan 2026 11:57:35 +0100 Subject: [PATCH 23/29] [maven-release-plugin] prepare release v0.16.0-RC5 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 1025824..b3ca61e 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.rascalmpl typepal - 0.16.0-RC5-SNAPSHOT + 0.16.0-RC5 jar @@ -22,7 +22,7 @@ scm:git:ssh://git@github.com/usethesource/typepal.git - v0.15.1 + v0.16.0-RC5 From 29b39b73d1601b1db327876f57daa10bdfe8f3de Mon Sep 17 00:00:00 2001 From: paulklint Date: Fri, 16 Jan 2026 11:57:39 +0100 Subject: [PATCH 24/29] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b3ca61e..c4875ee 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.rascalmpl typepal - 0.16.0-RC5 + 0.16.0-RC6-SNAPSHOT jar @@ -22,7 +22,7 @@ scm:git:ssh://git@github.com/usethesource/typepal.git - v0.16.0-RC5 + v0.15.1 From 8f4620cf276cd405199899a90a4627d24c979051 Mon Sep 17 00:00:00 2001 From: paulklint Date: Tue, 20 Jan 2026 13:52:42 +0100 Subject: [PATCH 25/29] Removed erroneous (and redundant) line --- src/examples/dataModel/Checker.rsc | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/examples/dataModel/Checker.rsc b/src/examples/dataModel/Checker.rsc index 61e142e..3ec5e55 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() From 0b2d5a3625e645784f5a984f960e4519aa0c9af9 Mon Sep 17 00:00:00 2001 From: paulklint Date: Tue, 20 Jan 2026 13:53:28 +0100 Subject: [PATCH 26/29] Reduce number of duplicate messages --- src/analysis/typepal/Collector.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analysis/typepal/Collector.rsc b/src/analysis/typepal/Collector.rsc index 3a30618..ba7d534 100644 --- a/src/analysis/typepal/Collector.rsc +++ b/src/analysis/typepal/Collector.rsc @@ -1025,7 +1025,7 @@ Collector newCollector(str modelName, map[str,Tree] namedTrees, TypePalConfig co tm.calculators = toLogicalLocs(calculators); calculators = {}; tm.requirements = toLogicalLocs(requirements); requirements = {}; tm.store = toLogicalLocs(storeVals); storeVals = (); - tm.messages = toPhysicalLocs(messages) + addedMessages; messages = addedMessages = []; + tm.messages = toList(toSet(toPhysicalLocs(messages) + addedMessages)); messages = addedMessages = []; physical2logical = logical2physical = (); return tm; From 2dcd9ad432e13e08df0ebac4a781a973546c6a2f Mon Sep 17 00:00:00 2001 From: paulklint Date: Tue, 20 Jan 2026 13:57:35 +0100 Subject: [PATCH 27/29] Set version number back to 1.1.0 since there are no changes in TModel --- src/analysis/typepal/Version.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analysis/typepal/Version.rsc b/src/analysis/typepal/Version.rsc index 3b6219b..dddacb1 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); From ba151bc67cbb6c2a8d62eb95a7ff548ed501de47 Mon Sep 17 00:00:00 2001 From: paulklint Date: Tue, 20 Jan 2026 14:06:41 +0100 Subject: [PATCH 28/29] [maven-release-plugin] prepare release v0.16.0 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index c4875ee..282930a 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.rascalmpl typepal - 0.16.0-RC6-SNAPSHOT + 0.16.0 jar @@ -22,7 +22,7 @@ scm:git:ssh://git@github.com/usethesource/typepal.git - v0.15.1 + v0.16.0 From 37ff636d9736afe31784e35951fac83fe82f021b Mon Sep 17 00:00:00 2001 From: paulklint Date: Tue, 20 Jan 2026 14:06:45 +0100 Subject: [PATCH 29/29] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 282930a..942d5bb 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.rascalmpl typepal - 0.16.0 + 0.16.1-SNAPSHOT jar @@ -22,7 +22,7 @@ scm:git:ssh://git@github.com/usethesource/typepal.git - v0.16.0 + v0.15.1