diff --git a/src/org/rascalmpl/core/library/lang/rascalcore/check/AType.rsc b/src/org/rascalmpl/core/library/lang/rascalcore/check/AType.rsc index 860229ac..4f3b1380 100644 --- a/src/org/rascalmpl/core/library/lang/rascalcore/check/AType.rsc +++ b/src/org/rascalmpl/core/library/lang/rascalcore/check/AType.rsc @@ -2,10 +2,9 @@ module lang::rascalcore::check::AType /* - Every needed to operate on ATypes, including asubtype, alub, + Every needed to operate on ATypes, including asubtype, alub, */ - extend lang::rascalcore::check::ATypeBase; extend lang::rascalcore::grammar::definition::Characters; @@ -18,23 +17,23 @@ import Set; @doc{ .Synopsis Subtype on types. -} +} //bool asubtype(type[&T] t, type[&U] u) { throw "asubtype not yet implemented on and "; } //asubtype(t.symbol, u.symbol); @doc{ .Synopsis -This function documents and implements the subtype relation of Rascal's type system. +This function documents and implements the subtype relation of Rascal's type system. } -bool asubtype(tvar(s), AType r) { - throw TypeUnavailable(); +bool asubtype(tvar(s), AType r) { + throw TypeUnavailable(); } default bool asubtype(AType l, AType r){ switch(r){ - case l: + case l: return true; case tvar(_): - throw TypeUnavailable(); + throw TypeUnavailable(); case overloadedAType(overloads): //TODO: Alternative: return asubtype(l, (\avoid() | alub(it, tp) | <_, _, tp> <- overloads)); return isEmpty(overloads) ? asubtype(l, avoid()) : any(<_, _, tp> <- overloads, asubtype(l, tp)); @@ -44,7 +43,7 @@ default bool asubtype(AType l, AType r){ return l is aint || l is areal || l is arat || l is anum; case aalias(str _, list[AType] _, AType aliased): return asubtype(l, aliased); - case \start(AType t): + case \start(AType t): return asubtype(l, t); case aprod(p): return asubtype(l, p.def); @@ -73,15 +72,15 @@ default bool asubtype(AType l, AType r){ case areified(AType t): return asubtype(l, t); } - if(l.alabel? || r.alabel?) - return asubtype(unset(l, "alabel") , unset(r, "alabel")); - else + if(l.alabel? || r.alabel?) + return asubtype(unset(l, "alabel") , unset(r, "alabel")); + else return l == r; } bool asubtype(p1:aparameter(str n1, AType b1), AType r) = asubtypeParam(p1, r); - + // From "Exploring Type Parameters: // aparameter, open bool asubtypeParam(p1:aparameter(str n1, AType b1, closed=false), AType r) { @@ -89,23 +88,23 @@ bool asubtypeParam(p1:aparameter(str n1, AType b1, closed=false), AType r) { if(aparameter(str _, AType _, closed=false) := r){ // [S1] res = true; } else if(aparameter(str _, AType b2, closed=true) := r){ // [S3] - res = asubtype(p1, b2); + res = asubtype(p1, b2); } else { // [S5] - res = asubtype(b1, r); + res = asubtype(b1, r); } //println("asubtype(, ) =\> "); return res; - } - + } + // aparameter, closed bool asubtypeParam(p1:aparameter(str n1, AType b1, closed=true), AType r) { res = false; if(aparameter(str n2, AType _, closed=true) := r ){ // [S2] res = n1 == n2; } else if(p2:aparameter(str _, AType _,closed=false) := r){// [S4] - res = asubtype(b1, p2); + res = asubtype(b1, p2); } else { // [S7] - res = asubtype(b1, r); + res = asubtype(b1, r); } //println("asubtype(, ) =\> "); return res; @@ -117,7 +116,7 @@ bool asubtype(overloadedAType(overloads), AType r) bool asubtype(avoid(), AType _) = true; default bool asubtype(AType _, avalue()) = true; - + bool asubtype(ac:acons(AType a, list[AType] ap, list[Keyword] _), AType b){ switch(b){ case acons(a,list[AType] bp, list[Keyword] _): @@ -202,9 +201,9 @@ bool asubtype(i:\iter-seps(AType s, list[AType] seps), AType b){ return true; case anode(_): return true; - case \iter-seps(AType t, list[AType] seps2): + case \iter-seps(AType t, list[AType] seps2): return asubtype(s,t) && asubtypeList(removeLayout(seps), removeLayout(seps2)); - case \iter(AType t): + case \iter(AType t): return asubtype(s,t) && isEmpty(removeLayout(seps)); case \iter-star(AType t): return asubtype(s,t) && isEmpty(removeLayout(seps)); @@ -285,7 +284,7 @@ bool asubtype(alist(AType a), AType b){ switch(b){ case alist(AType t): return asubtype(a, t); - case alrel(AType t): + case alrel(AType t): return asubtype(a, atuple(t)); case avalue(): return true; @@ -311,7 +310,7 @@ bool asubtype(aset(AType a), AType b){ switch(b){ case aset(AType t): return asubtype(a, t); - case arel(AType t): + case arel(AType t): return asubtype(a, atuple(t)); case avalue(): return true; @@ -321,7 +320,7 @@ bool asubtype(aset(AType a), AType b){ bool asubtype(arel(AType a), AType b){ switch(b){ - case arel(AType t): + case arel(AType t): return asubtype(a,t); case aset(AType t): return asubtype(atuple(a), t); @@ -331,9 +330,9 @@ bool asubtype(arel(AType a), AType b){ fail; } -bool asubtype(abag(AType s), abag(AType t)) = asubtype(s, t); +bool asubtype(abag(AType s), abag(AType t)) = asubtype(s, t); -bool asubtype(amap(AType from1, AType to1), amap(AType from2, AType to2)) +bool asubtype(amap(AType from1, AType to1), amap(AType from2, AType to2)) = asubtype(from1, from2) && asubtype(to1, to2); bool asubtype(AType l:afunc(AType a, list[AType] ap, list[Keyword] _), AType r){ @@ -356,7 +355,7 @@ bool asubtype(AType l:afunc(AType a, list[AType] ap, list[Keyword] _), AType r){ // areified bool asubtype(areified(AType s), AType b){ switch(b){ - case areified(AType t): + case areified(AType t): return asubtype(s,t); case anode(_): return true; @@ -370,7 +369,7 @@ bool asubtype(a:anode(list[AType] l), AType b){ switch(b){ case anode(_): return true; - case anode(list[AType] r): + case anode(list[AType] r): return l <= r; case \start(t): return asubtype(a, t); @@ -395,7 +394,7 @@ bool asubtype(l:\achar-class(_), AType r){ return true; } case aadt("Tree", _, _): - return true; // characters are Tree instances + return true; // characters are Tree instances case \start(t): return asubtype(l, t); case avalue(): @@ -477,14 +476,14 @@ bool outerComparable1(f1:afunc(AType r1, list[AType] p1, list[Keyword] _), f2:af = outerComparable(r1, r2) && (f1.varArgs ? (f2.varArgs ? outerComparable(p1, p2) : outerComparable(p1[0..-1], p2)) : (f2.varArgs ? outerComparable(p1, p2[0..-1]) - : outerComparable(p1, p2))); - + : outerComparable(p1, p2))); + bool outerComparable1(afunc(AType r1, list[AType] p1, list[Keyword] _), acons(AType r2, list[AType] p2, list[Keyword] _)) = outerComparable(r1, r2) && outerComparable(p1, p2); bool outerComparable1(acons(AType r1, list[AType] p1, list[Keyword] _), afunc(AType r2, list[AType] p2, list[Keyword] _)) = outerComparable(r1, r2) && outerComparable(p1, p2); -bool outerComparable1(aparameter(str pname1, AType bound1), aparameter(str pname2, AType bound2)) +bool outerComparable1(aparameter(str pname1, AType bound1), aparameter(str pname2, AType bound2)) = outerComparable(bound1, bound2); bool outerComparable1(aadt(str adtName1, list[AType] parameters1, SyntaxRole syntaxRole1), areified(_)) = true; @@ -507,7 +506,7 @@ bool equivalent(AType s, AType t) = asubtype(s,t) && asubtype(t,s); @doc{ .Synopsis -Structural equality between values. +Structural equality between values. .Description The difference is that no implicit coercions are done between values of incomparable types, such as == does for @@ -534,13 +533,13 @@ public java bool eq(value x, value y); The least-upperbound (lub) between two types. .Description -This function documents and implements the lub operation in Rascal's type system. +This function documents and implements the lub operation in Rascal's type system. } -AType alub(tvar(s), AType r) { - throw TypeUnavailable(); -} -AType alub(AType l, tvar(s)) { - throw TypeUnavailable(); +AType alub(tvar(s), AType r) { + throw TypeUnavailable(); +} +AType alub(AType l, tvar(s)) { + throw TypeUnavailable(); } AType alub(AType s, s) = s; @@ -558,7 +557,7 @@ AType alub(overloadedAType(overloads), AType t2) AType alub(AType t1, overloadedAType(overloads)) //TODO: Alternative: = alub(t1, (\avoid() | alub(it, tp) | <_, _, tp> <- overloads)); = isEmpty(overloads) ? t1 : alub(t1, (avalue() | aglb(it, tp) | <_, _, tp> <- overloads)); - + AType alub(avalue(), AType t) = avalue(); AType alub(AType s, avalue()) = avalue(); AType alub(avoid(), AType t) = t; @@ -576,37 +575,37 @@ AType alub(anum(), aint()) = anum(); AType alub(anum(), areal()) = anum(); AType alub(anum(), arat()) = anum(); -AType alub(aset(AType s), aset(AType t)) = aset(alub(s, t)); - -AType alub(aset(AType s), arel(AType t)) = aset(alub(s,atuple(t))); +AType alub(aset(AType s), aset(AType t)) = aset(alub(s, t)); + +AType alub(aset(AType s), arel(AType t)) = aset(alub(s,atuple(t))); AType alub(arel(AType s), aset(AType t)) = aset(alub(atuple(s), t)); AType alub(arel(atypeList(list[AType] l)), arel(atypeList(list[AType] r))) = size(l) == size(r) ? arel(atypeList(alubList(l, r))) : aset(avalue()); -AType alub(alist(AType s), alist(AType t)) = alist(alub(s, t)); -AType alub(alist(AType s), alrel(AType t)) = alist(alub(s,atuple(t))); +AType alub(alist(AType s), alist(AType t)) = alist(alub(s, t)); +AType alub(alist(AType s), alrel(AType t)) = alist(alub(s,atuple(t))); AType alub(alrel(AType s), alist(AType t)) = alist(alub(atuple(s),t)); AType alub(alrel(atypeList(list[AType] l)), alrel(atypeList(list[AType] r))) = size(l) == size(r) ? alrel(atypeList(alubList(l, r))) : alist(avalue()); AType alub(atuple(atypeList(list[AType] l)), atuple(atypeList(list[AType] r))) = size(l) == size(r) ? atuple(atypeList(alubList(l, r))) : avalue(); -AType alub(amap(ld, lr), amap(rd, rr)) = amap(alub(ld, rd), alub(lr, rr)); +AType alub(amap(ld, lr), amap(rd, rr)) = amap(alub(ld, rd), alub(lr, rr)); AType alub(abag(AType s), abag(AType t)) = abag(alub(s, t)); AType alub(aadt(str n, list[AType] _, SyntaxRole_), anode(_)) = anode([]); AType alub(anode(_), aadt(str n, list[AType] _, SyntaxRole _)) = anode([]); -AType alub(a1:aadt(str n, list[AType] lp, SyntaxRole lsr), a2:aadt(n, list[AType] rp, SyntaxRole rsr)) +AType alub(a1:aadt(str n, list[AType] lp, SyntaxRole lsr), a2:aadt(n, list[AType] rp, SyntaxRole rsr)) = addADTLabel(a1, a2, aadt(n, alubList(lp,rp), sr)) when size(lp) == size(rp) && getTypeParamNames(lp) == getTypeParamNames(rp) && size(getTypeParamNames(lp)) > 0 && sr := overloadSyntaxRole({lsr, rsr}) && sr != illegalSyntax(); - -AType alub(a1:aadt(str n, list[AType] lp, SyntaxRole lsr), a2:aadt(n, list[AType] rp, SyntaxRole rsr)) + +AType alub(a1:aadt(str n, list[AType] lp, SyntaxRole lsr), a2:aadt(n, list[AType] rp, SyntaxRole rsr)) = addADTLabel(a1, a2, aadt(n, alubList(lp,rp), sr)) when size(lp) == size(rp) && size(getTypeParamNames(lp)) == 0 && sr := overloadSyntaxRole({lsr, rsr}) && sr != illegalSyntax(); - + AType alub(aadt(str n, list[AType] lp, SyntaxRole _), aadt(str m, list[AType] rp,SyntaxRole _)) = anode([]) when n != m; AType alub(a1: aadt(str ln, list[AType] lp,SyntaxRole _), acons(AType b, _, _)) = alub(a1,b); @@ -647,7 +646,7 @@ AType alub(AType l, aalias(str _, list[AType] _, AType aliased)) = alub(l, alias // From "Exploring Type Parameters (adapted to keep aparameter as long as possible) AType alub(p1:aparameter(n1, b1,closed=false), aparameter(n2, b2,closed=false)) = n1 == n2 && b1 == gl ? p1 : gl when gl := aglb(b1, b2); -AType alub(p:aparameter(n1, b1,closed=true), aparameter(n2, b2, closed=true)) = n1 == n2 ? aparameter(n1, aglb(b1, b2),closed=true) +AType alub(p:aparameter(n1, b1,closed=true), aparameter(n2, b2, closed=true)) = n1 == n2 ? aparameter(n1, aglb(b1, b2),closed=true) : lb == b1 ? p : lb when lb := alub(b1, b2); AType alub(p1:aparameter(n1, b1,closed=false), p2:aparameter(n2, b2,closed=true)) = n1 == n2 && lb == b1 ? p1 : lb when lb := alub(b1, p2); @@ -699,8 +698,8 @@ AType alub(afunc(AType lr, list[AType] lp, list[Keyword] lkw), afunc(AType rr, l return avalue(); } -public list[AType] alubList(list[AType] l, list[AType] r) = [alub(l[idx],r[idx]) | idx <- index(l)] when size(l) == size(r); -default list[AType] alubList(list[AType] l, list[AType] r) = [avalue()]; +public list[AType] alubList(list[AType] l, list[AType] r) = [alub(l[idx],r[idx]) | idx <- index(l)] when size(l) == size(r); +default list[AType] alubList(list[AType] l, list[AType] r) = [avalue()]; private list[str] getTypeParamNames(list[AType] l) = [ s | li <- l, aparameter(s,_) := li]; @@ -719,13 +718,13 @@ public bool comparableOrNum(AType l, AType r) { case areal() => anum() case arat() => anum() }; - + rightAsNum = visit(r) { case aint() => anum() case areal() => anum() case arat() => anum() }; - + return comparable(l, r) || comparable(leftAsNum,rightAsNum); } @@ -750,8 +749,8 @@ public AType aglb(anum(), arat()) = arat(); public AType aglb(areal(), anum()) = areal(); public AType aglb(anum(), areal()) = areal(); -public AType aglb(aset(AType s), aset(AType t)) = aset(aglb(s, t)); -public AType aglb(aset(AType s), arel(AType t)) = aset(aglb(s,atuple(t))); +public AType aglb(aset(AType s), aset(AType t)) = aset(aglb(s, t)); +public AType aglb(aset(AType s), arel(AType t)) = aset(aglb(s,atuple(t))); public AType aglb(arel(AType s), aset(AType t)) = aset(aglb(atuple(s), t)); AType aglb(arel(atypeList(list[AType] l)), arel(atypeList(list[AType] r))) = size(l) == size(r) ? arel(atypeList(aglbList(l, r))) : aset(avalue()); @@ -763,9 +762,9 @@ AType aglb(overloadedAType(overloads), AType t2) AType aglb(AType t1, overloadedAType(overloads)) //TODO: Alternative: = aglb(t1, (\avoid() | alub(it, tp) | <_, _, tp> <- overloads)); = isEmpty(overloads) ? t1 : aglb(t1, (avoid() | alub(it, tp) | <_, _, tp> <- overloads)); - -public AType aglb(alist(AType s), alist(AType t)) = alist(aglb(s, t)); -public AType aglb(alist(AType s), alrel(AType t)) = alist(aglb(s,atuple(t))); + +public AType aglb(alist(AType s), alist(AType t)) = alist(aglb(s, t)); +public AType aglb(alist(AType s), alrel(AType t)) = alist(aglb(s,atuple(t))); public AType aglb(alrel(AType s), alist(AType t)) = alist(aglb(atuple(s), t)); AType aglb(alrel(atypeList(list[AType] l)), alrel(atypeList(list[AType] r))) = size(l) == size(r) ? alrel(atypeList(aglbList(l, r))) : alist(avalue()); @@ -779,16 +778,16 @@ public AType aglb(abag(AType s), abag(AType t)) = abag(aglb(s, t)); public AType aglb(anode(list[AType] l), aadt(str _, list[AType] _, SyntaxRole _), SyntaxRole _) = anode(l); public AType aglb(aadt(str _, list[AType] _, SyntaxRole _), anode(list[AType] r)) = anode(r); -AType aglb(a1:aadt(str n, list[AType] lp, SyntaxRole lsr), a2:aadt(n, list[AType] rp, SyntaxRole rsr)) +AType aglb(a1:aadt(str n, list[AType] lp, SyntaxRole lsr), a2:aadt(n, list[AType] rp, SyntaxRole rsr)) = addADTLabel(a1, a2, aadt(n, aglbList(lp,rp), sr)) when size(lp) == size(rp) && getTypeParamNames(lp) == getTypeParamNames(rp) && size(getTypeParamNames(lp)) > 0 && sr := overloadSyntaxRole({lsr, rsr}) && sr != illegalSyntax(); - -AType aglb(a1:aadt(str n, list[AType] lp, SyntaxRole lsr), a2:aadt(n, list[AType] rp, SyntaxRole rsr)) + +AType aglb(a1:aadt(str n, list[AType] lp, SyntaxRole lsr), a2:aadt(n, list[AType] rp, SyntaxRole rsr)) = addADTLabel(a1, a2, aadt(n, aglbList(lp,rp), sr)) - when size(lp) == size(rp) && size(getTypeParamNames(lp)) == 0 && + when size(lp) == size(rp) && size(getTypeParamNames(lp)) == 0 && sr := overloadSyntaxRole({lsr, rsr}) && sr != illegalSyntax(); - + AType aglb(aadt(str n, list[AType] lp, SyntaxRole _), aadt(str m, list[AType] rp,SyntaxRole _)) = anode([]) when n != m; AType aglb(a1: aadt(str ln, list[AType] lp,SyntaxRole _), acons(AType b, _, _)) = aglb(a1,b); @@ -826,5 +825,5 @@ public AType aglb(afunc(AType lr, list[AType] lp, list[Keyword] kwl), afunc(ATyp return avalue(); } -public list[AType] aglbList(list[AType] l, list[AType] r) = [aglb(l[idx],r[idx]) | idx <- index(l)] when size(l) == size(r); -public default list[AType] aglbList(list[AType] l, list[AType] r) = [avalue()]; +public list[AType] aglbList(list[AType] l, list[AType] r) = [aglb(l[idx],r[idx]) | idx <- index(l)] when size(l) == size(r); +public default list[AType] aglbList(list[AType] l, list[AType] r) = [avalue()]; diff --git a/src/org/rascalmpl/core/library/lang/rascalcore/check/Checker.rsc b/src/org/rascalmpl/core/library/lang/rascalcore/check/Checker.rsc index f3475648..4e975e66 100644 --- a/src/org/rascalmpl/core/library/lang/rascalcore/check/Checker.rsc +++ b/src/org/rascalmpl/core/library/lang/rascalcore/check/Checker.rsc @@ -144,7 +144,8 @@ ModuleStatus rascalTModelForLocs( ms = getImportAndExtendGraph(topModuleNames, compilerConfig); if(/error(_,_) := ms.messages){ - return ms; + + return clearTModelCache(ms); } if(compilerConfig.forceCompilationTopModule){ @@ -153,8 +154,8 @@ ModuleStatus rascalTModelForLocs( } } - imports_and_extends = ms.strPaths<0,2>; + imports_and_extends = ms.strPaths<0,2>; = stronglyConnectedComponentsAndTopSort(imports_and_extends); map[str, set[str]] module2component = (m : c | c <- components, m <- c); @@ -187,7 +188,7 @@ ModuleStatus rascalTModelForLocs( component = module2component[ordered[mi]]; jobStep(jobName, intercalate(" + ", [*component]), work=size(component)); - recheck = !all(m <- component, (tpl_uptodate() in ms.status[m] || checked() in ms.status[m])); + recheck = !all(m <- component, ms.status[m]?, (tpl_uptodate() in ms.status[m] || checked() in ms.status[m])); for(m <- component){ mi += 1; if(!recheck){ @@ -199,7 +200,34 @@ ModuleStatus rascalTModelForLocs( } } } - if(!all(m <- component, tpl_uptodate() in ms.status[m] || checked() in ms.status[m])){ + + compatible_with_all_imports = true; + for(m <- component){ + m_compatible = false; + = getTModelForModule(m, ms); + if(found){ + imports_extends_m = imports_and_extends[m]; + = importsAndExtendsAreBinaryCompatible(tm, imports_extends_m, ms); + if(m_compatible){ + ms.status[m] += {tpl_uptodate(), checked()}; + } + } + compatible_with_all_imports = compatible_with_all_imports && m_compatible; + } + + any_rsc_changed = any(m <- component, rsc_changed() in ms.status[m]); + all_tmodels_uptodate = true; + for(m <- component){ + if(tpl_uptodate() notin ms.status[m] && checked() notin ms.status[m]) + all_tmodels_uptodate = false; + } + recheckCond = !compatible_with_all_imports || any_rsc_changed || !all_tmodels_uptodate; + + if(recheckCond){ + if(ms.compilerConfig.verbose){ + println("recheck : compatible_with_all_imports: , any_rsc_changed: , all_tmodels_uptodate: "); + } + = rascalTModelComponent(component, ms); moduleScopes += getModuleScopes(tm); map[str,TModel] tmodels_for_component = (); @@ -218,6 +246,7 @@ ModuleStatus rascalTModelForLocs( msgs = []; = getModuleParseTree(m, ms); if(success){ + msgs += [info("Checked ", pt.header.name@\loc)]; check_imports: for(imod <- pt.header.imports, imod has \module){ iname = unescape(""); @@ -228,10 +257,10 @@ ModuleStatus rascalTModelForLocs( if(iname == "ParseTree" && implicitlyUsesParseTree(ms.moduleLocs[m].path, tm)){ continue check_imports; } - if(ms.moduleLocs[iname]? && implicitlyUsesLayoutOrLexical(ms.moduleLocs[m].path, ms.moduleLocs[iname].path, tm)){ + if(ms.moduleLocs[iname]? && ms.moduleLocs[m]? && implicitlyUsesLayoutOrLexical(ms.moduleLocs[m].path, ms.moduleLocs[iname].path, tm)){ continue check_imports; } - if(ms.moduleLocs[iname]? && usesOrExtendsADT(ms.moduleLocs[m].path, ms.moduleLocs[iname].path, tm)){ + if(ms.moduleLocs[iname]? && ms.moduleLocs[m]? && usesOrExtendsADT(ms.moduleLocs[m].path, ms.moduleLocs[iname].path, tm)){ continue check_imports; } if(checked() in ms.status[iname] && rsc_not_found() notin ms.status[iname]){ @@ -271,6 +300,16 @@ ModuleStatus rascalTModelForLocs( } } ms = doSaveModule(component, m_imports, m_extends, ms, moduleScopes, transient_tms, compilerConfig); + for(m <- component){ + ms.status[m] -= {rsc_changed()}; + ms.status[m] += {tpl_uptodate()}; + } + } else { + for(m <- component){ + imports = { imp | <- ms.strPaths, m1 == m }; + extends = { ext | <- ms.strPaths, m1 == m }; + updateBOM(m, imports, extends, ms); + } } } } catch ParseError(loc src): { @@ -292,7 +331,7 @@ ModuleStatus rascalTModelForLocs( } jobEnd(jobName); - return ms; + return clearTModelCache(ms); } bool implicitlyUsesParseTree(str modulePath, TModel tm){ @@ -440,9 +479,21 @@ list[ModuleMessages] checkAll(loc root, RascalCompilerConfig compilerConfig){ // ---- Convenience check function during development ------------------------- +void find(str s, ModuleStatus ms){ + if(ms.moduleLocs[s]?) println("moduleLocs[] = "); + for(mname <- ms.tmodels){ + tm = ms.tmodels[mname]; + for(d <- tm.definitions){ + def = tm.definitions[d]; + if(contains("", s)) {println(": "); } + } + } +} + map[str, list[Message]] checkModules(list[str] moduleNames, RascalCompilerConfig compilerConfig) { ModuleStatus ms = rascalTModelForNames(moduleNames, compilerConfig, dummy_compile1); tmodels = ms.tmodels; + //find("Exception.rsc|(0,", ms); tmMsgs = (mname : tmodels[mname].messages | mname <- tmodels, !isEmpty(tmodels[mname].messages)); return //(mname : tmodels[mname].messages | mname <- tmodels, !isEmpty(tmodels[mname].messages)) (mname : ms.messages[mname] + (tmMsgs[mname] ? []) | mname <- ms.messages, !isEmpty(ms.messages[mname])); diff --git a/src/org/rascalmpl/core/library/lang/rascalcore/check/CheckerCommon.rsc b/src/org/rascalmpl/core/library/lang/rascalcore/check/CheckerCommon.rsc index 82c585f3..9e0d37cc 100644 --- a/src/org/rascalmpl/core/library/lang/rascalcore/check/CheckerCommon.rsc +++ b/src/org/rascalmpl/core/library/lang/rascalcore/check/CheckerCommon.rsc @@ -43,6 +43,7 @@ void checkSupportedByParserGenerator(Tree t, Collector c){ data MStatus = rsc_not_found() | tpl_not_found() + | rsc_changed() | parsed() | parse_error() | module_dependencies_extracted() @@ -178,9 +179,21 @@ tuple[bool, Module, ModuleStatus] getModuleParseTree(str qualifiedModuleName, Mo } } +/* + * We implement a caching mechanism for TModels with the following properties: + * - tmodelCacheSize tmodels are cached. + * - The most frequently uses modules are hardwired and are never removed. + They are determined by static analysis of the import/extend graph. + * - TModels on file (.tpl) physical locations have been replaced by logical locations where possible. + * - When a TModel is read in, physical locations are converted by logical logical locations + * - The policy is to keep TModels in the cache in this physical form as long as possible. + * - During its presence in the cache, the BOM of a TModel may get updated. + * - When a TModel has to be removed from the cache, it is converted back to the logical form and written back to file. + */ + set[str] hardwired = {}; -int tmodelCacheSize = 4; // should be > 0 +int tmodelCacheSize = 12; // should be > 0 int maxHardwired = tmodelCacheSize/4; @@ -202,25 +215,54 @@ void analyzeTModels(ModuleStatus ms){ hardwired = toSet(domain(hardwire)); } +ModuleStatus clearTModelCache(ModuleStatus ms){ + for(candidate <- ms.tmodelLIFO){ + ms = removeOldestTModelFromCache(ms); + } + for(candidate <- hardwired){ + ms = removeTModel(candidate, ms); + } + return ms; +} + +ModuleStatus removeTModel(str candidate, ModuleStatus ms){ + if(tpl_saved() notin ms.status[candidate]){ + pcfg = ms.pathConfig; + if(ms.compilerConfig.verbose) println("Save before removing from cache "); + tm = ms.tmodels[candidate]; + = getTPLWriteLoc(candidate, pcfg); + tm = convertTModel2LogicalLocs(tm, ms.tmodels); + ms.status[candidate] += tpl_saved(); + try { + writeBinaryValueFile(tplLoc, tm); + if(traceTPL) println("Written "); + } catch value e: { + throw "Cannot write TPL file , reason: "; + } + } + ms.tmodels = delete(ms.tmodels, candidate); + return ms; +} + +ModuleStatus removeOldestTModelFromCache(ModuleStatus ms){ + if(size(ms.tmodelLIFO) > 0){ + candidate = ms.tmodelLIFO[-1]; + ms = removeTModel(candidate, ms); + if(traceTModelCache) println("*** deleting tmodel , tmodels: , lifo: "); + ms.tmodelLIFO = ms.tmodelLIFO[..-1]; + } + return ms; +} + ModuleStatus addTModel (str qualifiedModuleName, TModel tm, ModuleStatus ms){ if(traceTModelCache) println("addTModel: "); if(tmodelCacheSize > 0){ - if(tpl_saved() notin ms.status[qualifiedModuleName]){ - iprintln(ms.status); - throw "Cannot add module with unsaved tpl"; - } ms.tmodels[qualifiedModuleName] = tm; if(qualifiedModuleName notin hardwired){ if(qualifiedModuleName notin ms.tmodelLIFO){ ms.tmodelLIFO = [qualifiedModuleName, *ms.tmodelLIFO]; while(size(ms.tmodels) >= tmodelCacheSize && size(ms.tmodelLIFO) > 0 && ms.tmodelLIFO[-1] != qualifiedModuleName){ - if(tpl_saved() notin ms.status[ms.tmodelLIFO[-1]]){ - iprintln(ms.status); - throw "Cannot remove unsaved tpl , "; - } - ms.tmodels = delete(ms.tmodels, ms.tmodelLIFO[-1]); - if(traceTModelCache) println("*** deleting tmodel , tmodels: , lifo: "); - ms.tmodelLIFO = ms.tmodelLIFO[..-1]; + ms = removeOldestTModelFromCache(ms); } } } @@ -231,16 +273,11 @@ ModuleStatus addTModel (str qualifiedModuleName, TModel tm, ModuleStatus ms){ tuple[bool, TModel, ModuleStatus] getTModelForModule(str qualifiedModuleName, ModuleStatus ms){ if(traceTModelCache) println("getTModelForModule: "); pcfg = ms.pathConfig; - if(ms.tmodels[qualifiedModuleName]?){ - if(tpl_saved() notin ms.status[qualifiedModuleName]){ - throw "Unsaved tmodel for in cache"; - } + if(ms.tmodels[qualifiedModuleName]? /*&& tpl_uptodate() in ms.status[qualifiedModuleName]*/){ return ; } while(size(ms.tmodels) >= tmodelCacheSize && size(ms.tmodelLIFO) > 0 && ms.tmodelLIFO[-1] != qualifiedModuleName){ - ms.tmodels = delete(ms.tmodels, ms.tmodelLIFO[-1]); - if(traceTModelCache) println("*** deleting tmodel , tmodels: , lifo: "); - ms.tmodelLIFO = ms.tmodelLIFO[..-1]; + ms = removeOldestTModelFromCache(ms); } = getTPLReadLoc(qualifiedModuleName, pcfg); @@ -252,7 +289,7 @@ tuple[bool, TModel, ModuleStatus] getTModelForModule(str qualifiedModuleName, Mo tpl = convertTModel2PhysicalLocs(tpl); ms.tmodels[qualifiedModuleName] = tpl; - ms.status[qualifiedModuleName] += {tpl_uptodate(), tpl_saved()}; + ms.status[qualifiedModuleName] ? {} += {tpl_uptodate(), tpl_saved()}; if(qualifiedModuleName notin hardwired){ ms.tmodelLIFO = [qualifiedModuleName, *ms.tmodelLIFO]; } @@ -285,4 +322,4 @@ int nextClosure(){ void resetClosureCounter(){ closureCounter = 0; -} \ No newline at end of file +} diff --git a/src/org/rascalmpl/core/library/lang/rascalcore/check/CollectType.rsc b/src/org/rascalmpl/core/library/lang/rascalcore/check/CollectType.rsc index 1db9b133..317ad79d 100644 --- a/src/org/rascalmpl/core/library/lang/rascalcore/check/CollectType.rsc +++ b/src/org/rascalmpl/core/library/lang/rascalcore/check/CollectType.rsc @@ -99,8 +99,8 @@ void collect(current: (TypeArg) ` `, Collector c){ } // ---- structured types ------------------------------------------------------ -@doc{Convert structured types, such as list<>. Check here for certain syntactical -conditions, such as: all field names must be distinct in a given type; lists require +@doc{Convert structured types, such as list<>. Check here for certain syntactical +conditions, such as: all field names must be distinct in a given type; lists require exactly one type argument; etc.} public list[&T] dup(list[&T] lst) { @@ -115,7 +115,7 @@ public list[&T] dup(list[&T] lst) { void collect(current:(Type)`list [ < {TypeArg ","}+ tas > ]`, Collector c){ targs = [ta | ta <- tas]; - + collect(targs[0], c); try { dt = c.getType(targs[0]); @@ -124,8 +124,8 @@ void collect(current:(Type)`list [ < {TypeArg ","}+ tas > ]`, Collector c){ } c.fact(current, makeListType(dt)); } catch TypeUnavailable():{ - c.calculate("list type", current, targs, - AType(Solver s){ + c.calculate("list type", current, targs, + AType(Solver s){ dt = s.getType(targs[0]); if (!isEmpty(dt.alabel)) { s.report(warning(tas, "Element name `` ignored")); @@ -143,7 +143,7 @@ void collect(current:(Type)`list [ < {TypeArg ","}+ tas > ]`, Collector c){ void collect(current:(Type)`set [ < {TypeArg ","}+ tas > ]`, Collector c){ targs = [ta | ta <- tas]; collect(targs[0], c); - + try { dt = c.getType(targs[0]); if (!isEmpty(dt.alabel)) { @@ -151,13 +151,13 @@ void collect(current:(Type)`set [ < {TypeArg ","}+ tas > ]`, Collector c){ } c.fact(current, makeSetType(dt)); } catch TypeUnavailable():{ - c.calculate("set type", current, targs, - AType(Solver s){ + c.calculate("set type", current, targs, + AType(Solver s){ dt = s.getType(targs[0]); if (!isEmpty(dt.alabel)) { s.report(warning(tas, "Element name `` ignored")); } - return makeSetType(dt); + return makeSetType(dt); }); } if(size(targs) != 1){ @@ -169,7 +169,7 @@ void collect(current:(Type)`set [ < {TypeArg ","}+ tas > ]`, Collector c){ void collect(current:(Type)`bag [ < {TypeArg ","}+ tas > ]`, Collector c){ targs = [ta | ta <- tas]; - collect(targs[0], c); + collect(targs[0], c); try { c.fact(current, makeBagType(c.getType(targs[0]))); } catch TypeUnavailable(): { @@ -183,7 +183,7 @@ void collect(current:(Type)`bag [ < {TypeArg ","}+ tas > ]`, Collector c){ // ---- map tuple[list[FailMessage] msgs, AType atype] handleMapFields({TypeArg ","}+ tas, AType dt, AType rt){ - if (!isEmpty(dt.alabel) && !isEmpty(rt.alabel) && dt.alabel != rt.alabel) { + if (!isEmpty(dt.alabel) && !isEmpty(rt.alabel) && dt.alabel != rt.alabel) { return <[], makeMapType(dt, rt)>; } else if (!isEmpty(dt.alabel) && !isEmpty(rt.alabel) && dt.alabel == rt.alabel) { return <[error(tas,"Non-well-formed map type, labels must be distinct")], makeMapType(unset(dt, "alabel"),unset(rt,"alabel"))>; @@ -198,7 +198,7 @@ tuple[list[FailMessage] msgs, AType atype] handleMapFields({TypeArg ","}+ tas, A void collect(current:(Type)`map [ < {TypeArg ","}+ tas > ]`, Collector c){ targs = [ta | ta <- tas]; - + if(size(targs) != 2){ c.report(error(current, "Type `map` should have two type arguments")); c.fact(current, amap(avalue(), avalue())); @@ -207,20 +207,20 @@ void collect(current:(Type)`map [ < {TypeArg ","}+ tas > ]`, Collector c){ //c.push(currentAdt, ); collect(targs, c); //c.pop(currentAdt); - + try { = handleMapFields(tas, c.getType(targs[0]), c.getType(targs[1])); for(m <- msgs) c.report(m); c.fact(current, result); } catch TypeUnavailable(): { - c.calculate("map type", current, targs[0..2], + c.calculate("map type", current, targs[0..2], AType(Solver s){ = handleMapFields(tas, s.getType(targs[0]), s.getType(targs[1])); for(m <- msgs) s.report(m); - return result; + return result; }); } - + } // ---- rel @@ -249,7 +249,7 @@ void collect(current:(Type)`rel [ < {TypeArg ","}+ tas > ]`, Collector c){ for(m <- msgs) c.report(m); c.fact(current, result); } catch TypeUnavailable(): { - c.calculate("rel type", current, targs, + c.calculate("rel type", current, targs, AType(Solver s){ = handleRelFields(tas, [s.getType(ta) | ta <- targs]); for(m <- msgs) s.report(m); @@ -284,7 +284,7 @@ void collect(current:(Type)`lrel [ < {TypeArg ","}+ tas > ]`, Collector c){ for(m <- msgs) c.report(m); c.fact(current, result); } catch TypeUnavailable(): { - c.calculate("lrel type", current, targs, + c.calculate("lrel type", current, targs, AType(Solver s){ = handleListRelFields(tas, [s.getType(ta) | ta <- targs]); for(m <- msgs) s.report(m); @@ -313,82 +313,82 @@ tuple[list[FailMessage] msgs, AType atype] handleTupleFields({TypeArg ","}+ tas, return ; } else if (size(distinctLabels) > 0) { return ; - } - return <[], avoid()>; + } + return <[], avoid()>; } void collect(current:(Type)`tuple [ < {TypeArg ","}+ tas > ]`, Collector c){ targs = [ta | ta <- tas]; - collect(tas, c); + collect(tas, c); try { = handleTupleFields(tas, [c.getType(ta) | ta <- targs]); for(m <- msgs) c.report(m); c.fact(current, result); } catch TypeUnavailable():{ - c.calculate("tuple type", current, targs, + c.calculate("tuple type", current, targs, AType(Solver s){ = handleTupleFields(tas, [s.getType(ta) | ta <- targs]); for(m <- msgs) s.report(m); return result; }); } -} +} // ---- type -tuple[list[FailMessage] msgs, AType atype] handleTypeField({TypeArg ","}+ tas, AType fieldType){ +tuple[list[FailMessage] msgs, AType atype] handleTypeField({TypeArg ","}+ tas, AType fieldType){ if (!isEmpty(fieldType.alabel)) { return <[warning(tas, "Field name `` ignored")], areified(fieldType)>; } else { return <[], areified(fieldType)>; - } + } } void collect(current:(Type)`type [ < {TypeArg ","}+ tas > ]`, Collector c){ targs = [ta | ta <- tas]; collect(targs[0], c); - + try { = handleTypeField(tas, c.getType(targs[0])); for(m <- msgs) c.report(m); c.fact(current, result); } catch TypeUnavailable(): { - c.calculate("type type", current, targs[0..1], + c.calculate("type type", current, targs[0..1], AType(Solver s){ = handleTypeField(tas, s.getType(targs[0])); for(m <- msgs) s.report(m); return result; }); - } + } if(size(targs) != 1){ c.report(error(current, "Non-well-formed type, type should have one type argument")); } -} +} // ---- function type --------------------------------------------------------- - -tuple[list[FailMessage] msgs, AType atype] handleFunctionType({TypeArg ","}* _, AType returnType, list[AType] argTypes){ + +tuple[list[FailMessage] msgs, AType atype] handleFunctionType({TypeArg ","}* _, AType returnType, list[AType] argTypes){ return <[], afunc(returnType, argTypes, [])>; } @doc{Convert Rascal function types into their abstract representation.} void collect(current: (FunctionType) ` ( <{TypeArg ","}* tas> )`, Collector c) { - + //println("collect: "); // return type, any type parameters should be closed beginUseTypeParameters(c, closed=true); collect(t, c); endUseTypeParameters(c); - + targs = [ta | ta <- tas]; - + // When a function type occurs in a body, just use closed type parameters beginDefineOrReuseTypeParameters(c,closed=false); for(targ <- targs){ collect(targ, c); } endDefineOrReuseTypeParameters(c); - + c.calculate("function type", current, t + targs, AType(Solver s){ = handleFunctionType(tas, s.getType(t), [s.getType(ta) | ta <- targs]); @@ -400,7 +400,7 @@ void collect(current: (FunctionType) ` ( <{TypeArg ","}* tas> )`, Collec // ---- user defined type ----------------------------------------------------- -tuple[list[FailMessage] msgs, AType atype] handleUserType(QualifiedName n, AType baseType){ +tuple[list[FailMessage] msgs, AType atype] handleUserType(QualifiedName n, AType baseType){ if(aadt(adtName, _, _) := baseType){ nformals = size(baseType.parameters); if(nformals > 0) return <[error(n, "Expected %v type parameter(s) for %q, found 0", nformals, adtName)], baseType>; @@ -426,13 +426,13 @@ void collect(current:(UserType) ``, Collector c){ } else { c.useQualified([qualifier, base], n, {dataId(), aliasId(), lexicalId(), nonterminalId(), keywordId(), layoutId()}, dataOrSyntaxRoles + {moduleId()}); } - + try { = handleUserType(n, c.getType(n)); for(m <- msgs) c.report(m); c.fact(current, result); - } catch TypeUnavailable(): - + } catch TypeUnavailable(): + c.calculate("type without parameters", current, [n], AType(Solver s){ = handleUserType(n, s.getType(n)); @@ -449,7 +449,7 @@ void collect(current:(UserType) `[ <{Type ","}+ ts> ]`, Collect c.useQualified([qualifier, base], n, {dataId(), aliasId(), lexicalId(), nonterminalId(), keywordId(), layoutId()}, dataOrSyntaxRoles + {moduleId()}); } actuals = [t | t <- ts]; - + c.calculate("parameterized type with parameters", current, n + actuals, AType(Solver s){ nactuals = size(actuals); @@ -462,7 +462,7 @@ void collect(current:(UserType) `[ <{Type ","}+ ts> ]`, Collect } else if(aalias(aname, params, aliased) := baseType){ nformals = size(baseType.parameters); if(nactuals != nformals) s.report(error(ts, "Expected %v type parameter(s) for %v, found %v", nformals, aname, nactuals)); - + bindings = (params[i].pname : s.getType(actuals[i]) | i <- index(params)); return instantiateRascalTypeParameters(ts, aliased, bindings, s); } @@ -492,7 +492,7 @@ str md5ContribSym(Nonterminal n) = ""; void collect(current:(Sym) `& `, Collector c){ pname = prettyPrintName(""); - + if( := defineOrReuseTypeParameters(c)){ if(c.isAlreadyDefined(pname, n)){ c.use(n, {typeVarId() }); @@ -509,8 +509,8 @@ void collect(current:(Sym) `& `, Collector c){ //println("Use at "); c.fact(current, n); return; - } - + } + c.fact(current, aparameter(prettyPrintName(""),treeType,closed=true)); } @@ -520,9 +520,9 @@ str md5ContribSym((Sym) `& `) void collect(current:(Sym) `[ <{Sym ","}+ parameters> ]`, Collector c){ params = [p | p <- parameters]; c.use(n, syntaxRoles); - c.calculate("parameterized ", current, n + params, - AType(Solver s) { - base = getSyntaxType(n, s); + c.calculate("parameterized ", current, n + params, + AType(Solver s) { + base = getSyntaxType(n, s); s.requireTrue(isParameterizedNonTerminalType(base), error(current, "Expected a non-terminal type, found %t", base)); nexpected = size(getADTTypeParameters(base)); nparams = size(params); s.requireTrue(nexpected == nparams, error(current, "Expected %v type parameter(s) for %q, found %v", nexpected, getADTName(base), nparams)); @@ -561,21 +561,21 @@ void collect(current:(Sym) ` `, Collector c){ } else { throw "Cannot compute md5 for "; } - + // TODO require symbol is nonterminal - c.define(un, fieldId(), n, defType([symbol], - AType(Solver s){ - res = s.getType(symbol)[alabel=un]; + c.define(un, fieldId(), n, defType([symbol], + AType(Solver s){ + res = s.getType(symbol)[alabel=un]; return res; })[md5=md5Hash("")]); - + c.fact(current, n); collect(symbol, c); } str md5ContribSym((Sym) ` `) = "")>"; - + // ---- literals void collect(current:(Sym) ``, Collector c){ @@ -607,15 +607,15 @@ bool isLexicalContext(Collector c){ adtStack = c.getStack(currentAdt); if(!isEmpty(adtStack) && := adtStack[0]){ return !(adt is language); - } + } return false; } void collect(current:(Sym) `+`, Collector c){ if(isIterSym(symbol)) c.report(warning(current, "Nested iteration")); isLexical = isLexicalContext(c); - c.calculate("iter", current, [symbol], AType(Solver s) { - symbol_type = s.getType(symbol); + c.calculate("iter", current, [symbol], AType(Solver s) { + symbol_type = s.getType(symbol); return isLexical ? \iter(symbol_type, isLexical=true) : \iter(symbol_type); //return isLexical ? \iter(getSyntaxType(symbol, s), isLexical=true) : \iter(getSyntaxType(symbol, s)); }); @@ -624,11 +624,11 @@ void collect(current:(Sym) `+`, Collector c){ str md5ContribSym((Sym) `+`) = "PLUS"; - + void collect(current:(Sym) `*`, Collector c) { if(isIterSym(symbol)) c.report(warning(current, "Nested iteration")); isLexical = isLexicalContext(c); - c.calculate("iterStar", current, [symbol], AType(Solver s) { + c.calculate("iterStar", current, [symbol], AType(Solver s) { symbol_type = s.getType(symbol); return isLexical ? \iter-star(symbol_type, isLexical=true) : \iter-star(symbol_type); //return isLexical ? \iter-star(getSyntaxType(symbol, s), isLexical=true) : \iter-star(getSyntaxType(symbol, s)); @@ -638,12 +638,12 @@ void collect(current:(Sym) `*`, Collector c) { str md5ContribSym((Sym) `*`) = "STAR"; - + void collect(current:(Sym) `{ }+`, Collector c){ if(isIterSym(symbol)) c.report(warning(current, "Nested iteration")); isLexical = isLexicalContext(c); - c.calculate("iterSep", current, [symbol, sep], - AType(Solver s) { + c.calculate("iterSep", current, [symbol, sep], + AType(Solver s) { seps = [s.getType(sep)]; validateSeparators(current, seps, s); symbol_type = s.getType(symbol); @@ -661,8 +661,8 @@ str md5ContribSym((Sym) `{ }+`){ void collect(current:(Sym) `{ }*`, Collector c){ if(isIterSym(symbol)) c.report(warning(current, "Nested iteration")); isLexical = isLexicalContext(c); - c.calculate("iterStarSep", current, [symbol, sep], - AType(Solver s) { + c.calculate("iterStarSep", current, [symbol, sep], + AType(Solver s) { seps = [s.getType(sep)]; validateSeparators(current, seps, s); symbol_type = s.getType(symbol); @@ -676,7 +676,7 @@ str md5ContribSym((Sym) `{ }*`){ res = "LCRCSTAR"; return res; } - + void validateSeparators(Tree current, list[AType] separators, Solver s){ if(all(sep <- separators, isLayoutAType(sep))) s.report(warning(current, "At least one element of separators should be non-layout")); // TODO make error @@ -708,11 +708,11 @@ str md5ContribSym((Sym) `( | <{Sym "|"}+ alternatives> )`) void collect(current:(Sym) `( )`, Collector c){ seqs = first + [seq | seq <- sequence]; - c.calculate("sequence", current, seqs, - AType(Solver s) { + c.calculate("sequence", current, seqs, + AType(Solver s) { symbols = [s.getType(seq) | seq <- seqs]; forbidConsecutiveLayout(current, symbols, s); - return AType::seq(symbols); + return AType::seq(symbols); }); collect(seqs, c); } @@ -752,12 +752,12 @@ void collect(current:(Sym) `^ `, Collector c){ str md5ContribSym((Sym) `^ `) = "BEGIN"; - + void collect(current:(Sym) ` ! `, Collector c){ // TODO: c.use(n, {productionId()}); un = unescape(""); - c.calculate("except", current, [symbol], AType(Solver s) { - res = AType::conditional(s.getType(symbol), {ACondition::\a-except(un) }); + c.calculate("except", current, [symbol], AType(Solver s) { + res = AType::conditional(s.getType(symbol), {ACondition::\a-except(un) }); return res; }); collect(symbol, c); @@ -765,7 +765,7 @@ void collect(current:(Sym) ` ! `, Collector c){ str md5ContribSym((Sym) ` ! `) = "EXCEPT")>"; - + bool isTerminal((Sym) ` @ `) = isTerminal(symbol); bool isTerminal((Sym) ` $`) = isTerminal(symbol); bool isTerminal((Sym) `^ `) = isTerminal(symbol); @@ -775,10 +775,10 @@ default bool isTerminal(Sym s) = s is literal || s is caseInsensitiveLiteral || s is characterClass; void collect(current:(Sym) ` \>\> `, Collector c){ - c.calculate("follow", current, [symbol, match], - AType(Solver s) { + c.calculate("follow", current, [symbol, match], + AType(Solver s) { s.requireTrue(isTerminal(match), warning(match, "Followed By (`\>\>`) requires literal or character class, found %v", match)); - return AType::conditional(s.getType(symbol), {ACondition::\follow(s.getType(match)) }); + return AType::conditional(s.getType(symbol), {ACondition::\follow(s.getType(match)) }); }); collect(symbol, match, c); } @@ -787,10 +787,10 @@ str md5ContribSym((Sym) ` \>\> `) = "FOLLOW"; void collect(current:(Sym) ` !\>\> `, Collector c){ - c.calculate("notFollow", current, [symbol, match], - AType(Solver s) { + c.calculate("notFollow", current, [symbol, match], + AType(Solver s) { s.requireTrue(isTerminal(match), warning(match, "Not Followed By (`!\>\>`) requires literal or character class, found %v", match)); - res = AType::conditional(s.getType(symbol), {ACondition::\not-follow(s.getType(match)) }); + res = AType::conditional(s.getType(symbol), {ACondition::\not-follow(s.getType(match)) }); return res; }); collect(symbol, match, c); @@ -798,12 +798,12 @@ void collect(current:(Sym) ` !\>\> `, Collector c){ str md5ContribSym((Sym) ` !\>\> `) = "NOTFOLLOW"; - + void collect(current:(Sym) ` \<\< `, Collector c){ - c.calculate("precede", current, [match, symbol], - AType(Solver s) { + c.calculate("precede", current, [match, symbol], + AType(Solver s) { s.requireTrue(isTerminal(match), warning(match, "Preceded By (`\<\<`) requires literal or character class, found %v", match)); - return AType::conditional(s.getType(symbol), {ACondition::\precede(s.getType(match)) }); + return AType::conditional(s.getType(symbol), {ACondition::\precede(s.getType(match)) }); }); collect(match, symbol, c); } @@ -812,20 +812,20 @@ str md5ContribSym((Sym) ` \<\< `) = "PRECEDE"; void collect(current:(Sym) ` !\<\< `, Collector c){ - c.calculate("notPrecede", current, [match, symbol], - AType(Solver s) { + c.calculate("notPrecede", current, [match, symbol], + AType(Solver s) { s.requireTrue(isTerminal(match), warning(match, "Not Preceded By (`!\<\<`) requires literal or character class, found %v", match)); - return AType::conditional(s.getType(symbol), {ACondition::\not-precede(s.getType(match)) }); + return AType::conditional(s.getType(symbol), {ACondition::\not-precede(s.getType(match)) }); }); collect(match, symbol, c); } str md5ContribSym((Sym) ` !\<\< `) = "NOTPRECEDE"; - + void collect(current:(Sym) ` \\ `, Collector c){ - c.calculate("exclude", current, [symbol, match], - AType(Solver s) { + c.calculate("exclude", current, [symbol, match], + AType(Solver s) { t = s.getType(match); if(alit(_) !:= t && (t has syntaxRole && t.syntaxRole != keywordSyntax())){ s.report(error(match, "Exclude (`\\`) requires keywords as right argument, found %t", match)); @@ -847,7 +847,7 @@ void collect(Sym current, Collector c){ void collect(current:(TypeVar) `& `, Collector c){ pname = prettyPrintName(n); - + if( := defineOrReuseTypeParameters(c)){ if(c.isAlreadyDefined(pname, n)){ c.use(n, {typeVarId() }); @@ -865,22 +865,22 @@ void collect(current:(TypeVar) `& `, Collector c){ } c.calculate("xxx", current, [n], AType (Solver s) { return s.getType(n)[closed=closed]; }); return; - + } else if( := useTypeParameters(c)){ c.use(n, {typeVarId() }); //if(debugTP)println("Use at , closed="); c.calculate("xxx", current, [n], AType (Solver s) { return s.getType(n)[closed=closed]; }); return; - } else { + } else { if( := useBoundedTypeParameters(c)){ if(tpbounds[pname]?){ bnds = toList(tpbounds[pname]); //if(debugTP)println("collect: Adding calculator for "); c.calculate("type parameter with bound", current, bnds, - AType(Solver s){ + AType(Solver s){ new_bnd = (avalue() | aglb(it, s.getType(bnd)) | bnd <- bnds); return aparameter(pname, new_bnd, closed=true); - }); + }); } else { //if(debugTP)println("collect: fact for , closed="); c.fact(current, aparameter(pname, avalue(), closed=true)); @@ -893,12 +893,12 @@ void collect(current:(TypeVar) `& `, Collector c){ void collect(current: (TypeVar) `& \<: `, Collector c){ pname = prettyPrintName(n); - + if( := defineOrReuseTypeParameters(c)){ if(c.isAlreadyDefined(pname, n)){ c.use(n, {typeVarId() }); //if(debugTP)println("Use at "); - } else { + } else { c.define(pname, typeVarId(), n, defTypeCall([getLoc(tp)], AType(Solver s) {return aparameter(pname,s.getType(tp), closed=closed); })); //if(debugTP)println("Define at "); } @@ -910,21 +910,21 @@ void collect(current: (TypeVar) `& \<: `, Collector c){ } else if( := useBoundedTypeParameters(c)){ if(!isEmpty(tpbounds[pname])){ bnds = toList(tpbounds[pname]); - c.calculate("type parameter with bound", n, bnds, - AType(Solver s){ + c.calculate("type parameter with bound", n, bnds, + AType(Solver s){ new_bnd = (avalue() | aglb(it, s.getType(bnd)) | bnd <- bnds); return aparameter(prettyPrintName(n), s.getType(new_bnd), closed=true); - }); + }); } else { c.calculate("type parameter with bound", n, [tp], AType(Solver s){ return aparameter(prettyPrintName(n), s.getType(tp), closed=true); }); - } + } c.fact(current, n); } - + collect(tp, c); } @doc{A parsing function, useful for generating test cases.} public Type parseType(str s) { return parse(#Type, s); -} \ No newline at end of file +} diff --git a/src/org/rascalmpl/core/library/lang/rascalcore/check/Import.rsc b/src/org/rascalmpl/core/library/lang/rascalcore/check/Import.rsc index 5275bd5e..2abfeda4 100644 --- a/src/org/rascalmpl/core/library/lang/rascalcore/check/Import.rsc +++ b/src/org/rascalmpl/core/library/lang/rascalcore/check/Import.rsc @@ -117,7 +117,9 @@ ModuleStatus getImportAndExtendGraph(str qualifiedModuleName, ModuleStatus ms){ lm = getLastModified(m, ms.moduleLastModified, pcfg); if(lm == startOfEpoch || lm > timestampInBom) { allImportsAndExtendsValid = false; - if(tpl_uptodate() notin ms.status[m] && lm != timestampInBom && ms.compilerConfig.verbose){ + ms.status[m] += rsc_changed(); + ms.status[m] -= {tpl_uptodate(), checked()}; + if(ms.compilerConfig.verbose){ println("--- using (most recent) version of , ' older version was used in previous check of "); } @@ -132,7 +134,8 @@ ModuleStatus getImportAndExtendGraph(str qualifiedModuleName, ModuleStatus ms){ mloc = getModuleLocation(qualifiedModuleName, pcfg); if(mloc.extension != "rsc" || isModuleLocationInLibs(mloc, pcfg)) throw "No src or library module 1"; //There is only a tpl file available } catch value _:{ - if(!isCompatibleBinary(tm, domain(localImportsAndExtends), ms)){ + = isCompatibleBinaryLibrary(tm, domain(localImportsAndExtends), ms); + if(!compatible){ msg = error("Binary module `qualifiedModuleName` needs recompilation", |unknown:///|); tm.messages += [msg]; ms.messages[qualifiedModuleName] ? [] += [msg]; @@ -147,12 +150,11 @@ ModuleStatus getImportAndExtendGraph(str qualifiedModuleName, ModuleStatus ms){ } if(allImportsAndExtendsValid){ ms.status[qualifiedModuleName] += {tpl_uptodate(), checked()}; //TODO: maybe check existence of generated java files - ms.moduleLocs += tm.moduleLocs; ms.paths += tm.paths; ms.strPaths += { | <- localImportsAndExtends }; ms.status[qualifiedModuleName] += module_dependencies_extracted(); - for(imp <- localImportsAndExtends<0>, module_dependencies_extracted() notin ms.status[imp] ){ + for(imp <- localImportsAndExtends<0>, isEmpty({module_dependencies_extracted()} & ms.status[imp]) ){ ms = getImportAndExtendGraph(imp, ms); } return ms; @@ -172,9 +174,7 @@ ModuleStatus getImportAndExtendGraph(str qualifiedModuleName, ModuleStatus ms){ ms = getImportAndExtendGraph(imp, ms); } } else { - if(rsc_not_found() notin ms.status[qualifiedModuleName]){ - ms.status[qualifiedModuleName] += rsc_not_found(); - } + ms.status[qualifiedModuleName] += rsc_not_found(); } return ms; @@ -192,27 +192,61 @@ ModuleStatus getInlineImportAndExtendGraph(Tree pt, RascalCompilerConfig ccfg){ return complete(ms); } +// Example: |rascal+function:///util/Math/round$d80e373d64c01979| ==> util::Math str getModuleFromLogical(loc l){ - i = findFirst(l.path[1..], "/"); - return i >= 0 ? l.path[1..i+1] : l.path[1..]; + i = findLast(l.path[1..], "/"); + res = i >= 0 ? l.path[1..i+1] : l.path[1..]; + return replaceAll(res, "/", "::"); } -bool isCompatibleBinary(TModel lib, set[str] otherImportsAndExtends, ModuleStatus ms){ - - provides = { | l <- domain(lib.logical2physical), m := getModuleFromLogical(l) }; - requires = {}; - for(m <- otherImportsAndExtends){ +// Is what library module lib provides compatible with all uses in the modules libUsers? +tuple[bool, ModuleStatus] isCompatibleBinaryLibrary(TModel lib, set[str] libUsers, ModuleStatus ms){ + libName = lib.modelName; + libProvides = domain(lib.logical2physical); + libProvidesModules = { getModuleFromLogical(l) | l <- libProvides }; + usersRequire = {}; + for(m <- libUsers){ = getTModelForModule(m, ms); if(found){ - requires += { | l <- domain(tm.logical2physical), m := getModuleFromLogical(l) }; + usersRequire += domain(tm.logical2physical); } } + usersRequireFromLib = { l | l <- usersRequire, getModuleFromLogical(l) in libProvidesModules }; + + if(usersRequireFromLib <= libProvides){ + //println("isCompatibleBinaryLibrary : satisfied"); + return ; + } else { + //println("isCompatibleBinaryLibrary, unsatisfied: "); + return ; + } +} - if(isEmpty(requires - provides)){ - return true; +tuple[bool, ModuleStatus] importsAndExtendsAreBinaryCompatible(TModel tm, set[str] importsAndExtends, ModuleStatus ms){ + moduleName = tm.modelName; + physical2logical = invertUnique(tm.logical2physical); + + modRequires = { lg | l <- range(tm.useDef), + physical2logical[l]?, lg := physical2logical[l], + moduleName !:= getModuleFromLogical(lg) }; + provided = {}; + if(!isEmpty(modRequires)){ + for(m <- importsAndExtends){ + = getTModelForModule(m, ms); + if(found){ + provided += domain(tm.logical2physical); + } + } + } + + //println(" requires "); + + if(isEmpty(modRequires - provided)){ + //println("importsAndExtendsAreBinaryCompatible : satisfied"); + return ; } else { - println("isCompatibleBinary, unsatisfied: "); - return false; + //println("importsAndExtendsAreBinaryCompatible, unsatisfied: "); + return ; } } @@ -290,6 +324,28 @@ tuple[map[str,TModel], ModuleStatus] prepareForCompilation(set[str] component, m } return ; } +rel[str,datetime,PathRole] makeBom(str qualifiedModuleName, set[str] imports, set[str] extends, ModuleStatus ms){ + map[str,datetime] moduleLastModified = ms.moduleLastModified; + pcfg = ms.pathConfig; + return { < m, getLastModified(m, moduleLastModified, pcfg), importPath() > | m <- imports } + + { < m, getLastModified(m, moduleLastModified, pcfg), extendPath() > | m <- extends } + + { }; +} +void updateBOM(str qualifiedModuleName, set[str] imports, set[str] extends, ModuleStatus ms){ + = getTModelForModule(qualifiedModuleName, ms); + if(found){ + newBom = makeBom(qualifiedModuleName, imports, extends, ms); + if(newBom != tm.store[key_bom]){ + tm.store[key_bom] = newBom; + ms.status[qualifiedModuleName] -= tpl_saved(); + addTModel(qualifiedModuleName, tm, ms); + + if(ms.compilerConfig.logWrittenFiles) println("Updated BOM: "); + } + } else{ + println("Could not update BOM of "); + } +} ModuleStatus doSaveModule(set[str] component, map[str,set[str]] m_imports, map[str,set[str]] m_extends, ModuleStatus ms, map[str,loc] moduleScopes, map[str, TModel] transient_tms, RascalCompilerConfig compilerConfig){ map[str,datetime] moduleLastModified = ms.moduleLastModified; @@ -315,15 +371,14 @@ ModuleStatus doSaveModule(set[str] component, map[str,set[str]] m_imports, map[s for(qualifiedModuleName <- component){ start_save = cpuTime(); tm = transient_tms[qualifiedModuleName]; - try { + //try { mscope = getModuleScope(qualifiedModuleName, moduleScopes, pcfg); = getTPLWriteLoc(qualifiedModuleName, pcfg); + imports = m_imports[qualifiedModuleName]; extends = m_extends[qualifiedModuleName]; - bom = { < m, getLastModified(m, moduleLastModified, pcfg), importPath() > | m <- imports } - + { < m, getLastModified(m, moduleLastModified, pcfg), extendPath() > | m <- extends } - + { }; + bom = makeBom(qualifiedModuleName, imports, extends, ms); extendedModuleScopes = {getModuleScope(m, moduleScopes, pcfg) | str m <- extends, checked() in ms.status[m]}; extendedModuleScopes += {*tm.paths[ems,importPath()] | ems <- extendedModuleScopes}; // add imports of extended modules @@ -395,57 +450,15 @@ ModuleStatus doSaveModule(set[str] component, map[str,set[str]] m_imports, map[s case kwField(AType atype, str fieldName, str definingModule, Expression _defaultExp) => kwField(atype, fieldName, definingModule) case loc l : if(!isEmpty(l.fragment)) insert l[fragment=""]; }; - m1.logical2physical = tm.logical2physical; - //println("Import, tmodel:"); iprintln(m1); - m1 = convertTModel2LogicalLocs(m1, ms.tmodels); - - ////TODO temporary check: are external locations present in the TModel? If so, throw exception - // - //result = ""; - // - //void checkPhysical(value v, str label){ - // visit(v){ - // case loc l: - // if(!(isContainedInComponentScopes(l) || l == |global-scope:///| || contains(l.scheme, "rascal+"))) - // result += "