diff --git a/Jenkinsfile b/Jenkinsfile index 2b3080220..2164a2c2a 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -144,7 +144,8 @@ melt.trynode('silver') { // Projects with 'develop' as main branch, we'll try to build specific branch names if they exist def github_projects = ["/melt-umn/ableC", "/melt-umn/Oberon0", "/melt-umn/meta-ocaml-lite", "/melt-umn/lambda-calculus", "/melt-umn/rewriting-regex-matching", "/melt-umn/rewriting-optimization-demo", - "/melt-umn/caml-light", "/melt-umn/tree-sharing-demo"] + "/melt-umn/caml-light", "/melt-umn/tree-sharing-demo", + "/melt-umn/foil"] // These are not currently maintened: "/internal/ring" // Specific other jobs to build def specific_jobs = ["/internal/matlab/master"] diff --git a/check-compile b/check-compile index 555623cb2..1a4b9245e 100755 --- a/check-compile +++ b/check-compile @@ -9,7 +9,7 @@ set -euo pipefail BUILDGRAMMAR=${BUILDGRAMMAR:-"silver:compiler:composed:Default"} export SILVER_HOME=$PWD -JVM_ARGS=(-Xss30M -Xmx6G -jar ../jars/silver.compiler.composed.Default.jar --no-stdlib --dont-translate "$@") +JVM_ARGS=(-Xss30M -Xmx7G -jar ../jars/silver.compiler.composed.Default.jar --no-stdlib --dont-translate "$@") export GRAMMAR_PATH="../grammars" mkdir -p build diff --git a/grammars/silver/compiler/analysis/typechecking/core/Expr.sv b/grammars/silver/compiler/analysis/typechecking/core/Expr.sv index f94c835ed..15785859a 100644 --- a/grammars/silver/compiler/analysis/typechecking/core/Expr.sv +++ b/grammars/silver/compiler/analysis/typechecking/core/Expr.sv @@ -5,7 +5,7 @@ import silver:compiler:definition:flow:env; attribute upSubst, downSubst, upSubst2, downSubst2, finalSubst occurs on Expr, ExprInhs, ExprInh, Exprs, AppExprs, AppExpr, AnnoExpr, AnnoAppExprs; -flowtype Expr = upSubst {forward}, finalType {forward}; +flowtype Expr = upSubst {forward}, upSubst2 {forward, downSubst2}, finalType {forward}; propagate upSubst, downSubst on Expr, ExprInhs, ExprInh, Exprs, AppExprs, AppExpr, AnnoExpr, AnnoAppExprs diff --git a/grammars/silver/compiler/analysis/uniqueness/Expr.sv b/grammars/silver/compiler/analysis/uniqueness/Expr.sv index 88c6e48dd..b06133c0c 100644 --- a/grammars/silver/compiler/analysis/uniqueness/Expr.sv +++ b/grammars/silver/compiler/analysis/uniqueness/Expr.sv @@ -2,7 +2,7 @@ grammar silver:compiler:analysis:uniqueness; attribute sharedRefs occurs on Expr, Exprs, AppExprs, AppExpr, PrimPatterns, PrimPattern; propagate sharedRefs on Expr, Exprs, AppExprs, AppExpr, PrimPatterns, PrimPattern - excluding ifThenElse, matchPrimitiveReal, consPattern; + excluding ifThenElse, matchPrimitiveReal, consPattern, letp; aspect production decorationSiteExpr top::Expr ::= '@' e::Expr @@ -25,9 +25,10 @@ top::Expr ::= '@' e::Expr top.errors <- case e.flowVertexInfo of -- These are errors because we assume these checks in the translation: - | just(lhsVertexType_real()) -> [errFromOrigin(e, s"Cannot share the production LHS.")] - | just(forwardVertexType_real()) -> [errFromOrigin(e, s"Cannot share the forward tree.")] - | just(anonVertexType(_)) -> [errFromOrigin(e, s"Cannot share an anonymously decorated tree.")] -- TODO: I think this works now? + | just(lhsVertexType()) -> [errFromOrigin(e, s"Cannot share the production LHS.")] + | just(forwardVertexType()) -> [errFromOrigin(e, s"Cannot share the forward tree.")] + | just(anonVertexType(_, _, _)) -> [errFromOrigin(e, s"Cannot share an anonymously decorated tree.")] -- TODO: I think this works now? + | just(subtermVertexType(_, _, _)) -> [errFromOrigin(e, s"Cannot share a pattern variable.")] -- Only way this can happen | just(v) -> -- Check that this tree is shared in at most one non-mutually-exclusive place. case lookupSharedRefs(top.frame.fullName, v, top.flowEnv) of @@ -68,9 +69,10 @@ top::AppExpr ::= e::Expr if sigIsShared && isForwardParam then case e.flowVertexInfo of -- These are errors because we assume these checks in the translation: - | just(lhsVertexType_real()) -> [errFromOrigin(e, s"Cannot share the production LHS.")] - | just(forwardVertexType_real()) -> [errFromOrigin(e, s"Cannot share the forward tree.")] - | just(anonVertexType(_)) -> [errFromOrigin(e, s"Cannot share an anonymously decorated tree.")] -- TODO: I think this works now? + | just(lhsVertexType()) -> [errFromOrigin(e, s"Cannot share the production LHS.")] + | just(forwardVertexType()) -> [errFromOrigin(e, s"Cannot share the forward tree.")] + | just(anonVertexType(_, _, _)) -> [errFromOrigin(e, s"Cannot share an anonymously decorated tree.")] -- TODO: I think this works now? + | just(subtermVertexType(_, _, _)) -> [errFromOrigin(e, s"Cannot share a pattern variable.")] -- Only way this can happen | just(v) -> -- Check that this tree is shared in at most one non-mutually-exclusive place. case lookupSharedRefs(top.frame.fullName, v, top.flowEnv) of @@ -114,3 +116,15 @@ top::PrimPatterns ::= p::PrimPattern _ ps::PrimPatterns { top.sharedRefs := unionMutuallyExclusiveRefs(p.sharedRefs, ps.sharedRefs); } + +aspect production letp +top::Expr ::= la::AssignExpr e::Expr +{ + top.sharedRefs := e.sharedRefs; +} + +aspect production lexicalLocalReference +top::Expr ::= @q::QName _ _ sr::[(String, SharedRefSite)] +{ + top.sharedRefs <- sr; +} diff --git a/grammars/silver/compiler/analysis/warnings/flow/FlowTypeCopyEquation.sv b/grammars/silver/compiler/analysis/warnings/flow/FlowTypeCopyEquation.sv index 73b457368..419a60909 100644 --- a/grammars/silver/compiler/analysis/warnings/flow/FlowTypeCopyEquation.sv +++ b/grammars/silver/compiler/analysis/warnings/flow/FlowTypeCopyEquation.sv @@ -13,6 +13,9 @@ grammar silver:compiler:analysis:warnings:flow; -- The flow environment can give us the authoritative list of those attributes to check. -- These may be from `options` and so requires the flowEnv. +-- TODO: Lots of duplicate warnings here when a projected production exceeds a flow type. +-- Somehow suppress them? Or filter out edges from tile stitch points that exceed a flow type? + aspect production productionDcl top::AGDcl ::= 'abstract' 'production' id::Name d::ProductionImplements ns::ProductionSignature body::ProductionBody { @@ -40,7 +43,7 @@ function raiseImplicitFwdEqFlowTypes [Message] ::= config::Decorated CmdArgs lhsNt::String prod::String attr::String e::FlowEnv myGraph::ProductionGraph myFlow::EnvTree { -- The actual dependencies for `forward.attr` - local fwdFlowDeps :: set:Set = onlyLhsInh(expandGraph([forwardEqVertex(), forwardSynVertex(attr)], myGraph)); + local fwdFlowDeps :: set:Set = onlyLhsInh(expandGraph(forwardVertexType().synDeps(attr), myGraph)); -- The flow type for `attr` on `lhsNt` local depsForThisAttr :: set:Set = inhDepsForSyn(attr, lhsNt, myFlow); -- Actual forwards equation deps not in the flow type for `attr` diff --git a/grammars/silver/compiler/analysis/warnings/flow/HiddenTransitiveDeps.sv b/grammars/silver/compiler/analysis/warnings/flow/HiddenTransitiveDeps.sv new file mode 100644 index 000000000..141377c9d --- /dev/null +++ b/grammars/silver/compiler/analysis/warnings/flow/HiddenTransitiveDeps.sv @@ -0,0 +1,576 @@ +grammar silver:compiler:analysis:warnings:flow; + +aspect production synthesizedAttributeDef +top::ProductionStmt ::= @dl::DefLHS @attr::QNameAttrOccur e::Expr +{ + -- Extension productions that implement a dispatch signature + + local ns :: NamedSignature = -- top.frame.signature might have aspect sig names that don't match the flow env + case getValueDcl(top.frame.fullName, top.env) of + | dcl :: _ -> dcl.namedSignature + | _ -> error("didn't find a decl for prod " ++ top.frame.fullName) + end; + local implementedSig :: Maybe = + case getValueDcl(top.frame.fullName, top.env) of + | dcl :: _ -> dcl.implementedSignature + | _ -> nothing() + end; + local dispatchHostSigDeps:: Maybe> = do { + dispatchSig :: NamedSignature <- implementedSig; + guard(!isExportedBy( + top.frame.sourceGrammar, + [substring(0, lastIndexOf(":", dispatchSig.fullName), dispatchSig.fullName)], + top.compiledGrammars)); + return set:fromList(flatMap(fromDispatchSigVertex(dispatchSig, ns, _), + set:toList(findProductionGraph(dispatchSig.fullName, myGraphs).tileEdgeMap( + lhsSynVertex(attr.attrDcl.fullName))))); + }; + + local sigNames::[String] = + take(length(fromMaybe(ns, implementedSig).inputNames), ns.inputNames); + local tileSigDeps::set:Set = + expandTileGraphSigDeps(e.flowDeps, sigNames, top.frame.flowGraph); + + -- problem = lhsinh deps - inh deps on host implementation prods + local tileSigDepsExceedsDispatchHostSigDeps :: [FlowVertex] = + case dispatchHostSigDeps of + | just(deps) -> set:toList(set:difference(tileSigDeps, deps)) + | _ -> [] + end; + + top.errors <- + case implementedSig of + | just(sig) + when top.config.warnMissingInh + && !null(tileSigDepsExceedsDispatchHostSigDeps) -> + [mwdaWrnFromOrigin(top, + s"Synthesized override equation for ${attr.attrDcl.fullName} has excess dependencies on\n" ++ + flatMap(\ v::FlowVertex -> s"\t${v.vertexName}\n", tileSigDepsExceedsDispatchHostSigDeps) ++ + s"In host-language implementations of dispatch ${sig.fullName}, it depends ${depVertexListStr(dispatchHostSigDeps.fromJust)}")] + | _ -> [] + end; +} + +aspect production inheritedAttributeDef +top::ProductionStmt ::= @dl::DefLHS @attr::QNameAttrOccur e::Expr +{ + -- Make sure we aren't introducing any hidden transitive dependencies. + + -- oh no again! + local myGraphs::EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).productionFlowGraphs; + + local vertexHasHideableEq :: (Boolean ::= VertexType String) = + possibleDecSiteHasInhEq(top.frame.fullName, _, _, myGraphs, top.flowEnv, top.env); + + local refDecSiteInhDepsLhsInh :: Maybe> = + case filter(vertexHasHideableEq(_, attr.attrDcl.fullName), dl.defLHSDecSites) of + | [] -> nothing() + | vs -> just(onlyLhsInh(expandGraph( + dl.defLHSVertex.outerEqDeps ++ + flatMap(\ v::VertexType -> v.inhDeps(attr.attrDcl.fullName), vs), + top.frame.flowGraph))) + end; + + local transBaseRefDecSiteInhDepsLhsInh :: Maybe> = + case dl.defLHSVertex of + | transAttrVertexType(v, transAttr) -> + case filter(vertexHasHideableEq(_, dl.inhAttrName), dl.defLHSTransBaseDecSites) of + | [] -> nothing() + | vs -> just(onlyLhsInh(expandGraph( + v.outerEqDeps ++ + flatMap(\ v::VertexType -> v.inhDeps(dl.inhAttrName), vs), + top.frame.flowGraph))) + end + | _ -> nothing() + end; + + -- problem = lhsinh deps - inh deps on dec site + local lhsInhExceedsRefDecSiteDeps :: [String] = + case refDecSiteInhDepsLhsInh of + | just(deps) -> set:toList(set:difference(lhsInhDeps, deps)) + | _ -> [] + end; + + local lhsInhExceedsTransBaseRefDecSiteDeps :: [String] = + case transBaseRefDecSiteInhDepsLhsInh of + | just(deps) -> set:toList(set:difference(lhsInhDeps, deps)) + | _ -> [] + end; + + -- Extension productions that implement a dispatch signature + + local ns :: NamedSignature = -- top.frame.signature might have aspect sig names that don't match the flow env + case getValueDcl(top.frame.fullName, top.env) of + | dcl :: _ -> dcl.namedSignature + | _ -> error("didn't find a decl for prod " ++ top.frame.fullName) + end; + local implementedSig :: Maybe = + case getValueDcl(top.frame.fullName, top.env) of + | dcl :: _ -> dcl.implementedSignature + | _ -> nothing() + end; + local dispatchHostSigDeps:: Maybe> = do { + dispatchSig :: NamedSignature <- implementedSig; + guard(!isExportedBy( + top.frame.sourceGrammar, + [substring(0, lastIndexOf(":", dispatchSig.fullName), dispatchSig.fullName)], + top.compiledGrammars)); + sigName <- + case dl.defLHSVertex of + | rhsVertexType(sigName) -> just(sigName) + | transAttrVertexType(rhsVertexType(sigName), _) -> just(sigName) + | _ -> nothing() + end; + let sigPos = positionOf(sigName, ns.inputNames); + when_(sigPos < 0, error("sigName lookup failed")); + guard(sigPos < length(dispatchSig.inputElements)); + let dispatchVertex = rhsInhVertex( + head(drop(sigPos, dispatchSig.inputElements)).elementName, + dl.inhAttrName); + return set:fromList(flatMap(fromDispatchSigVertex(dispatchSig, ns, _), + rhsEqVertex(sigName) :: -- TODO: Workaround: the rhs inh vertex should depend on the rhs eq vertex already! + set:toList(findProductionGraph(dispatchSig.fullName, myGraphs).tileEdgeMap(dispatchVertex)))); + }; + + local sigNames::[String] = + take(length(fromMaybe(ns, implementedSig).inputNames), ns.inputNames); + local tileSigDeps::set:Set = + expandTileGraphSigDeps(e.flowDeps, sigNames, top.frame.flowGraph); + + -- problem = lhsinh deps - inh deps on host implementation prods + local tileSigDepsExceedsDispatchHostSigDeps :: [FlowVertex] = + case dispatchHostSigDeps of + | just(deps) -> set:toList(set:difference(tileSigDeps, deps)) + | _ -> [] + end; + + top.errors <- + if top.config.warnMissingInh + && !null(lhsInhExceedsRefDecSiteDeps) + then + [mwdaWrnFromOrigin(top, + s"Inherited override equation for ${attr.attrDcl.fullName} on ${dl.defLHSVertex.vertexPP} may exceed a flow type " ++ + s"with hidden transitive dependencies on ${implode(", ", lhsInhExceedsRefDecSiteDeps)}; " ++ + s"on some reference to this tree, this attribute may be expected to depend ${depListStr(refDecSiteInhDepsLhsInh.fromJust)}" ++ + s" (from ${implode(", ", map((.vertexPP), lookupRefPossibleDecSites(top.frame.fullName, dl.defLHSVertex, top.flowEnv)))})")] + else []; + top.errors <- + case dl.defLHSVertex of + | transAttrVertexType(v, transAttr) + when top.config.warnMissingInh + && !null(lhsInhExceedsTransBaseRefDecSiteDeps) -> + [mwdaWrnFromOrigin(top, + s"Inherited override equation for ${transAttr}.${attr.attrDcl.fullName} on ${v.vertexPP} may exceed a flow type " ++ + s"with hidden transitive dependencies on ${implode(", ", lhsInhExceedsTransBaseRefDecSiteDeps)}; " ++ + s"on some reference to this tree, this attribute may be expected to depend ${depListStr(transBaseRefDecSiteInhDepsLhsInh.fromJust)}" ++ + s" (from ${implode(", ", map((.vertexPP), lookupRefPossibleDecSites(top.frame.fullName, v, top.flowEnv)))})")] + | _ -> [] + end; + top.errors <- + case implementedSig of + | just(sig) + when top.config.warnMissingInh + && !null(tileSigDepsExceedsDispatchHostSigDeps) -> + [mwdaWrnFromOrigin(top, + s"Inherited override equation for ${attr.attrDcl.fullName} on ${dl.defLHSVertex.vertexPP} has excess dependencies on\n" ++ + flatMap(\ v::FlowVertex -> s"\t${v.vertexName}\n", tileSigDepsExceedsDispatchHostSigDeps) ++ + s"In host-language implementations of dispatch ${sig.fullName}, it depends ${depVertexListStr(dispatchHostSigDeps.fromJust)}")] + | _ -> [] + end; +} + +-- TODO: massive copy/paste section for collection equations: +aspect production synBaseColAttributeDef +top::ProductionStmt ::= @dl::DefLHS @attr::QNameAttrOccur e::Expr +{ + -- Extension productions that implement a dispatch signature + + local ns :: NamedSignature = -- top.frame.signature might have aspect sig names that don't match the flow env + case getValueDcl(top.frame.fullName, top.env) of + | dcl :: _ -> dcl.namedSignature + | _ -> error("didn't find a decl for prod " ++ top.frame.fullName) + end; + local implementedSig :: Maybe = + case getValueDcl(top.frame.fullName, top.env) of + | dcl :: _ -> dcl.implementedSignature + | _ -> nothing() + end; + local dispatchHostSigDeps:: Maybe> = do { + dispatchSig :: NamedSignature <- implementedSig; + guard(!isExportedBy( + top.frame.sourceGrammar, + [substring(0, lastIndexOf(":", dispatchSig.fullName), dispatchSig.fullName)], + top.compiledGrammars)); + return set:fromList(flatMap(fromDispatchSigVertex(dispatchSig, ns, _), + set:toList(findProductionGraph(dispatchSig.fullName, myGraphs).tileEdgeMap( + lhsSynVertex(attr.attrDcl.fullName))))); + }; + + local sigNames::[String] = + take(length(fromMaybe(ns, implementedSig).inputNames), ns.inputNames); + local tileSigDeps::set:Set = + expandTileGraphSigDeps(e.flowDeps, sigNames, top.frame.flowGraph); + + -- problem = lhsinh deps - inh deps on host implementation prods + local tileSigDepsExceedsDispatchHostSigDeps :: [FlowVertex] = + case dispatchHostSigDeps of + | just(deps) -> set:toList(set:difference(tileSigDeps, deps)) + | _ -> [] + end; + + top.errors <- + case implementedSig of + | just(sig) + when top.config.warnMissingInh + && !null(tileSigDepsExceedsDispatchHostSigDeps) -> + [mwdaWrnFromOrigin(top, + s"Synthesized override equation for ${attr.attrDcl.fullName} has excess dependencies on\n" ++ + flatMap(\ v::FlowVertex -> s"\t${v.vertexName}\n", tileSigDepsExceedsDispatchHostSigDeps) ++ + s"In host-language implementations of dispatch ${sig.fullName}, it depends ${depVertexListStr(dispatchHostSigDeps.fromJust)}")] + | _ -> [] + end; +} +aspect production synAppendColAttributeDef +top::ProductionStmt ::= @dl::DefLHS @attr::QNameAttrOccur e::Expr +{ + -- Extension productions that implement a dispatch signature + + local ns :: NamedSignature = -- top.frame.signature might have aspect sig names that don't match the flow env + case getValueDcl(top.frame.fullName, top.env) of + | dcl :: _ -> dcl.namedSignature + | _ -> error("didn't find a decl for prod " ++ top.frame.fullName) + end; + local implementedSig :: Maybe = + case getValueDcl(top.frame.fullName, top.env) of + | dcl :: _ -> dcl.implementedSignature + | _ -> nothing() + end; + local dispatchHostSigDeps:: Maybe> = do { + dispatchSig :: NamedSignature <- implementedSig; + guard(!isExportedBy( + top.frame.sourceGrammar, + [substring(0, lastIndexOf(":", dispatchSig.fullName), dispatchSig.fullName)], + top.compiledGrammars)); + return set:fromList(flatMap(fromDispatchSigVertex(dispatchSig, ns, _), + set:toList(findProductionGraph(dispatchSig.fullName, myGraphs).tileEdgeMap( + lhsSynVertex(attr.attrDcl.fullName))))); + }; + + local sigNames::[String] = + take(length(fromMaybe(ns, implementedSig).inputNames), ns.inputNames); + local tileSigDeps::set:Set = + expandTileGraphSigDeps(e.flowDeps, sigNames, top.frame.flowGraph); + + -- problem = lhsinh deps - inh deps on host implementation prods + local tileSigDepsExceedsDispatchHostSigDeps :: [FlowVertex] = + case dispatchHostSigDeps of + | just(deps) -> set:toList(set:difference(tileSigDeps, deps)) + | _ -> [] + end; + + top.errors <- + case implementedSig of + | just(sig) + when top.config.warnMissingInh + && !null(tileSigDepsExceedsDispatchHostSigDeps) -> + [mwdaWrnFromOrigin(top, + s"Synthesized contribution equation for ${attr.attrDcl.fullName} has excess dependencies on\n" ++ + flatMap(\ v::FlowVertex -> s"\t${v.vertexName}\n", tileSigDepsExceedsDispatchHostSigDeps) ++ + s"In host-language implementations of dispatch ${sig.fullName}, it depends ${depVertexListStr(dispatchHostSigDeps.fromJust)}")] + | _ -> [] + end; +} + +aspect production inhBaseColAttributeDef +top::ProductionStmt ::= @dl::DefLHS @attr::QNameAttrOccur e::Expr +{ + -- Make sure we aren't introducing any hidden transitive dependencies. + + -- oh no again! + local myGraphs::EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).productionFlowGraphs; + + local vertexHasHideableEq :: (Boolean ::= VertexType String) = + possibleDecSiteHasInhEq(top.frame.fullName, _, _, myGraphs, top.flowEnv, top.env); + + local refDecSiteInhDepsLhsInh :: Maybe> = + case filter(vertexHasHideableEq(_, attr.attrDcl.fullName), dl.defLHSDecSites) of + | [] -> nothing() + | vs -> just(onlyLhsInh(expandGraph( + dl.defLHSVertex.outerEqDeps ++ + flatMap(\ v::VertexType -> v.inhDeps(attr.attrDcl.fullName), vs), + top.frame.flowGraph))) + end; + + local transBaseRefDecSiteInhDepsLhsInh :: Maybe> = + case dl.defLHSVertex of + | transAttrVertexType(v, transAttr) -> + case filter(vertexHasHideableEq(_, dl.inhAttrName), dl.defLHSTransBaseDecSites) of + | [] -> nothing() + | vs -> just(onlyLhsInh(expandGraph( + v.outerEqDeps ++ + flatMap(\ v::VertexType -> v.inhDeps(dl.inhAttrName), vs), + top.frame.flowGraph))) + end + | _ -> nothing() + end; + + -- problem = lhsinh deps - inh deps on dec site + local lhsInhExceedsRefDecSiteDeps :: [String] = + case refDecSiteInhDepsLhsInh of + | just(deps) -> set:toList(set:difference(lhsInhDeps, deps)) + | _ -> [] + end; + + local lhsInhExceedsTransBaseRefDecSiteDeps :: [String] = + case transBaseRefDecSiteInhDepsLhsInh of + | just(deps) -> set:toList(set:difference(lhsInhDeps, deps)) + | _ -> [] + end; + + -- Extension productions that implement a dispatch signature + + local ns :: NamedSignature = -- top.frame.signature might have aspect sig names that don't match the flow env + case getValueDcl(top.frame.fullName, top.env) of + | dcl :: _ -> dcl.namedSignature + | _ -> error("didn't find a decl for prod " ++ top.frame.fullName) + end; + local implementedSig :: Maybe = + case getValueDcl(top.frame.fullName, top.env) of + | dcl :: _ -> dcl.implementedSignature + | _ -> nothing() + end; + local dispatchHostSigDeps:: Maybe> = do { + dispatchSig :: NamedSignature <- implementedSig; + guard(!isExportedBy( + top.frame.sourceGrammar, + [substring(0, lastIndexOf(":", dispatchSig.fullName), dispatchSig.fullName)], + top.compiledGrammars)); + sigName <- + case dl.defLHSVertex of + | rhsVertexType(sigName) -> just(sigName) + | transAttrVertexType(rhsVertexType(sigName), _) -> just(sigName) + | _ -> nothing() + end; + let sigPos = positionOf(sigName, ns.inputNames); + when_(sigPos < 0, error("sigName lookup failed")); + guard(sigPos < length(dispatchSig.inputElements)); + let dispatchVertex = rhsInhVertex( + head(drop(sigPos, dispatchSig.inputElements)).elementName, + dl.inhAttrName); + return set:fromList(flatMap(fromDispatchSigVertex(dispatchSig, ns, _), + rhsEqVertex(sigName) :: -- TODO: Workaround: the rhs inh vertex should depend on the rhs eq vertex already! + set:toList(findProductionGraph(dispatchSig.fullName, myGraphs).tileEdgeMap(dispatchVertex)))); + }; + + local sigNames::[String] = + take(length(fromMaybe(ns, implementedSig).inputNames), ns.inputNames); + local tileSigDeps::set:Set = + expandTileGraphSigDeps(e.flowDeps, sigNames, top.frame.flowGraph); + + -- problem = lhsinh deps - inh deps on host implementation prods + local tileSigDepsExceedsDispatchHostSigDeps :: [FlowVertex] = + case dispatchHostSigDeps of + | just(deps) -> set:toList(set:difference(tileSigDeps, deps)) + | _ -> [] + end; + + top.errors <- + if top.config.warnMissingInh + && !null(lhsInhExceedsRefDecSiteDeps) + then + [mwdaWrnFromOrigin(top, + s"Inherited override equation for ${attr.attrDcl.fullName} on ${dl.defLHSVertex.vertexPP} may exceed a flow type " ++ + s"with hidden transitive dependencies on ${implode(", ", lhsInhExceedsRefDecSiteDeps)}; " ++ + s"on some reference to this tree, this attribute may be expected to depend ${depListStr(refDecSiteInhDepsLhsInh.fromJust)}" ++ + s" (from ${implode(", ", map((.vertexPP), lookupRefPossibleDecSites(top.frame.fullName, dl.defLHSVertex, top.flowEnv)))})")] + else []; + top.errors <- + case dl.defLHSVertex of + | transAttrVertexType(v, transAttr) + when top.config.warnMissingInh + && !null(lhsInhExceedsTransBaseRefDecSiteDeps) -> + [mwdaWrnFromOrigin(top, + s"Inherited override equation for ${transAttr}.${attr.attrDcl.fullName} on ${v.vertexPP} may exceed a flow type " ++ + s"with hidden transitive dependencies on ${implode(", ", lhsInhExceedsTransBaseRefDecSiteDeps)}; " ++ + s"on some reference to this tree, this attribute may be expected to depend ${depListStr(transBaseRefDecSiteInhDepsLhsInh.fromJust)}" ++ + s" (from ${implode(", ", map((.vertexPP), lookupRefPossibleDecSites(top.frame.fullName, v, top.flowEnv)))})")] + | _ -> [] + end; + top.errors <- + case implementedSig of + | just(sig) + when top.config.warnMissingInh + && !null(tileSigDepsExceedsDispatchHostSigDeps) -> + [mwdaWrnFromOrigin(top, + s"Inherited override equation for ${attr.attrDcl.fullName} on ${dl.defLHSVertex.vertexPP} has excess dependencies on\n" ++ + flatMap(\ v::FlowVertex -> s"\t${v.vertexName}\n", tileSigDepsExceedsDispatchHostSigDeps) ++ + s"In host-language implementations of dispatch ${sig.fullName}, it depends ${depVertexListStr(dispatchHostSigDeps.fromJust)}")] + | _ -> [] + end; +} +aspect production inhBaseColAttributeDef +top::ProductionStmt ::= @dl::DefLHS @attr::QNameAttrOccur e::Expr +{ + -- Make sure we aren't introducing any hidden transitive dependencies. + + -- oh no again! + local myGraphs::EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).productionFlowGraphs; + + local vertexHasHideableEq :: (Boolean ::= VertexType String) = + possibleDecSiteHasInhEq(top.frame.fullName, _, _, myGraphs, top.flowEnv, top.env); + + local refDecSiteInhDepsLhsInh :: Maybe> = + case filter(vertexHasHideableEq(_, attr.attrDcl.fullName), dl.defLHSDecSites) of + | [] -> nothing() + | vs -> just(onlyLhsInh(expandGraph( + dl.defLHSVertex.outerEqDeps ++ + flatMap(\ v::VertexType -> v.inhDeps(attr.attrDcl.fullName), vs), + top.frame.flowGraph))) + end; + + local transBaseRefDecSiteInhDepsLhsInh :: Maybe> = + case dl.defLHSVertex of + | transAttrVertexType(v, transAttr) -> + case filter(vertexHasHideableEq(_, dl.inhAttrName), dl.defLHSTransBaseDecSites) of + | [] -> nothing() + | vs -> just(onlyLhsInh(expandGraph( + v.outerEqDeps ++ + flatMap(\ v::VertexType -> v.inhDeps(dl.inhAttrName), vs), + top.frame.flowGraph))) + end + | _ -> nothing() + end; + + -- problem = lhsinh deps - inh deps on dec site + local lhsInhExceedsRefDecSiteDeps :: [String] = + case refDecSiteInhDepsLhsInh of + | just(deps) -> set:toList(set:difference(lhsInhDeps, deps)) + | _ -> [] + end; + + local lhsInhExceedsTransBaseRefDecSiteDeps :: [String] = + case transBaseRefDecSiteInhDepsLhsInh of + | just(deps) -> set:toList(set:difference(lhsInhDeps, deps)) + | _ -> [] + end; + + -- Extension productions that implement a dispatch signature + + local ns :: NamedSignature = -- top.frame.signature might have aspect sig names that don't match the flow env + case getValueDcl(top.frame.fullName, top.env) of + | dcl :: _ -> dcl.namedSignature + | _ -> error("didn't find a decl for prod " ++ top.frame.fullName) + end; + local implementedSig :: Maybe = + case getValueDcl(top.frame.fullName, top.env) of + | dcl :: _ -> dcl.implementedSignature + | _ -> nothing() + end; + local dispatchHostSigDeps:: Maybe> = do { + dispatchSig :: NamedSignature <- implementedSig; + guard(!isExportedBy( + top.frame.sourceGrammar, + [substring(0, lastIndexOf(":", dispatchSig.fullName), dispatchSig.fullName)], + top.compiledGrammars)); + sigName <- + case dl.defLHSVertex of + | rhsVertexType(sigName) -> just(sigName) + | transAttrVertexType(rhsVertexType(sigName), _) -> just(sigName) + | _ -> nothing() + end; + let sigPos = positionOf(sigName, ns.inputNames); + when_(sigPos < 0, error("sigName lookup failed")); + guard(sigPos < length(dispatchSig.inputElements)); + let dispatchVertex = rhsInhVertex( + head(drop(sigPos, dispatchSig.inputElements)).elementName, + dl.inhAttrName); + return set:fromList(flatMap(fromDispatchSigVertex(dispatchSig, ns, _), + rhsEqVertex(sigName) :: -- TODO: Workaround: the rhs inh vertex should depend on the rhs eq vertex already! + set:toList(findProductionGraph(dispatchSig.fullName, myGraphs).tileEdgeMap(dispatchVertex)))); + }; + + local sigNames::[String] = + take(length(fromMaybe(ns, implementedSig).inputNames), ns.inputNames); + local tileSigDeps::set:Set = + expandTileGraphSigDeps(e.flowDeps, sigNames, top.frame.flowGraph); + + -- problem = lhsinh deps - inh deps on host implementation prods + local tileSigDepsExceedsDispatchHostSigDeps :: [FlowVertex] = + case dispatchHostSigDeps of + | just(deps) -> set:toList(set:difference(tileSigDeps, deps)) + | _ -> [] + end; + + top.errors <- + if top.config.warnMissingInh + && !null(lhsInhExceedsRefDecSiteDeps) + then + [mwdaWrnFromOrigin(top, + s"Inherited contribution equation for ${attr.attrDcl.fullName} on ${dl.defLHSVertex.vertexPP} may exceed a flow type " ++ + s"with hidden transitive dependencies on ${implode(", ", lhsInhExceedsRefDecSiteDeps)}; " ++ + s"on some reference to this tree, this attribute may be expected to depend ${depListStr(refDecSiteInhDepsLhsInh.fromJust)}" ++ + s" (from ${implode(", ", map((.vertexPP), lookupRefPossibleDecSites(top.frame.fullName, dl.defLHSVertex, top.flowEnv)))})")] + else []; + top.errors <- + case dl.defLHSVertex of + | transAttrVertexType(v, transAttr) + when top.config.warnMissingInh + && !null(lhsInhExceedsTransBaseRefDecSiteDeps) -> + [mwdaWrnFromOrigin(top, + s"Inherited contribution equation for ${transAttr}.${attr.attrDcl.fullName} on ${v.vertexPP} may exceed a flow type " ++ + s"with hidden transitive dependencies on ${implode(", ", lhsInhExceedsTransBaseRefDecSiteDeps)}; " ++ + s"on some reference to this tree, this attribute may be expected to depend ${depListStr(transBaseRefDecSiteInhDepsLhsInh.fromJust)}" ++ + s" (from ${implode(", ", map((.vertexPP), lookupRefPossibleDecSites(top.frame.fullName, v, top.flowEnv)))})")] + | _ -> [] + end; + top.errors <- + case implementedSig of + | just(sig) + when top.config.warnMissingInh + && !null(tileSigDepsExceedsDispatchHostSigDeps) -> + [mwdaWrnFromOrigin(top, + s"Inherited contribution equation for ${attr.attrDcl.fullName} on ${dl.defLHSVertex.vertexPP} has excess dependencies on\n" ++ + flatMap(\ v::FlowVertex -> s"\t${v.vertexName}\n", tileSigDepsExceedsDispatchHostSigDeps) ++ + s"In host-language implementations of dispatch ${sig.fullName}, it depends ${depVertexListStr(dispatchHostSigDeps.fromJust)}")] + | _ -> [] + end; +} + + +fun depListStr String ::= deps::set:Set = + case set:toList(deps) of + | [] -> "on no left-side inherited attributes" + | deps -> "only on " ++ implode(", ", deps) + end; + +fun depVertexListStr String ::= deps::set:Set = + case set:toList(deps) of + | [] -> "on nothing" + | deps -> "only on\n" ++ flatMap(\ v::FlowVertex -> s"\t${v.vertexName}\n", deps) + end; + +fun vertexHasPossibleInhEq Boolean ::= v::VertexType env::Env = + case v of + | subtermVertexType(_, prodName, sigName) -> + case getTypeDcl(prodName, env), getValueDcl(prodName, env) of + | dcl :: _, _ -> !lookupSignatureInputElem(sigName, dcl.dispatchSignature).elementShared + | _, dcl :: _ -> !lookupSignatureInputElem(sigName, dcl.namedSignature).elementShared + | _, _ -> false + end + | _ -> true + end; + +fun fromDispatchSigVertex +[FlowVertex] ::= dispatchSig::NamedSignature prodSig::NamedSignature v::FlowVertex = + case v of + | lhsSynVertex(_) -> [v] + | lhsInhVertex(_) -> [v] + | rhsEqVertex(sn) -> + [rhsEqVertex(head(drop(positionOf(sn, dispatchSig.inputNames), prodSig.inputNames)))] + | rhsSynVertex(sn, a) -> + [rhsSynVertex(head(drop(positionOf(sn, dispatchSig.inputNames), prodSig.inputNames)), a)] + | rhsInhVertex(sn, a) -> + [rhsInhVertex(head(drop(positionOf(sn, dispatchSig.inputNames), prodSig.inputNames)), a)] + | _ -> [] + end; + diff --git a/grammars/silver/compiler/analysis/warnings/flow/Inh.sv b/grammars/silver/compiler/analysis/warnings/flow/Inh.sv index 02036e516..3d303ba96 100644 --- a/grammars/silver/compiler/analysis/warnings/flow/Inh.sv +++ b/grammars/silver/compiler/analysis/warnings/flow/Inh.sv @@ -46,114 +46,6 @@ Either ::= args::[String] -------------------------------------------------------------------------------- -{-- - - Used as a stop-gap measure to ensure equations exist. - - Given a needed equation (represented by FlowVertex 'v'), - - ensure such an equation exists, accounting for: - - 1. Defaults - - 2. Forwards - - 3. Reference accesses - - - - This gives rise to 'missing transitive dependency' errors. - - The reason this exists is to handle 'taking a reference' - - actions needing to ensure equations were actually provided for - - things we reference. - - - - @param v A value we need an equation for. - - @param anonResolve A list of anonymous decoration sites - - @param config Command-line arguments, that affect error reporting - - @param prodGraphs The final production flow graphs. - - @param prodName The full name of the production we're in - - @param prodNt The nonterminal this production belongs to. (For functions, a dummy value is ok) - - @param flowEnv The local flow environment - - @param realEnv The local real environment - - @returns Errors for missing equations - -} -fun checkEqDeps -[Message] ::= - v::FlowVertex anonResolve::[(String, Location)] - config::Decorated CmdArgs prodName::String - prodGraphs::EnvTree flowEnv::FlowEnv realEnv::Env = - -- We're concerned with missing inherited equations on RHS, LOCAL, and ANON. (Implicitly, FORWARD.) - case v of - -- A dependency on an LHS.INH is a flow issue: these equations do not exist - -- locally, so we cannot check them. - | lhsInhVertex(_) -> [] - -- A dependency on an LHS.SYN can be checked locally, but we do not do so here. - -- All productions must have all SYN equations, so those errors are raised elsewhere. - | lhsSynVertex(attrName) -> [] - -- A dependency on an RHS.ATTR. SYN are always present, so we only care about INH here. - | rhsInhVertex(sigName, attrName) -> - checkInhEq(prodName, rhsVertexType(sigName), attrName, config, prodGraphs, flowEnv, realEnv) - | rhsSynVertex(sigName, attrName) -> [] - -- A dependency on a LOCAL. Technically, local equations may not exist! - -- But let's just assume they do, since `local name :: type = expr;` is the preferred syntax. - | localEqVertex(fName) -> [] - -- A dependency on a LOCAL.ATTR. SYN always exist again, so we only care about INH here. - | localInhVertex(fName, attrName) -> - checkInhEq(prodName, localVertexType(fName), attrName, config, prodGraphs, flowEnv, realEnv) - | localSynVertex(fName, attrName) -> [] - -- A dependency on a ANON. This do always exist (`decorate expr with..` always has expr.) - | anonEqVertex(fName) -> [] - -- A dependency on ANON.ATTR. Again, SYN are safe. We need to check only for INH. - -- If the equation is missing, then we again filter down to just those equations - -- missing within THIS overall equation. - -- i.e. `top.syn1 = ... missing ...; top.syn2 = top.syn1;` should only raise - -- the missing in the first equation. - | anonInhVertex(fName, attrName) -> - if !null(lookupLocalInh(prodName, fName, attrName, flowEnv)) - then [] - else let - anonl :: Maybe = lookup(fName, anonResolve) - in if anonl.isJust - then [mwdaWrn(config, anonl.fromJust, "Decoration requires inherited attribute for " ++ attrName ++ ".")] - else [] -- If it's not in the list, then it's a transitive dep from a DIFFERENT equation (and thus reported there) - end - | anonSynVertex(fName, attrName) -> [] - -- A dependency on a projected equation in another production. - | subtermInhVertex(parent, termProdName, sigName, attrName) -> - checkInhEq(prodName, subtermVertexType(parent, termProdName, sigName), attrName, config, prodGraphs, flowEnv, realEnv) - | subtermSynVertex(parent, termProdName, sigName, attrName) -> [] - end; - -fun checkInhEq -[Message] ::= - prodName::String vt::VertexType attrName::String config::Decorated CmdArgs - prodGraphs::EnvTree flowEnv::FlowEnv realEnv::Env = - case resolveInhEq(prodName, vt, attrName, prodGraphs, flowEnv, realEnv) of - | alwaysDec() -> [] - | missing -> [mwdaWrnAmbientOrigin(config, s"Equation requires inherited attribute ${attrName} be supplied to ${prettyDecSites(0, missing)}")] - end; - -function checkAllEqDeps -[Message] ::= - vs::[FlowVertex] flowDefs::[FlowDef] - config::Decorated CmdArgs prodName::String prodGraphs::EnvTree flowEnv::FlowEnv realEnv::Env -{ - -- If a shared tree is missing an inherited equation, then the equation is also - -- missing for the sharing decoration site vertex on which it depends. - -- We want to suppress reporting the error again on the decoration site vertex, - -- since that error wouldn't list the original vertex as a place where the - -- attribute could be supplied. - local alreadyReported::[FlowVertex] = do { - v :: FlowVertex <- vs; - refInh::(VertexType, String) <- - case v of - | rhsInhVertex(sigName, attrName) -> [(rhsVertexType(sigName), attrName)] - | localInhVertex(fName, attrName) -> [(localVertexType(fName), attrName)] - | anonInhVertex(fName, attrName) -> [(anonVertexType(fName), attrName)] - | _ -> [] - end; - decSite::VertexType <- lookupRefDecSite(prodName, refInh.1, flowEnv); - guard(!decSiteHasInhEq(prodName, refInh.1, refInh.2, prodGraphs, flowEnv, realEnv)); - expandGraph([decSite.inhVertex(refInh.2)], findProductionGraph(prodName, prodGraphs)); - }; - local anonResolve::[(String, Location)] = collectAnonOrigin(flowDefs); - return flatMap( - checkEqDeps(_, anonResolve, config, prodName, prodGraphs, flowEnv, realEnv), - removeAll(alreadyReported, vs)); -} - {-- - Look up flow types, either from the flow environment (for a nonterminal) or the occurs-on contexts (for a type var). - @param syn A synthesized attribute's full name @@ -182,54 +74,12 @@ function inhDepsForSynOnType -------------------------------------------------------------------------------- -aspect production globalValueDclConcrete -top::AGDcl ::= 'global' id::Name '::' cl::ConstraintList '=>' t::TypeExpr '=' e::Expr ';' -{ - -- oh no again! - local myGraphs::EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).productionFlowGraphs; - - local transitiveDeps :: [FlowVertex] = expandGraph(e.flowDeps, e.frame.flowGraph); - - top.errors <- - if top.config.warnMissingInh - then checkAllEqDeps(transitiveDeps, e.flowDefs, top.config, fName, myGraphs, top.flowEnv, top.env) - else []; -} - -aspect production defaultConstraintClassBodyItem -top::ClassBodyItem ::= id::Name '::' cl::ConstraintList '=>' ty::TypeExpr '=' e::Expr ';' -{ - -- oh no again! - local myGraphs::EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).productionFlowGraphs; - - local transitiveDeps :: [FlowVertex] = expandGraph(e.flowDeps, e.frame.flowGraph); - - top.errors <- - if top.config.warnMissingInh - then checkAllEqDeps(transitiveDeps, e.flowDefs, top.config, fName, myGraphs, top.flowEnv, top.env) - else []; -} - -aspect production instanceBodyItem -top::InstanceBodyItem ::= id::QName '=' e::Expr ';' -{ - -- oh no again! - local myGraphs::EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).productionFlowGraphs; - - local transitiveDeps :: [FlowVertex] = expandGraph(e.flowDeps, e.frame.flowGraph); - - top.errors <- - if top.config.warnMissingInh - then checkAllEqDeps(transitiveDeps, e.flowDefs, top.config, id.lookupValue.fullName, myGraphs, top.flowEnv, top.env) - else []; -} - aspect production synthesizedAttributeDef top::ProductionStmt ::= @dl::DefLHS @attr::QNameAttrOccur e::Expr { -- oh no again! local myFlow :: EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).grammarFlowTypes; - local myGraphs::EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).productionFlowGraphs; + production myGraphs::EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).productionFlowGraphs; local transitiveDeps :: [FlowVertex] = expandGraph(e.flowDeps, top.frame.flowGraph); @@ -238,10 +88,8 @@ top::ProductionStmt ::= @dl::DefLHS @attr::QNameAttrOccur e::Expr local lhsInhExceedsFlowType :: [String] = set:toList(set:difference(lhsInhDeps, inhDepsForSyn(attr.attrDcl.fullName, top.frame.lhsNtName, myFlow))); top.errors <- - if dl.found && attr.found && top.config.warnMissingInh - then checkAllEqDeps(transitiveDeps, e.flowDefs, top.config, top.frame.fullName, myGraphs, top.flowEnv, top.env) ++ - if null(lhsInhExceedsFlowType) then [] - else [mwdaWrnFromOrigin(top, "Synthesized equation " ++ attr.name ++ " exceeds flow type with dependencies on " ++ implode(", ", lhsInhExceedsFlowType))] + if dl.found && attr.found && top.config.warnMissingInh && !null(lhsInhExceedsFlowType) + then [mwdaWrnFromOrigin(top, "Synthesized equation " ++ attr.name ++ " exceeds flow type with dependencies on " ++ implode(", ", lhsInhExceedsFlowType))] else []; } @@ -250,12 +98,11 @@ top::ProductionStmt ::= @dl::DefLHS @attr::QNameAttrOccur e::Expr { -- oh no again! local myFlow :: EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).grammarFlowTypes; - local myGraphs::EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).productionFlowGraphs; local transitiveDeps :: [FlowVertex] = expandGraph(e.flowDeps, top.frame.flowGraph); - local lhsInhDeps :: set:Set = onlyLhsInh(transitiveDeps); + production lhsInhDeps :: set:Set = onlyLhsInh(transitiveDeps); -- problem = lhsinh deps - fwd flow type - this inh attribute local lhsInhExceedsForwardFlowType :: [String] = @@ -266,156 +113,19 @@ top::ProductionStmt ::= @dl::DefLHS @attr::QNameAttrOccur e::Expr lhsInhDeps, inhDepsForSyn("forward", top.frame.lhsNtName, myFlow)))); - -- Make sure we aren't introducing any hidden transitive dependencies. - - local vertexHasHideableEq :: (Boolean ::= VertexType String) = - possibleDecSiteHasInhEq(top.frame.fullName, _, _, myGraphs, top.flowEnv, top.env); - - local refDecSiteInhDepsLhsInh :: Maybe> = - case filter( - vertexHasHideableEq(_, attr.attrDcl.fullName), - lookupRefPossibleDecSites(top.frame.fullName, dl.defLHSVertex, top.flowEnv)) of - | [] -> nothing() - | vs -> just(onlyLhsInh(expandGraph( - dl.defLHSVertex.eqVertex ++ - map(\ v::VertexType -> v.inhVertex(attr.attrDcl.fullName), vs), - top.frame.flowGraph))) - end; - - local transBaseRefDecSiteInhDepsLhsInh :: Maybe> = - case dl.defLHSVertex of - | transAttrVertexType(v, transAttr) -> - case filter( - vertexHasHideableEq(_, dl.inhAttrName), - lookupRefPossibleDecSites(top.frame.fullName, v, top.flowEnv)) of - | [] -> nothing() - | vs -> just(onlyLhsInh(expandGraph( - v.eqVertex ++ - map(\ v::VertexType -> v.inhVertex(dl.inhAttrName), vs), - top.frame.flowGraph))) - end - | _ -> nothing() - end; - - -- problem = lhsinh deps - inh deps on dec site - local lhsInhExceedsRefDecSiteDeps :: [String] = - case refDecSiteInhDepsLhsInh of - | just(deps) -> set:toList(set:difference(lhsInhDeps, deps)) - | _ -> [] - end; - - local lhsInhExceedsTransBaseRefDecSiteDeps :: [String] = - case transBaseRefDecSiteInhDepsLhsInh of - | just(deps) -> set:toList(set:difference(lhsInhDeps, deps)) - | _ -> [] - end; - - -- Extension productions that implement a dispatch signature - - local ns :: NamedSignature = -- top.frame.signature might have aspect sig names that don't match the flow env - case getValueDcl(top.frame.fullName, top.env) of - | dcl :: _ -> dcl.namedSignature - | _ -> error("didn't find a decl for prod " ++ top.frame.fullName) - end; - local implementedSig :: Maybe = - case getValueDcl(top.frame.fullName, top.env) of - | dcl :: _ -> dcl.implementedSignature - | _ -> nothing() - end; - local dispatchHostSigInhDepsLhsInh :: Maybe> = - case implementedSig of - | just(dispatchSig) -> - case dl.defLHSVertex of - | rhsVertexType(sigName) - when lookupSignatureInputElem(sigName, ns).elementShared -> - just(onlyLhsInh(expandGraph( - [rhsInhVertex( - head(drop(positionOf(sigName, ns.inputNames), dispatchSig.inputNames)), - attr.attrDcl.fullName)], - findProductionGraph(dispatchSig.fullName, myGraphs)))) - | transAttrVertexType(rhsVertexType(sigName), transAttr) - when lookupSignatureInputElem(sigName, ns).elementShared -> - just(onlyLhsInh(expandGraph( - [rhsInhVertex( - head(drop(positionOf(sigName, ns.inputNames), dispatchSig.inputNames)), - transAttr ++ "." ++ attr.attrDcl.fullName)], - findProductionGraph(dispatchSig.fullName, myGraphs)))) - | _ -> nothing() - end - | _ -> nothing() - end; - - -- problem = lhsinh deps - inh deps on host implementation prods - local lhsInhExceedsDispatchHostSigInhDeps :: [String] = - case dispatchHostSigInhDepsLhsInh of - | just(deps) -> set:toList(set:difference(lhsInhDeps, deps)) - | _ -> [] - end; - - top.errors <- - if top.config.warnMissingInh - then checkAllEqDeps(transitiveDeps, e.flowDefs, top.config, top.frame.fullName, myGraphs, top.flowEnv, top.env) - else []; top.errors <- if top.config.warnMissingInh && dl.name == "forward" && !null(lhsInhExceedsForwardFlowType) then [mwdaWrnFromOrigin(top, "Forward inherited equation for " ++ dl.inhAttrName ++ " exceeds flow type with dependencies on " ++ implode(", ", lhsInhExceedsForwardFlowType))] else []; - top.errors <- - if top.config.warnMissingInh && !null(lhsInhExceedsRefDecSiteDeps) - then - [mwdaWrnFromOrigin(top, - s"Inherited override equation for ${attr.attrDcl.fullName} on ${dl.defLHSVertex.vertexPP} may exceed a flow type " ++ - s"with hidden transitive dependencies on ${implode(", ", lhsInhExceedsRefDecSiteDeps)}; " ++ - s"on some reference to this tree, this attribute may be expected to depend ${depListStr(refDecSiteInhDepsLhsInh.fromJust)}" ++ - s" (from ${implode(", ", map((.vertexPP), lookupRefPossibleDecSites(top.frame.fullName, dl.defLHSVertex, top.flowEnv)))})")] - else []; - top.errors <- - case dl.defLHSVertex of - | transAttrVertexType(v, transAttr) - when top.config.warnMissingInh && !null(lhsInhExceedsTransBaseRefDecSiteDeps) -> - [mwdaWrnFromOrigin(top, - s"Inherited override equation for ${transAttr}.${attr.attrDcl.fullName} on ${v.vertexPP} may exceed a flow type " ++ - s"with hidden transitive dependencies on ${implode(", ", lhsInhExceedsTransBaseRefDecSiteDeps)}; " ++ - s"on some reference to this tree, this attribute may be expected to depend ${depListStr(transBaseRefDecSiteInhDepsLhsInh.fromJust)}" ++ - s" (from ${implode(", ", map((.vertexPP), lookupRefPossibleDecSites(top.frame.fullName, v, top.flowEnv)))})")] - | _ -> [] - end; - top.errors <- - case implementedSig of - | just(sig) when top.config.warnMissingInh && !null(lhsInhExceedsDispatchHostSigInhDeps) -> - [mwdaWrnFromOrigin(top, - s"Inherited override equation for ${attr.attrDcl.fullName} on ${dl.defLHSVertex.vertexPP} may exceed a flow type " ++ - s"with hidden transitive dependencies on ${implode(", ", lhsInhExceedsDispatchHostSigInhDeps)}; " ++ - s"in a production that dispatched to this one, this attribute may be expected to depend ${depListStr(dispatchHostSigInhDepsLhsInh.fromJust)}" ++ - s" (from ${sig.fullName})")] - | _ -> [] - end; } -fun depListStr String ::= deps::set:Set = - case set:toList(deps) of - | [] -> "on no left-side inherited attributes" - | deps -> "only on " ++ implode(", ", deps) - end; - -fun vertexHasPossibleInhEq Boolean ::= v::VertexType env::Env = - case v of - | subtermVertexType(_, prodName, sigName) -> - case getTypeDcl(prodName, env), getValueDcl(prodName, env) of - | dcl :: _, _ -> !lookupSignatureInputElem(sigName, dcl.dispatchSignature).elementShared - | _, dcl :: _ -> !lookupSignatureInputElem(sigName, dcl.namedSignature).elementShared - | _, _ -> false - end - | _ -> true - end; - ----- WARNING TODO BEGIN MASSIVE COPY & PASTE SESSION aspect production synBaseColAttributeDef top::ProductionStmt ::= @dl::DefLHS @attr::QNameAttrOccur e::Expr { -- oh no again! local myFlow :: EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).grammarFlowTypes; - local myGraphs::EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).productionFlowGraphs; + production myGraphs::EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).productionFlowGraphs; local transitiveDeps :: [FlowVertex] = expandGraph(e.flowDeps, top.frame.flowGraph); @@ -424,10 +134,8 @@ top::ProductionStmt ::= @dl::DefLHS @attr::QNameAttrOccur e::Expr local lhsInhExceedsFlowType :: [String] = set:toList(set:difference(lhsInhDeps, inhDepsForSyn(attr.attrDcl.fullName, top.frame.lhsNtName, myFlow))); top.errors <- - if dl.found && attr.found && top.config.warnMissingInh - then checkAllEqDeps(transitiveDeps, e.flowDefs, top.config, top.frame.fullName, myGraphs, top.flowEnv, top.env) ++ - if null(lhsInhExceedsFlowType) then [] - else [mwdaWrnFromOrigin(top, "Synthesized equation " ++ attr.name ++ " exceeds flow type with dependencies on " ++ implode(", ", lhsInhExceedsFlowType))] + if dl.found && attr.found && top.config.warnMissingInh && !null(lhsInhExceedsFlowType) + then [mwdaWrnFromOrigin(top, "Synthesized equation " ++ attr.name ++ " exceeds flow type with dependencies on " ++ implode(", ", lhsInhExceedsFlowType))] else []; } aspect production synAppendColAttributeDef @@ -435,7 +143,7 @@ top::ProductionStmt ::= @dl::DefLHS @attr::QNameAttrOccur e::Expr { -- oh no again! local myFlow :: EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).grammarFlowTypes; - local myGraphs::EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).productionFlowGraphs; + production myGraphs::EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).productionFlowGraphs; local transitiveDeps :: [FlowVertex] = expandGraph(e.flowDeps, top.frame.flowGraph); @@ -444,10 +152,8 @@ top::ProductionStmt ::= @dl::DefLHS @attr::QNameAttrOccur e::Expr local lhsInhExceedsFlowType :: [String] = set:toList(set:difference(lhsInhDeps, inhDepsForSyn(attr.attrDcl.fullName, top.frame.lhsNtName, myFlow))); top.errors <- - if dl.found && attr.found && top.config.warnMissingInh - then checkAllEqDeps(transitiveDeps, e.flowDefs, top.config, top.frame.fullName, myGraphs, top.flowEnv, top.env) ++ - if null(lhsInhExceedsFlowType) then [] - else [mwdaWrnFromOrigin(top, "Synthesized equation " ++ attr.name ++ " exceeds flow type with dependencies on " ++ implode(", ", lhsInhExceedsFlowType))] + if dl.found && attr.found && top.config.warnMissingInh && !null(lhsInhExceedsFlowType) + then [mwdaWrnFromOrigin(top, "Synthesized equation " ++ attr.name ++ " exceeds flow type with dependencies on " ++ implode(", ", lhsInhExceedsFlowType))] else []; } aspect production inhBaseColAttributeDef @@ -455,12 +161,11 @@ top::ProductionStmt ::= @dl::DefLHS @attr::QNameAttrOccur e::Expr { -- oh no again! local myFlow :: EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).grammarFlowTypes; - local myGraphs::EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).productionFlowGraphs; local transitiveDeps :: [FlowVertex] = expandGraph(e.flowDeps, top.frame.flowGraph); - local lhsInhDeps :: set:Set = onlyLhsInh(transitiveDeps); + production lhsInhDeps :: set:Set = onlyLhsInh(transitiveDeps); -- problem = lhsinh deps - fwd flow type - this inh attribute local lhsInhExceedsForwardFlowType :: [String] = set:toList( @@ -471,25 +176,20 @@ top::ProductionStmt ::= @dl::DefLHS @attr::QNameAttrOccur e::Expr inhDepsForSyn("forward", top.frame.lhsNtName, myFlow)))); top.errors <- - if top.config.warnMissingInh - then checkAllEqDeps(transitiveDeps, e.flowDefs, top.config, top.frame.fullName, myGraphs, top.flowEnv, top.env) ++ - if dl.name != "forward" || null(lhsInhExceedsForwardFlowType) then [] - else [mwdaWrnFromOrigin(top, "Forward inherited equation for " ++ dl.inhAttrName ++ " exceeds flow type with dependencies on " ++ implode(", ", lhsInhExceedsForwardFlowType))] + if top.config.warnMissingInh && dl.name == "forward" && !null(lhsInhExceedsForwardFlowType) + then [mwdaWrnFromOrigin(top, "Forward inherited equation for " ++ dl.inhAttrName ++ " exceeds flow type with dependencies on " ++ implode(", ", lhsInhExceedsForwardFlowType))] else []; - - -- TOOD: Hidden transitive deps check? } aspect production inhAppendColAttributeDef top::ProductionStmt ::= @dl::DefLHS @attr::QNameAttrOccur e::Expr { -- oh no again! local myFlow :: EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).grammarFlowTypes; - local myGraphs::EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).productionFlowGraphs; local transitiveDeps :: [FlowVertex] = expandGraph(e.flowDeps, top.frame.flowGraph); - local lhsInhDeps :: set:Set = onlyLhsInh(transitiveDeps); + production lhsInhDeps :: set:Set = onlyLhsInh(transitiveDeps); -- problem = lhsinh deps - fwd flow type - this inh attribute local lhsInhExceedsForwardFlowType :: [String] = set:toList( @@ -500,13 +200,9 @@ top::ProductionStmt ::= @dl::DefLHS @attr::QNameAttrOccur e::Expr inhDepsForSyn("forward", top.frame.lhsNtName, myFlow)))); top.errors <- - if top.config.warnMissingInh - then checkAllEqDeps(transitiveDeps, e.flowDefs, top.config, top.frame.fullName, myGraphs, top.flowEnv, top.env) ++ - if dl.name != "forward" || null(lhsInhExceedsForwardFlowType) then [] - else [mwdaWrnFromOrigin(top, "Forward inherited equation exceeds for " ++ dl.inhAttrName ++ " flow type with dependencies on " ++ implode(", ", lhsInhExceedsForwardFlowType))] + if top.config.warnMissingInh && dl.name == "forward" && !null(lhsInhExceedsForwardFlowType) + then [mwdaWrnFromOrigin(top, "Forward inherited equation for " ++ dl.inhAttrName ++ " exceeds flow type with dependencies on " ++ implode(", ", lhsInhExceedsForwardFlowType))] else []; - - -- TOOD: Hidden transitive deps check? } ------ END AWFUL COPY & PASTE SESSION @@ -515,7 +211,6 @@ top::ProductionStmt ::= 'forwards' 'to' e::Expr ';' { -- oh no again! local myFlow :: EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).grammarFlowTypes; - local myGraphs::EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).productionFlowGraphs; local transitiveDeps :: [FlowVertex] = expandGraph(e.flowDeps, top.frame.flowGraph); @@ -524,10 +219,8 @@ top::ProductionStmt ::= 'forwards' 'to' e::Expr ';' local lhsInhExceedsFlowType :: [String] = set:toList(set:difference(lhsInhDeps, inhDepsForSyn("forward", top.frame.lhsNtName, myFlow))); top.errors <- - if top.config.warnMissingInh - then checkAllEqDeps(transitiveDeps, e.flowDefs, top.config, top.frame.fullName, myGraphs, top.flowEnv, top.env) ++ - if null(lhsInhExceedsFlowType) then [] - else [mwdaWrnFromOrigin(top, "Forward equation exceeds flow type with dependencies on " ++ implode(", ", lhsInhExceedsFlowType))] + if top.config.warnMissingInh && !null(lhsInhExceedsFlowType) + then [mwdaWrnFromOrigin(top, "Forward equation exceeds flow type with dependencies on " ++ implode(", ", lhsInhExceedsFlowType))] else []; } aspect production forwardInh @@ -535,7 +228,6 @@ top::ForwardInh ::= lhs::ForwardLHSExpr '=' e::Expr ';' { -- oh no again! local myFlow :: EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).grammarFlowTypes; - local myGraphs::EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).productionFlowGraphs; local transitiveDeps :: [FlowVertex] = expandGraph(e.flowDeps, top.frame.flowGraph); @@ -553,62 +245,12 @@ top::ForwardInh ::= lhs::ForwardLHSExpr '=' e::Expr ';' inhDepsForSyn("forward", top.frame.lhsNtName, myFlow)))); top.errors <- - if top.config.warnMissingInh - then checkAllEqDeps(transitiveDeps, e.flowDefs, top.config, top.frame.fullName, myGraphs, top.flowEnv, top.env) ++ - if null(lhsInhExceedsFlowType) then [] - else [mwdaWrnFromOrigin(top, "Forward inherited equation exceeds flow type with dependencies on " ++ implode(", ", lhsInhExceedsFlowType))] - else []; -} - -aspect production localValueDef -top::ProductionStmt ::= @val::QName e::Expr -{ - -- oh no again! - local myGraphs::EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).productionFlowGraphs; - - local transitiveDeps :: [FlowVertex] = - expandGraph(e.flowDeps, top.frame.flowGraph); - - -- check transitive deps only. No worries about flow types. - top.errors <- - if top.config.warnMissingInh - then checkAllEqDeps(transitiveDeps, e.flowDefs, top.config, top.frame.fullName, myGraphs, top.flowEnv, top.env) - else []; -} - -aspect production returnDef -top::ProductionStmt ::= 'return' e::Expr ';' -{ - -- oh no again! - local myGraphs::EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).productionFlowGraphs; - - local transitiveDeps :: [FlowVertex] = - expandGraph(e.flowDeps, top.frame.flowGraph); - - top.errors <- - if top.config.warnMissingInh - then checkAllEqDeps(transitiveDeps, e.flowDefs, top.config, top.frame.fullName, myGraphs, top.flowEnv, top.env) + if top.config.warnMissingInh && !null(lhsInhExceedsFlowType) + then [mwdaWrnFromOrigin(top, "Forward inherited equation exceeds flow type with dependencies on " ++ implode(", ", lhsInhExceedsFlowType))] else []; } -aspect production attachNoteStmt -top::ProductionStmt ::= 'attachNote' e::Expr ';' -{ - -- oh no again! - local myGraphs::EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).productionFlowGraphs; - - local transitiveDeps :: [FlowVertex] = - expandGraph(e.flowDeps, top.frame.flowGraph); - - top.errors <- - if top.config.warnMissingInh - then checkAllEqDeps(transitiveDeps, e.flowDefs, top.config, top.frame.fullName, myGraphs, top.flowEnv, top.env) - else []; -} - --- Skipping `baseCollectionValueDef`: it forwards to `localValueDef` --- Partially skipping `appendCollectionValueDef`: it likewise forwards --- But we do have a special "exceeds check" to do here: +-- We have a special "exceeds check" to do here: aspect production appendCollectionValueDef top::ProductionStmt ::= @val::QName e::Expr { @@ -628,8 +270,8 @@ top::ProductionStmt ::= @val::QName e::Expr if top.config.warnMissingInh -- We can ignore functions. We're checking LHS inhs here... functions don't have any! && top.frame.hasFullSignature - then if null(lhsInhExceedsFlowType) then [] - else [mwdaWrnFromOrigin(top, "Local contribution (" ++ val.name ++ " <-) equation exceeds flow dependencies with: " ++ implode(", ", lhsInhExceedsFlowType))] + && !null(lhsInhExceedsFlowType) + then [mwdaWrnFromOrigin(top, "Local contribution (" ++ val.name ++ " <-) equation exceeds flow dependencies with: " ++ implode(", ", lhsInhExceedsFlowType))] else []; } @@ -639,26 +281,40 @@ top::ProductionStmt ::= @val::QName e::Expr {- Step 2: Let's go check on expressions. This has two purposes: -1. Better error messages for missing equations than the "transitive dependency" ones. - But technically, unneeded and transititve dependencies are covering this. -2. We have to ensure that each individual access from a reference fits within the inferred reference set. - Additionally we must check that wherever we take a reference, the required reference set is bounded. +1. We have to ensure that each individual access from a reference fits within the inferred reference set. + Additionally we must check that wherever we take a reference, the required reference set from the type is bounded, + and all attributes of the reference set have equations. This is not covered by any other checks. +2. For any attribute access, we need to check that the attribute (for an inh) + or its dependencies (for a syn) have equations. -} aspect production childReference top::Expr ::= @q::QName { + -- oh no again + local myGraphs::EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).productionFlowGraphs; + + local vt::VertexType = rhsVertexType(q.lookupValue.fullName); top.errors <- if top.config.warnMissingInh && isDecorable(q.lookupValue.typeScheme.typerep, top.env) - then if refSet.isJust then [] - else [mwdaWrnFromOrigin(top, s"Cannot take a reference of type ${prettyType(top.finalType)}, as the reference set is not bounded.")] + then + case refSet of + | just(inhDeps) -> map(\ di::(DecSiteTree, [String]) -> + mwdaWrnFromOrigin(top, + s"Taking a reference to ${q.name} requires missing inherited attribute(s) ${implode(", ", di.2)}" ++ + " to be supplied to " ++ prettyDecSites(0, di.1)), + decSitesMissingInhEqs(top.frame.fullName, vt, inhDeps, myGraphs, top.flowEnv, top.env)) + | nothing() -> + [mwdaWrnFromOrigin(top, s"Cannot take a reference of type ${prettyType(top.finalType)}, as the reference set is not bounded.")] + end else []; } aspect production lhsReference top::Expr ::= @q::QName { + -- Only need to check ref set is bounded, since all inh missing on LHS is a flow issue and not checked here. top.errors <- if top.config.warnMissingInh then if refSet.isJust then [] @@ -668,20 +324,44 @@ top::Expr ::= @q::QName aspect production localReference top::Expr ::= @q::QName { + -- oh no again + local myGraphs::EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).productionFlowGraphs; + + local vt::VertexType = localVertexType(q.lookupValue.fullName); top.errors <- if top.config.warnMissingInh && isDecorable(q.lookupValue.typeScheme.typerep, top.env) - then if refSet.isJust then [] - else [mwdaWrnFromOrigin(top, s"Cannot take a reference of type ${prettyType(top.finalType)}, as the reference set is not bounded.")] + then + case refSet of + | just(inhDeps) -> map(\ di::(DecSiteTree, [String]) -> + mwdaWrnFromOrigin(top, + s"Taking a reference to ${q.name} requires missing inherited attribute(s) ${implode(", ", di.2)}" ++ + " to be supplied to " ++ prettyDecSites(0, di.1)), + decSitesMissingInhEqs(top.frame.fullName, vt, inhDeps, myGraphs, top.flowEnv, top.env)) + | nothing() -> + [mwdaWrnFromOrigin(top, s"Cannot take a reference of type ${prettyType(top.finalType)}, as the reference set is not bounded.")] + end else []; } aspect production forwardReference top::Expr ::= @q::QName { + -- oh no again + local myGraphs::EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).productionFlowGraphs; + + -- We do, actually, need to check for missing inh equations here, due to weirdness with translation attr overrides. top.errors <- if top.config.warnMissingInh - then if refSet.isJust then [] - else [mwdaWrnFromOrigin(top, s"Cannot take a reference of type ${prettyType(top.finalType)}, as the reference set is not bounded.")] + then + case refSet of + | just(inhDeps) -> map(\ di::(DecSiteTree, [String]) -> + mwdaWrnFromOrigin(top, + s"Taking a reference to ${q.name} requires missing inherited attribute(s) ${implode(", ", di.2)}" ++ + " to be supplied to " ++ prettyDecSites(0, di.1)), + decSitesMissingInhEqs(top.frame.fullName, forwardVertexType(), inhDeps, myGraphs, top.flowEnv, top.env)) + | nothing() -> + [mwdaWrnFromOrigin(top, s"Cannot take a reference of type ${prettyType(top.finalType)}, as the reference set is not bounded.")] + end else []; } @@ -741,28 +421,18 @@ top::Expr ::= @e::Expr @q::QNameAttrOccur ---------------- - -- CASE 2: More specific errors for things already caught by `checkAllEqDeps`. - -- Equation has transitive dep on `i`, but here we can say where this dependency - -- originated: from a syn access. + -- CASE 2: Check that there are inh equations for this attr's flow type. top.errors <- if null(e.errors) && top.config.warnMissingInh then case e.flowVertexInfo of - | just(vt) when - case vt of - | rhsVertexType(_) -> true - | localVertexType(_) -> true - | _ -> false - end -> - case decSitesMissingInhEqs(top.frame.fullName, vt, set:toList(inhDeps), myGraphs, top.flowEnv, top.env) of - | [] -> [] - | missingEqs -> map(\ di::(DecSiteTree, [String]) -> - mwdaWrnFromOrigin(top, - "Access of synthesized attribute " ++ q.name ++ " on " ++ e.unparse ++ - " requires missing inherited attribute(s) " ++ implode(", ", di.2) ++ - " to be supplied to " ++ prettyDecSites(0, di.1)), - missingEqs) - end + | just(lhsVertexType()) -> [] -- Short circuit to avoid overhead of checking accesses on the LHS + | just(vt) -> map(\ di::(DecSiteTree, [String]) -> + mwdaWrnFromOrigin(top, + "Access of synthesized attribute " ++ q.name ++ " on " ++ e.unparse ++ -- TODO: e.unparse can be big, abbreviate it? + " requires missing inherited attribute(s) " ++ implode(", ", di.2) ++ + " to be supplied to " ++ prettyDecSites(0, di.1)), + decSitesMissingInhEqs(top.frame.fullName, vt, set:toList(inhDeps), myGraphs, top.flowEnv, top.env)) | _ -> [] end else []; @@ -771,9 +441,10 @@ top::Expr ::= @e::Expr @q::QNameAttrOccur aspect production inhDecoratedAccessHandler top::Expr ::= @e::Expr @q::QNameAttrOccur { - -- In this case, ONLY check for references. - -- The transitive deps error will be less difficult to figure out when there's - -- an explicit access to the attributes. + -- oh no again + local myGraphs::EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).productionFlowGraphs; + + -- CASE 1: References. This check is necessary and won't be caught elsewhere. top.errors <- if null(e.errors) && top.config.warnMissingInh then @@ -786,6 +457,24 @@ top::Expr ::= @e::Expr @q::QNameAttrOccur else [mwdaWrnFromOrigin(top, "Access of inherited attribute " ++ q.name ++ " on reference of type " ++ prettyType(e.finalType) ++ " is not permitted")] end else []; + +---------------- + + -- CASE 2: Check that this inh has an equation. + top.errors <- + if null(e.errors) && top.config.warnMissingInh + then + case e.flowVertexInfo of + | just(lhsVertexType()) -> [] -- Short circuit to avoid overhead of checking accesses on the LHS + | just(vt) -> map(\ di::(DecSiteTree, [String]) -> + mwdaWrnFromOrigin(top, + "Access of inherited attribute " ++ q.name ++ " on " ++ e.unparse ++ -- TODO: e.unparse can be big, abbreviate it? + " requires missing inherited attribute(s) " ++ implode(", ", di.2) ++ + " to be supplied to " ++ prettyDecSites(0, di.1)), + decSitesMissingInhEqs(top.frame.fullName, vt, [q.attrDcl.fullName], myGraphs, top.flowEnv, top.env)) + | _ -> [] + end + else []; } aspect production transDecoratedAccessHandler @@ -803,15 +492,28 @@ top::Expr ::= @e::Expr @q::QNameAttrOccur -- When taking a reference to this translation attribute access, we depend on the ref set inhs on e. set:fromList(map(\ inh::String -> s"${q.attrDcl.fullName}.${inh}", fromMaybe([], refSet))); - -- Need to check that the reference set is bounded when taking a reference, as with locals/children/etc. + -- Need to check that all attrs in the reference set are supplied when taking a reference, as with locals/children/etc. top.errors <- - if top.config.warnMissingInh - then if refSet.isJust then [] - else [mwdaWrnFromOrigin(top, s"Cannot take a reference of type ${prettyType(e.finalType)}, as the reference set is not bounded.")] + if top.config.warnMissingInh && q.found + then + case refSet of + | just(inhDeps) -> + case e.flowVertexInfo of + | just(vt) -> map(\ di::(DecSiteTree, [String]) -> + mwdaWrnFromOrigin(top, + s"Taking a reference to ${top.unparse} requires missing inherited attribute(s) ${implode(", ", di.2)}" ++ + " to be supplied to " ++ prettyDecSites(0, di.1)), + decSitesMissingInhEqs(top.frame.fullName, transAttrVertexType(vt, q.attrDcl.fullName), inhDeps, myGraphs, top.flowEnv, top.env)) + | nothing() -> + if null(inhDeps) then [] + -- TODO: Would need to introduce an anon vertex type for e as a sink like pattern matching on a reference. + else [mwdaWrnFromOrigin(top, "Taking a reference to a translation attribute on a reference is not currently supported")] + end + | nothing() -> + [mwdaWrnFromOrigin(top, s"Cannot take a reference of type ${prettyType(top.finalType)}, as the reference set is not bounded.")] + end else []; - -- TODO: check that reference set is only inhs? - -- This logic exactly mirrors synDecoratedAccessHandler, except with inhDeps containing extra inh dependencies from taking a reference. -- This aspect is in two parts. First: we *must* check that any accesses @@ -853,28 +555,17 @@ top::Expr ::= @e::Expr @q::QNameAttrOccur ---------------- - -- CASE 2: More specific errors for things already caught by `checkAllEqDeps`. - -- Equation has transitive dep on `i`, but here we can say where this dependency - -- originated: from a syn access. + -- CASE 2: Check that there are inh equations for this attr's flow type. top.errors <- if null(e.errors) && top.config.warnMissingInh then case e.flowVertexInfo of - | just(vt) when - case vt of - | rhsVertexType(_) -> true - | localVertexType(_) -> true - | _ -> false - end -> - case decSitesMissingInhEqs(top.frame.fullName, vt, set:toList(inhDeps), myGraphs, top.flowEnv, top.env) of - | [] -> [] - | missingEqs -> map(\ di::(DecSiteTree, [String]) -> - mwdaWrnFromOrigin(top, - "Access of translation attribute " ++ q.name ++ " on " ++ e.unparse ++ - " requires missing inherited attribute(s) " ++ implode(", ", di.2) ++ - " to be supplied to " ++ prettyDecSites(0, di.1)), - missingEqs) - end + | just(vt) -> map(\ di::(DecSiteTree, [String]) -> + mwdaWrnFromOrigin(top, + "Access of translation attribute " ++ q.name ++ " on " ++ e.unparse ++ + " requires missing inherited attribute(s) " ++ implode(", ", di.2) ++ + " to be supplied to " ++ prettyDecSites(0, di.1)), + decSitesMissingInhEqs(top.frame.fullName, vt, set:toList(inhDeps), myGraphs, top.flowEnv, top.env)) | _ -> [] end else []; @@ -884,44 +575,12 @@ top::Expr ::= @e::Expr @q::QNameAttrOccur aspect production decorateExprWith top::Expr ::= 'decorate' e::Expr 'with' '{' inh::ExprInhs '}' { - -- Do nothing. Everything gets taken care of with anonResolve and checkEqDeps at the top-level of the equation + -- Do nothing. The inhs available for anon dec site references are tracked by the type system. } aspect production decorationSiteExpr top::Expr ::= '@' e::Expr { - -- Check for an inherited attribute supplied via sharing, that may be needed to determine dispatching. - - -- The dependencies for determining the production(s) under which this tree is shared: - local dispatchDeps :: set:Set = - set:fromList(expandGraph(top.dispatchFlowDeps, top.frame.flowGraph)); - - -- All inherited attributes known locally to occur on the shared tree. - -- We don't need *all* inherited attributes, because only the ones we know about - -- could be a dependency for dispatching. - local sharedRefInhs :: [String] = getInhAndInhOnTransAttrsOn(e.finalType.typeName, top.env); - - -- Inherited attributes on the shared tree that might be depended upon by dispatching. - local dispatchDepsOnRef :: [String] = - case e.flowVertexInfo of - | just(localVertexType(fName)) when isForwardProdAttr(top.frame.fullName, fName, top.flowEnv) -> [] - | just(vt) -> filter(\ i::String -> - set:contains(vt.inhVertex(i), dispatchDeps) && - !vertexHasInhEq(top.frame.fullName, vt, i, top.flowEnv), - sharedRefInhs) - | _ -> [] - end; - - top.errors <- - if top.config.warnMissingInh - then - case e.flowVertexInfo of - | just(vt) when !null(dispatchDepsOnRef) -> - [mwdaWrnFromOrigin(top, s"Dispatching may require inherited attribute(s) ${implode(", ", dispatchDepsOnRef)} on ${vt.vertexName}, but these attribute(s) are supplied here after dispatching")] - | _ -> [] - end - else []; - -- Sharing a forward production attribute somewhere that isn't already being decorated as the forward -- may cause hidden transitive dependency issues for attributes we don't know about, so we forbid this. top.errors <- @@ -930,7 +589,7 @@ top::Expr ::= '@' e::Expr case e.flowVertexInfo of | just(localVertexType(fName)) when isForwardProdAttr(top.frame.fullName, fName, top.flowEnv) -> case top.decSiteVertexInfo of - | just(forwardVertexType_real()) -> [] + | just(forwardVertexType()) -> [] | just(localVertexType(dSiteFName)) when isForwardProdAttr(top.frame.fullName, dSiteFName, top.flowEnv) -> [] | _ -> [mwdaWrnFromOrigin(top, s"Forward production attribute ${fName} may only be shared in a forward decoration site")] end @@ -942,38 +601,6 @@ top::Expr ::= '@' e::Expr aspect production presentAppExpr top::AppExpr ::= e::Expr { - -- Same checks as for decorationSiteExpr, for application of a prod with a shared signature param. - - -- The dependencies for determining the production(s) under which this tree is shared: - local dispatchDeps :: set:Set = - set:fromList(expandGraph(top.dispatchFlowDeps, top.frame.flowGraph)); - - -- All inherited attributes known locally to occur on the shared tree. - -- We don't need *all* inherited attributes, because only the ones we know about - -- could be a dependency for dispatching. - local sharedRefInhs :: [String] = getInhAndInhOnTransAttrsOn(e.finalType.typeName, top.env); - - -- Inherited attributes on the shared tree that might be depended upon by dispatching. - local dispatchDepsOnRef :: [String] = - case e.flowVertexInfo of - | just(localVertexType(fName)) when isForwardProdAttr(top.frame.fullName, fName, top.flowEnv) -> [] - | just(vt) -> filter(\ i::String -> - set:contains(vt.inhVertex(i), dispatchDeps) && - !vertexHasInhEq(top.frame.fullName, vt, i, top.flowEnv), - sharedRefInhs) - | _ -> [] - end; - - top.errors <- - if top.config.warnMissingInh && sigIsShared && isForwardParam - then - case e.flowVertexInfo of - | just(vt) when !null(dispatchDepsOnRef) -> - [mwdaWrnFromOrigin(top, s"Dispatching may require inherited attribute(s) ${implode(", ", dispatchDepsOnRef)} on ${vt.vertexName}, but these attribute(s) are supplied here after dispatching")] - | _ -> [] - end - else []; - -- Sharing a forward production attribute somewhere that isn't already being decorated as the forward -- may cause hidden transitive dependency issues for attributes we don't know about, so we forbid this. top.errors <- @@ -982,7 +609,7 @@ top::AppExpr ::= e::Expr case e.flowVertexInfo of | just(localVertexType(fName)) when isForwardProdAttr(top.frame.fullName, fName, top.flowEnv) -> case top.decSiteVertexInfo of - | just(forwardVertexType_real()) -> [] + | just(forwardVertexType()) -> [] | just(localVertexType(dSiteFName)) when isForwardProdAttr(top.frame.fullName, dSiteFName, top.flowEnv) -> [] | _ -> [mwdaWrnFromOrigin(top, s"Forward production attribute ${fName} may only be shared in a forward decoration site")] end @@ -991,88 +618,27 @@ top::AppExpr ::= e::Expr else []; } -{-- - - For pattern matching, we have an obligation to check: - - 1. If we invented an anon vertex type for the scrutinee, then it's a sink, and - - we need to check that nothing more than the ref set was depended upon. - -} -aspect production matchPrimitiveReal -top::Expr ::= e::Expr t::TypeExpr pr::PrimPatterns f::Expr -{ - -- slightly awkward way to recover the name and whether/not it was invented - local sinkVertexName :: Maybe = - case e.flowVertexInfo, pr.scrutineeVertexType of - | nothing(), anonVertexType(n) -> just(n) - | _, _ -> nothing() - end; - - -- These should be the only ones that can reference our anon sink - local transitiveDeps :: [FlowVertex] = - expandGraph(top.flowDeps, top.frame.flowGraph); - - pr.receivedDeps = transitiveDeps; - - -- just the deps on inhs of our sink - local inhDeps :: [String] = toAnonInhs(transitiveDeps, sinkVertexName.fromJust); - - -- Subtract the ref set from our deps - local diff :: [String] = - set:toList(set:removeAll(getMinRefSet(^scrutineeType, top.env), set:add(inhDeps, set:empty()))); - - top.errors <- - if null(e.errors) - && top.config.warnMissingInh - && sinkVertexName.isJust - && !null(diff) - then [mwdaWrnFromOrigin(e, "Pattern match on reference of type " ++ prettyType(^scrutineeType) ++ " has transitive dependencies on " ++ implode(", ", diff))] - else []; - -} - -fun toAnonInhs [String] ::= vs::[FlowVertex] vertex::String = - filterMap(\ v::FlowVertex -> - case v of - | anonInhVertex(n, inh) when n == vertex -> just(inh) - | _ -> nothing() - end, vs); - -inherited attribute receivedDeps :: [FlowVertex] occurs on VarBinders, VarBinder, PrimPatterns, PrimPattern; -propagate @receivedDeps on VarBinders, VarBinder, PrimPatterns, PrimPattern; - +-- Also need to check for taking a reference to a pattern var. +-- Note that we know this at VarBinder due to a non-empty reference set type being inferred. aspect production varVarBinder top::VarBinder ::= n::Name { -- oh no again! local myGraphs::EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).productionFlowGraphs; - -- Check that we're not taking an unbounded reference - top.errors <- - if top.config.warnMissingInh - && isDecorable(top.bindingType, top.env) - then if refSet.isJust then [] - else [mwdaWrnFromOrigin(top, s"Cannot take a reference of type ${prettyType(^finalTy)}, as the reference set is not bounded.")] - else []; - - -- fName is our invented vertex name for the pattern variable - local requiredInhs :: [String] = toAnonInhs(top.receivedDeps, fName); - - -- Check for equation's existence: - -- Prod: top.matchingAgainst.fromJust.fullName - -- Child: top.bindingName - -- Inh: each of requiredInhs - local missingInhEqs :: [(DecSiteTree, [String])] = - decSitesMissingInhEqs( - top.matchingAgainst.fromJust.fullName, rhsVertexType(top.bindingName), - removeAll(getMinRefSet(top.bindingType, top.env), requiredInhs), - myGraphs, top.flowEnv, top.env); - top.errors <- if top.config.warnMissingInh && isDecorable(top.bindingType, top.env) - && top.matchingAgainst.isJust - then map(\ eqs::(DecSiteTree, [String]) -> - mwdaWrnFromOrigin(top, s"Pattern variable '${n.name}' has transitive dependencies with missing remote equations for ${implode(", ", eqs.2)}. These attributes must be supplied to ${prettyDecSites(0, eqs.1)}"), - missingInhEqs) + then + case refSet of + | just(inhDeps) -> map(\ di::(DecSiteTree, [String]) -> + mwdaWrnFromOrigin(top, + s"Taking a reference to ${n.name} requires missing inherited attribute(s) ${implode(", ", di.2)}" ++ + " to be supplied to " ++ prettyDecSites(0, di.1)), + decSitesMissingInhEqs(top.frame.fullName, vt.fromJust, inhDeps, myGraphs, top.flowEnv, top.env)) + | nothing() -> + [mwdaWrnFromOrigin(top, s"Cannot take a reference of type ${prettyType(top.bindingType)}, as the reference set is not bounded.")] + end else []; } @@ -1109,14 +675,3 @@ top::Context ::= attr::String args::[Type] atty::Type inhs::Type ntty::Type else [mwdaWrn(top.config, top.contextLoc, s"The instance for ${prettyContext(^top)} (arising from ${top.contextSource}) has a flow type exceeding the constraint with dependencies on " ++ implode(", ", diff))] else []; } - --------------------------------------------------------------------------------- - --- TODO: There are a few final places where we need to `checkEqDeps` for the sake of `anonVertex`s - --- action blocks (production, terminal, disam, etc) - --- But we don't create flowEnv information for these locations so they can't be checked... oops --- (e.g. `checkEqDeps` wants a production fName to look things up about.) - - diff --git a/grammars/silver/compiler/analysis/warnings/flow/MWDA.sv b/grammars/silver/compiler/analysis/warnings/flow/MWDA.sv index 9d552b53d..0cb855d1e 100644 --- a/grammars/silver/compiler/analysis/warnings/flow/MWDA.sv +++ b/grammars/silver/compiler/analysis/warnings/flow/MWDA.sv @@ -21,7 +21,8 @@ imports silver:compiler:analysis:typechecking:core; -- flow analysis imports silver:compiler:definition:flow:ast; imports silver:compiler:definition:flow:env; -imports silver:compiler:definition:flow:driver only ProductionGraph, FlowType, prod, inhDepsForSyn, findProductionGraph, expandGraph, onlyLhsInh; +imports silver:compiler:definition:flow:driver only + ProductionGraph, FlowType, prod, inhDepsForSyn, findProductionGraph, expandGraph, onlyLhsInh, expandTileGraphSigDeps, tileEdgeMap; -- uniqueness analysis imports silver:compiler:analysis:uniqueness; diff --git a/grammars/silver/compiler/analysis/warnings/flow/MwdaFlag.sv b/grammars/silver/compiler/analysis/warnings/flow/MwdaFlag.sv index 06d4d5014..4ff0a3b9d 100644 --- a/grammars/silver/compiler/analysis/warnings/flow/MwdaFlag.sv +++ b/grammars/silver/compiler/analysis/warnings/flow/MwdaFlag.sv @@ -17,6 +17,7 @@ top::CmdArgs ::= rest::CmdArgs top.warnOrphaned = true; top.warnFwd = true; top.warnSharing = true; + -- warnSharingCycles is not enabled by default in --mwda forwards to @rest; } @@ -30,6 +31,7 @@ top::CmdArgs ::= rest::CmdArgs top.warnOrphaned = true; top.warnFwd = true; top.warnSharing = true; + top.warnSharingCycles = true; } aspect function parseArgs diff --git a/grammars/silver/compiler/analysis/warnings/flow/OrphanedProduction.sv b/grammars/silver/compiler/analysis/warnings/flow/OrphanedProduction.sv index f473764bf..6b3937280 100644 --- a/grammars/silver/compiler/analysis/warnings/flow/OrphanedProduction.sv +++ b/grammars/silver/compiler/analysis/warnings/flow/OrphanedProduction.sv @@ -57,9 +57,7 @@ top::AGDcl ::= 'abstract' 'production' id::Name d::ProductionImplements ns::Prod -- If this production implements a dispatch signature from a grammar that does not export this production !isExportedBy(top.grammarName, [implode(":", init(explode(":", dSig.fullName)))], top.compiledGrammars) && -- AND this production does not forward to an application of the same dispatch signature with the same shared children - !any(map( - \ e::Decorated Expr -> e.isDispatchApplication(dSig), - body.forwardExpr ++ body.forwardProdAttrExprs)) + !any(map(\ e::Decorated Expr -> e.isDispatchApplication(dSig), body.forwardExpr)) -> [mwdaWrnFromOrigin(top, s"Orphaned implementation production ${id.name} for dispatch ${dSig.fullName}; this production must forward directly to an application of this dispatch signature with the same shared children.")] | _ -> [] end @@ -74,7 +72,7 @@ top::AGDcl ::= 'abstract' 'production' id::Name d::ProductionImplements ns::Prod -} monoid attribute isDispatchApplication :: (Boolean ::= NamedSignature) with pure(false), lift2(conj, _, _) occurs on Expr, PrimPatterns, PrimPattern; -flowtype isDispatchApplication {decorate} on Expr; +flowtype isDispatchApplication {decorate} on Expr, PrimPattern; aspect isDispatchApplication on top::Expr using := of | dispatchApplication(e, es, _) -> \ dSig::NamedSignature -> diff --git a/grammars/silver/compiler/analysis/warnings/flow/Sharing.sv b/grammars/silver/compiler/analysis/warnings/flow/Sharing.sv index 1f37fe7c6..31e0dfa64 100644 --- a/grammars/silver/compiler/analysis/warnings/flow/Sharing.sv +++ b/grammars/silver/compiler/analysis/warnings/flow/Sharing.sv @@ -48,7 +48,7 @@ top::Expr ::= @q::QName || q.lookupValue.dcl.implementedSignature.isJust then [] else case top.appDecSiteVertexInfo of - | just(forwardVertexType_real()) -> [] + | just(forwardVertexType()) -> [] | just(localVertexType(fName)) when isForwardProdAttr(top.frame.fullName, fName, top.flowEnv) -> [] | _ -> [mwdaWrnFromOrigin(top, s"Non-dispatch production ${q.name} has shared children in its signature, and can only be referenced by applying it in the root position of a forward or forward production attribute equation.")] @@ -65,7 +65,7 @@ top::Expr ::= @e::Expr @es::AppExprs @anns::AnnoAppExprs case e.finalType of | dispatchType(ns) when any(map((.elementShared), ns.inputElements)) -> case top.decSiteVertexInfo of - | just(forwardVertexType_real()) -> [] + | just(forwardVertexType()) -> [] | just(localVertexType(fName)) when isForwardProdAttr(top.frame.fullName, fName, top.flowEnv) -> [] | _ -> [mwdaWrnFromOrigin(e, s"Dispatch ${ns.fullName} has shared children in its signature, and can only be applied in the root position of a forward or forward production attribute equation.")] diff --git a/grammars/silver/compiler/analysis/warnings/flow/SharingCycles.sv b/grammars/silver/compiler/analysis/warnings/flow/SharingCycles.sv new file mode 100644 index 000000000..607de04fe --- /dev/null +++ b/grammars/silver/compiler/analysis/warnings/flow/SharingCycles.sv @@ -0,0 +1,70 @@ +grammar silver:compiler:analysis:warnings:flow; + +synthesized attribute warnSharingCycles :: Boolean occurs on CmdArgs; + +aspect production endCmdArgs +top::CmdArgs ::= l::[String] +{ + top.warnSharingCycles = false; +} +abstract production warnSharingCyclesFlag +top::CmdArgs ::= rest::CmdArgs +{ + top.warnSharingCycles = true; + forwards to @rest; +} +aspect function parseArgs +Either ::= args::[String] +{ + flags <- [ + flagSpec(name="--warn-sharing-cycles", paramString=nothing(), + help="warn about potential cycles due to missing inherited override equations (conservative check, disabled in --mwda by default)", + flagParser=flag(warnSharingCyclesFlag))]; +} + +aspect production decorationSiteExpr +top::Expr ::= '@' e::Expr +{ + -- oh no again! + local myGraphs::EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).productionFlowGraphs; + + -- Check for cycles due to missing inherited equations on shared trees. + -- We need to check inherited attributes known locally to occur on the shared tree, + -- that don't have an inherited equation defined locally, and thus may be involved in a cycle. + -- We don't need *all* inherited attributes, because only the ones we know about + -- could be a dependency for constructing the decoration site tree. + top.errors <- + case top.decSiteVertexInfo, e.flowVertexInfo of + | _, just(localVertexType(fName)) when isForwardProdAttr(top.frame.fullName, fName, top.flowEnv) -> [] + | just(decSite), just(ref) when top.config.warnSharingCycles -> flatMap(\ i::String -> + if !vertexHasInhEq(top.frame.fullName, ref, i, top.flowEnv) + && decSiteHasInhEq(top.frame.fullName, decSite, i, myGraphs, top.flowEnv, top.env) + && contains(ref.inhVertex(i), expandGraph(decSite.inhDeps(i), top.frame.flowGraph)) + then [mwdaWrnFromOrigin(top, s"Potentially missing inherited override equation for ${i} on ${ref.vertexName}; a cycle may exist via its sharing decoration site ${decSite.vertexName}")] + else [], + getInhAndInhOnTransAttrsOn(e.finalType.typeName, top.env)) + | _, _ -> [] + end; +} + +aspect production presentAppExpr +top::AppExpr ::= e::Expr +{ + -- oh no again! + local myGraphs::EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).productionFlowGraphs; + + -- Same checks as for decorationSiteExpr, for application of a prod with a shared signature param. + top.errors <- + case sigDecSite, e.flowVertexInfo of + | just(decSite), just(ref) + when top.config.warnSharingCycles && sigIsShared && isForwardParam -> + flatMap(\ i::String -> + if !vertexHasInhEq(top.frame.fullName, ref, i, top.flowEnv) + && decSiteHasInhEq(top.frame.fullName, decSite, i, myGraphs, top.flowEnv, top.env) + && contains(ref.inhVertex(i), expandGraph(decSite.inhDeps(i), top.frame.flowGraph)) + then [mwdaWrnFromOrigin(top, s"Potentially missing inherited override equation for ${i} on ${ref.vertexName}; a cycle may exist via its sharing decoration site ${decSite.vertexName}")] + else [], + getInhAndInhOnTransAttrsOn(e.finalType.typeName, top.env)) + | _, _ -> [] + end; +} diff --git a/grammars/silver/compiler/definition/concrete_syntax/ParserSpec.sv b/grammars/silver/compiler/definition/concrete_syntax/ParserSpec.sv index 7c05a0b59..d15dbf03b 100644 --- a/grammars/silver/compiler/definition/concrete_syntax/ParserSpec.sv +++ b/grammars/silver/compiler/definition/concrete_syntax/ParserSpec.sv @@ -67,7 +67,7 @@ top::ParserSpec ::= production markingTerminalPrefixes::[Pair] = flatMap( \ gp::Pair -> - map(pair(fst=_, snd=gp.snd), lookup(gp.fst, componentGrammarMarkingTerminals).fromJust), + zipSnd(lookup(gp.1, componentGrammarMarkingTerminals).fromJust, gp.2), grammarTerminalPrefixes); top.cstAst = diff --git a/grammars/silver/compiler/definition/concrete_syntax/ast/CstAst.sv b/grammars/silver/compiler/definition/concrete_syntax/ast/CstAst.sv index a3c21b5cc..128131c89 100644 --- a/grammars/silver/compiler/definition/concrete_syntax/ast/CstAst.sv +++ b/grammars/silver/compiler/definition/concrete_syntax/ast/CstAst.sv @@ -165,6 +165,6 @@ EnvTree ::= allTerms::[String] layoutItems::[String] layoutContribs::[Pa return directBuildTree( flatMap( - \ item::Pair -> map(pair(fst=item.fst, snd=_), item.snd), + \ item::Pair -> zipFst(item.fst, item.snd), layoutTerms)); } diff --git a/grammars/silver/compiler/definition/concrete_syntax/ast/LexerClassModifiers.sv b/grammars/silver/compiler/definition/concrete_syntax/ast/LexerClassModifiers.sv index 37505615a..ddcf79fd0 100644 --- a/grammars/silver/compiler/definition/concrete_syntax/ast/LexerClassModifiers.sv +++ b/grammars/silver/compiler/definition/concrete_syntax/ast/LexerClassModifiers.sv @@ -66,7 +66,7 @@ top::SyntaxLexerClassModifier ::= super::[String] -- included in the parser. See https://github.com/melt-umn/silver/issues/694 production superRefs :: [Decorated SyntaxDcl] = concat(lookupStrings(super, top.cstEnv)); - top.superClassContribs := map(pair(fst=top.className, snd=_), map((.fullName), superRefs)); + top.superClassContribs := zipFst(top.className, map((.fullName), superRefs)); } {-- @@ -108,20 +108,20 @@ top::SyntaxLexerClassModifier ::= dom::[String] - A disambiguation function that should be created for the members of a lexer class. -} abstract production lexerClassDisambiguate -top::SyntaxLexerClassModifier ::= acode::String +top::SyntaxLexerClassModifier ::= acode::ActionCode { production terms :: [String] = searchEnvTree(top.className, top.classTerminals); production funName::String = s"disambiguate_${makeCopperName(top.className)}"; production syntaxDcl::SyntaxDcl = - syntaxDisambiguationGroup(funName, terms, true, s""" + syntaxDisambiguationGroup(funName, terms, true, acode(acodeTrans=s""" common.ConsCell tempShiftableList = common.ConsCell.nil; for (int i = nextMember(0, shiftable); i >= 0; i = nextMember(i+1, shiftable)) { tempShiftableList = new common.ConsCell(i, tempShiftableList); } final common.ConsCell shiftableList = tempShiftableList; -${acode} -""", location=top.location, sourceGrammar=top.sourceGrammar); +${acode.acodeTrans} +"""), location=top.location, sourceGrammar=top.sourceGrammar); syntaxDcl.cstEnv = top.cstEnv; syntaxDcl.containingGrammar = top.containingGrammar; syntaxDcl.classTerminals = top.classTerminals; diff --git a/grammars/silver/compiler/definition/concrete_syntax/ast/ProductionModifiers.sv b/grammars/silver/compiler/definition/concrete_syntax/ast/ProductionModifiers.sv index 3cd1aaece..e31b029b6 100644 --- a/grammars/silver/compiler/definition/concrete_syntax/ast/ProductionModifiers.sv +++ b/grammars/silver/compiler/definition/concrete_syntax/ast/ProductionModifiers.sv @@ -32,7 +32,7 @@ top::SyntaxProductionModifiers ::= nonterminal SyntaxProductionModifier with compareTo, isEqual, cstEnv, cstErrors, acode, productionPrecedence, customLayout, productionOperator, productionSig; -propagate compareTo, isEqual, cstEnv, productionSig on SyntaxProductionModifier; +propagate compareTo, isEqual, cstEnv, acode, productionSig on SyntaxProductionModifier; aspect default production top::SyntaxProductionModifier ::= @@ -67,10 +67,8 @@ top::SyntaxProductionModifier ::= term::String - The action to perform when this production is REDUCEd. -} abstract production prodAction -top::SyntaxProductionModifier ::= acode::String -{ - top.acode := acode; -} +top::SyntaxProductionModifier ::= acode::ActionCode +{} {-- - The layout for this production. -} diff --git a/grammars/silver/compiler/definition/concrete_syntax/ast/Syntax.sv b/grammars/silver/compiler/definition/concrete_syntax/ast/Syntax.sv index b59a56240..cc56cf4ac 100644 --- a/grammars/silver/compiler/definition/concrete_syntax/ast/Syntax.sv +++ b/grammars/silver/compiler/definition/concrete_syntax/ast/Syntax.sv @@ -160,7 +160,7 @@ top::SyntaxDcl ::= t::Type subdcls::Syntax exportedProds::[String] exportedLayou top.exportedProds = exportedProds; top.hasCustomLayout = modifiers.customLayout.isJust; - top.layoutContribs := map(pair(fst=t.typeName, snd=_), fromMaybe(exportedLayoutTerms, modifiers.customLayout)); + top.layoutContribs := zipFst(t.typeName, fromMaybe(exportedLayoutTerms, modifiers.customLayout)); top.copperElementReference = copper:elementReference(top.sourceGrammar, top.location, top.containingGrammar, makeCopperName(t.typeName)); @@ -195,8 +195,8 @@ top::SyntaxDcl ::= n::String regex::Regex modifiers::SyntaxTerminalModifiers top.classTerminalContribs := modifiers.classTerminalContribs; top.memberTerminals := [top]; top.dominatingTerminalContribs := - map(pair(fst=n, snd=_), flatMap((.memberTerminals), modifiers.submits_)) ++ - map(pair(fst=_, snd=top), map((.fullName), flatMap((.memberTerminals), modifiers.dominates_))); + zipFst(n, flatMap((.memberTerminals), modifiers.submits_)) ++ + zipSnd(map((.fullName), flatMap((.memberTerminals), modifiers.dominates_)), top); top.terminalRegex = ^regex; -- left(terminal name) or right(string prefix) @@ -273,7 +273,7 @@ top::SyntaxDcl ::= ns::NamedSignature modifiers::SyntaxProductionModifiers top.hasCustomLayout = modifiers.customLayout.isJust; top.layoutContribs := - map(pair(fst=ns.fullName, snd=_), fromMaybe([], modifiers.customLayout)) ++ + zipFst(ns.fullName, fromMaybe([], modifiers.customLayout)) ++ -- The production inherits its LHS nonterminal's layout, unless overridden. (if top.hasCustomLayout then [] else [(ns.fullName, head(lhsRef).fullName)]) ++ -- All nonterminals on the RHS that export this production inherit this @@ -400,7 +400,7 @@ top::SyntaxDcl ::= n::String modifiers::SyntaxLexerClassModifiers - A parser attribute. The acode initializes it. -} abstract production syntaxParserAttribute -top::SyntaxDcl ::= n::String ty::Type acode::String +top::SyntaxDcl ::= n::String ty::Type acode::ActionCode { top.fullName = n; top.sortKey = "BBB" ++ n; @@ -415,7 +415,7 @@ top::SyntaxDcl ::= n::String ty::Type acode::String top.copperGrammarElements = [ copper:parserAttribute(top.sourceGrammar, top.location, makeCopperName(n), ty.transType, - acode ++ implode("\n", searchEnvTree(n, top.parserAttributeAspects))) + acode.acodeTrans ++ implode("\n", searchEnvTree(n, top.parserAttributeAspects))) ]; -- TODO: technically, there should be no free variables in ty. @@ -427,7 +427,7 @@ top::SyntaxDcl ::= n::String ty::Type acode::String - a parser attribute. -} abstract production syntaxParserAttributeAspect -top::SyntaxDcl ::= n::String acode::String +top::SyntaxDcl ::= n::String acode::ActionCode { top.fullName = n; top.sortKey = "BBB" ++ n; @@ -438,7 +438,7 @@ top::SyntaxDcl ::= n::String acode::String top.cstNormalize := [^top]; - top.parserAttributeAspectContribs := [(n, acode)]; + top.parserAttributeAspectContribs := [(n, acode.acodeTrans)]; -- The Copper information for these gets picked up by the main syntaxParserAttribute declaration. top.copperElementReference = error("can't demand copperElementReference of an aspect"); top.copperGrammarElements = []; @@ -449,7 +449,7 @@ top::SyntaxDcl ::= n::String acode::String - The acode distinguished between the listed terminals. -} abstract production syntaxDisambiguationGroup -top::SyntaxDcl ::= n::String terms::[String] applicableToSubsets::Boolean acode::String +top::SyntaxDcl ::= n::String terms::[String] applicableToSubsets::Boolean acode::ActionCode { top.fullName = n; top.sortKey = "DDD" ++ n; @@ -474,7 +474,7 @@ top::SyntaxDcl ::= n::String terms::[String] applicableToSubsets::Boolean acode: trefs); top.copperGrammarElements = [ copper:disambiguationFunction(top.sourceGrammar, top.location, - makeCopperName(n), acode, members, applicableToSubsets) + makeCopperName(n), acode.acodeTrans, members, applicableToSubsets) ]; } @@ -491,3 +491,14 @@ function sortKeyLte Boolean ::= l::SyntaxDcl r::SyntaxDcl { return l.sortKey <= r.sortKey; } +annotation acodeSrc::String; +annotation acodeTrans::String; +data ActionCode = actionCode with acodeSrc, acodeTrans, acode; + +aspect acode on top::ActionCode using := of +| _ -> top.acodeTrans +end; + +instance Eq ActionCode { + eq = \ a1::ActionCode a2::ActionCode -> a1.acodeSrc == a2.acodeSrc; +} diff --git a/grammars/silver/compiler/definition/concrete_syntax/ast/TerminalModifiers.sv b/grammars/silver/compiler/definition/concrete_syntax/ast/TerminalModifiers.sv index 0854aef29..6fb3af7cf 100644 --- a/grammars/silver/compiler/definition/concrete_syntax/ast/TerminalModifiers.sv +++ b/grammars/silver/compiler/definition/concrete_syntax/ast/TerminalModifiers.sv @@ -56,7 +56,7 @@ closed nonterminal SyntaxTerminalModifier with compareTo, isEqual, cstEnv, cstEr prefixSeperatorToApply, componentGrammarMarkingTerminals, marking, terminalName, prettyName; -propagate compareTo, isEqual on SyntaxTerminalModifier; +propagate compareTo, isEqual, acode on SyntaxTerminalModifier; {- We default ALL attributes, so we can focus only on those that are interesting in each case... -} aspect default production @@ -123,7 +123,7 @@ top::SyntaxTerminalModifier ::= cls::[String] production allClsRefs :: [Decorated SyntaxDcl] = concat(lookupStrings(allCls, top.cstEnv)); top.cstErrors := []; - top.classTerminalContribs := map(pair(fst=_, snd=top.terminalName), allCls); + top.classTerminalContribs := zipSnd(allCls, top.terminalName); -- We "translate away" lexer classes dom/sub, by moving that info to the terminals (here) top.dominates_ := flatMap((.domContribs), allClsRefs); top.submits_ := flatMap((.subContribs), allClsRefs); @@ -172,10 +172,8 @@ top::SyntaxTerminalModifier ::= dom::[String] - The action to take whenever this terminal is SHIFTed. -} abstract production termAction -top::SyntaxTerminalModifier ::= acode::String -{ - top.acode := acode; -} +top::SyntaxTerminalModifier ::= acode::ActionCode +{} {-- - The prefix separator to use for the terminal. - Doesn't seem super useful, but support this on terminals too for consistency diff --git a/grammars/silver/compiler/definition/core/AspectDcl.sv b/grammars/silver/compiler/definition/core/AspectDcl.sv index d62894631..01a803fb9 100644 --- a/grammars/silver/compiler/definition/core/AspectDcl.sv +++ b/grammars/silver/compiler/definition/core/AspectDcl.sv @@ -1,14 +1,16 @@ grammar silver:compiler:definition:core; tracked nonterminal AspectProductionSignature with config, grammarName, env, unparse, errors, defs, realSignature, namedSignature, signatureName; -tracked nonterminal AspectProductionLHS with config, grammarName, env, unparse, errors, defs, outputElement, realSignature; +tracked nonterminal AspectProductionLHS with config, grammarName, env, unparse, errors, defs, outputElement, elementName, realSignature; tracked nonterminal AspectFunctionSignature with config, grammarName, env, unparse, errors, defs, realSignature, namedSignature, signatureName; tracked nonterminal AspectFunctionLHS with config, grammarName, env, unparse, errors, defs, realSignature, outputElement; -tracked nonterminal AspectRHS with config, grammarName, env, unparse, errors, defs, inputElements, realSignature; -tracked nonterminal AspectRHSElem with config, grammarName, env, unparse, errors, defs, realSignature, inputElements, deterministicCount; +tracked nonterminal AspectRHS with config, grammarName, env, unparse, errors, defs, inputElements, elementNames, realSignature; +tracked nonterminal AspectRHSElem with config, grammarName, env, unparse, errors, defs, realSignature, inputElements, elementNames, deterministicCount; +flowtype elementName {} on AspectProductionLHS; +flowtype elementNames {} on AspectRHS, AspectRHSElem; flowtype forward {realSignature, grammarName, env, flowEnv} on AspectProductionSignature, AspectProductionLHS, AspectFunctionSignature, AspectFunctionLHS, AspectRHS; flowtype forward {deterministicCount, realSignature, grammarName, env, flowEnv} on AspectRHSElem; @@ -151,7 +153,7 @@ top::AspectProductionSignature ::= lhs::AspectProductionLHS '::=' rhs::AspectRHS lhs.realSignature = if null(top.realSignature) then [] else [head(top.realSignature)]; rhs.realSignature = if null(top.realSignature) then [] else tail(top.realSignature); } action { - sigNames = foldNamedSignatureElements(lhs.outputElement :: rhs.inputElements).elementNames; + sigNames = lhs.elementName :: rhs.elementNames; } concrete production aspectProductionLHSNone @@ -198,6 +200,7 @@ top::AspectProductionLHS ::= id::Name t::Type rType = if null(top.realSignature) then errorType() else head(top.realSignature).elementDclType; top.outputElement = namedSignatureElement(id.name, ^t, false); + top.elementName = id.name; top.defs := [aliasedLhsDef(top.grammarName, id.nameLoc, fName, performSubstitution(^t, top.upSubst), id.name)]; @@ -213,6 +216,7 @@ top::AspectRHS ::= propagate defs; top.inputElements = []; + top.elementNames = []; } concrete production aspectRHSElemCons @@ -223,6 +227,7 @@ top::AspectRHS ::= h::AspectRHSElem t::AspectRHS propagate defs; top.inputElements = h.inputElements ++ t.inputElements; + top.elementNames = h.elementNames ++ t.elementNames; h.deterministicCount = length(t.inputElements); h.realSignature = if null(top.realSignature) then [] else [head(top.realSignature)]; @@ -233,6 +238,7 @@ concrete production aspectRHSElemNone top::AspectRHSElem ::= '_' { top.unparse = "_"; + top.elementNames = []; nondecorated production attribute rType :: Type; rType = if null(top.realSignature) then errorType() else head(top.realSignature).typerep; @@ -301,6 +307,7 @@ top::AspectRHSElem ::= shared::Boolean id::Name t::Type rType = if null(top.realSignature) then errorType() else head(top.realSignature).elementDclType; top.inputElements = [namedSignatureElement(id.name, ^t, shared)]; + top.elementNames = [id.name]; top.defs := [aliasedChildDef(top.grammarName, id.nameLoc, fName, performSubstitution(^t, top.upSubst), shared, id.name)]; @@ -326,6 +333,8 @@ top::AspectFunctionSignature ::= lhs::AspectFunctionLHS '::=' rhs::AspectRHS lhs.realSignature = if null(top.realSignature) then [] else [head(top.realSignature)]; rhs.realSignature = if null(top.realSignature) then [] else tail(top.realSignature); +} action { + sigNames = rhs.elementNames; } concrete production functionLHSType diff --git a/grammars/silver/compiler/definition/core/Expr.sv b/grammars/silver/compiler/definition/core/Expr.sv index e7f02f53b..8627d7747 100644 --- a/grammars/silver/compiler/definition/core/Expr.sv +++ b/grammars/silver/compiler/definition/core/Expr.sv @@ -18,7 +18,7 @@ tracked nonterminal ExprLHSExpr with flowtype unparse {} on Expr, Exprs, ExprInhs, ExprInh, ExprLHSExpr; flowtype freeVars {frame} on Expr, Exprs, ExprInhs, ExprInh, ExprLHSExpr; flowtype Expr = - forward {grammarName, env, flowEnv, downSubst, finalSubst, frame, isRoot, compiledGrammars, config, decSiteVertexInfo, appDecSiteVertexInfo, dispatchFlowDeps}, + forward {grammarName, env, flowEnv, downSubst, finalSubst, frame, isRoot, compiledGrammars, config, decSiteVertexInfo, appDecSiteVertexInfo}, decorate {forward, alwaysDecorated, originRules}, errors {forward}, typerep {forward}; @@ -438,6 +438,7 @@ top::Expr ::= @e::Expr @es::AppExprs @anns::AnnoAppExprs { top.unparse = e.unparse ++ "(" ++ es.unparse ++ "," ++ anns.unparse ++ ")"; + -- TODO: Error when no named arguments provided? local prod::Application = if es.appExprSize > 0 then annoUpdatePositionalErrorApplication @@ -1051,11 +1052,11 @@ tracked nonterminal AppExprs with flowtype AppExprs = decorate { config, grammarName, env, frame, compiledGrammars, appExprTypereps, appExprApplied, originRules, - downSubst, finalSubst, flowEnv, appIndexOffset, dispatchFlowDeps + downSubst, finalSubst, flowEnv, appIndexOffset }, errors { config, grammarName, env, frame, compiledGrammars, appExprTypereps, appExprApplied, - downSubst, finalSubst, flowEnv, decSiteVertexInfo, dispatchFlowDeps, appProd, appIndexOffset + downSubst, finalSubst, flowEnv, decSiteVertexInfo, appProd, appIndexOffset }; tracked nonterminal AppExpr with @@ -1064,11 +1065,11 @@ tracked nonterminal AppExpr with flowtype AppExpr = decorate { config, grammarName, env, frame, compiledGrammars, appExprIndex, appExprTyperep, appExprApplied, originRules, - downSubst, finalSubst, flowEnv, appIndexOffset, dispatchFlowDeps + downSubst, finalSubst, flowEnv, appIndexOffset }, errors { config, grammarName, env, frame, compiledGrammars, appExprIndex, appExprTyperep, appExprApplied, - downSubst, finalSubst, flowEnv, decSiteVertexInfo, dispatchFlowDeps, appProd, appIndexOffset + downSubst, finalSubst, flowEnv, decSiteVertexInfo, appProd, appIndexOffset }; propagate config, grammarName, env, freeVars, frame, compiledGrammars, errors, originRules on AppExprs, AppExpr; diff --git a/grammars/silver/compiler/definition/core/FunctionDcl.sv b/grammars/silver/compiler/definition/core/FunctionDcl.sv index f681c9aa0..e80151142 100644 --- a/grammars/silver/compiler/definition/core/FunctionDcl.sv +++ b/grammars/silver/compiler/definition/core/FunctionDcl.sv @@ -74,7 +74,7 @@ top::FunctionSignature ::= cl::ConstraintList '=>' lhs::FunctionLHS '::=' rhs::P then [errFromOrigin(rhs, "Sharing in function parameters is not permitted.")] else []; } action { - sigNames = foldNamedSignatureElements(rhs.inputElements).elementNames; + sigNames = rhs.elementNames; } concrete production functionSignatureNoCL @@ -84,7 +84,7 @@ top::FunctionSignature ::= lhs::FunctionLHS '::=' rhs::ProductionRHS forwards to functionSignature(nilConstraint(), '=>', @lhs, $2, @rhs); } action { - sigNames = foldNamedSignatureElements(rhs.inputElements).elementNames; + sigNames = rhs.elementNames; } concrete production functionLHS diff --git a/grammars/silver/compiler/definition/core/OccursDcl.sv b/grammars/silver/compiler/definition/core/OccursDcl.sv index bb620bc40..4fdd87052 100644 --- a/grammars/silver/compiler/definition/core/OccursDcl.sv +++ b/grammars/silver/compiler/definition/core/OccursDcl.sv @@ -178,6 +178,10 @@ top::AGDcl ::= at::QName attl::BracketedOptTypeExprs nt::QName nttl::BracketedOp " but type variable(s) have kind(s) " ++ implode(", ", map(compose(prettyKind, (.kindrep)), nttl.types)) ++ ".")] | _ -> [] end; + + -- Seeding flow deps + top.errors <- if false then [] else error(hackUnparse( + (nttl.forward, nt.qNameType, attl.errorsTyVars, top.unparse))); } concrete production attributionDcl diff --git a/grammars/silver/compiler/definition/core/ProductionBody.sv b/grammars/silver/compiler/definition/core/ProductionBody.sv index 2a3f2310e..ad665ef56 100644 --- a/grammars/silver/compiler/definition/core/ProductionBody.sv +++ b/grammars/silver/compiler/definition/core/ProductionBody.sv @@ -19,6 +19,10 @@ flowtype forward {frame, grammarName, compiledGrammars, config, env, flowEnv, do flowtype decorate {forward} on ProductionBody; flowtype decorate {forward, originRules} on ProductionStmts, ProductionStmt; +flowtype unparse {} on ProductionBody, ProductionStmts, ProductionStmt; +flowtype defs {forward} on ProductionBody, ProductionStmts, ProductionStmt; +flowtype productionAttributes {forward} on ProductionBody, ProductionStmts, ProductionStmt; + tracked nonterminal DefLHS with config, grammarName, env, unparse, errors, frame, compiledGrammars, name, typerep, defLHSattr, found, originRules; @@ -390,13 +394,6 @@ top::ProductionStmt ::= @dl::DefLHS @attr::QNameAttrOccur e::Expr top.unparse = "\t" ++ dl.unparse ++ "." ++ attr.unparse ++ " = " ++ e.unparse ++ ";"; e.isRoot = true; - - top.errors <- - case getValueDcl(top.frame.fullName, top.env) of - | dcl :: _ when dcl.hasForward && attr.found && attr.attrDcl.isTranslation -> - [errFromOrigin(top, s"Overriding translation attribute ${attr.attrDcl.fullName} in a forwarding production is not currently supported.")] - | _ -> [] - end; } abstract production inheritedAttributeDef implements AttributeDef diff --git a/grammars/silver/compiler/definition/core/ProductionDcl.sv b/grammars/silver/compiler/definition/core/ProductionDcl.sv index 00244de8d..96175bbc2 100644 --- a/grammars/silver/compiler/definition/core/ProductionDcl.sv +++ b/grammars/silver/compiler/definition/core/ProductionDcl.sv @@ -2,15 +2,16 @@ grammar silver:compiler:definition:core; tracked nonterminal ProductionImplements with config, grammarName, env, unparse, errors, implementsSig; tracked nonterminal ProductionSignature with config, grammarName, env, unparse, errors, defs, constraintDefs, occursDefs, namedSignature, signatureName, implementedSig; -tracked nonterminal ProductionLHS with config, grammarName, env, unparse, errors, defs, outputElement, implementedSig; -tracked nonterminal ProductionRHS with config, grammarName, env, unparse, errors, defs, inputElements, elementCount, implementedSig; -tracked nonterminal ProductionRHSElem with config, grammarName, env, unparse, errors, defs, inputElements, deterministicCount, implementedSig; +tracked nonterminal ProductionLHS with config, grammarName, env, unparse, errors, defs, outputElement, elementName, implementedSig; +tracked nonterminal ProductionRHS with config, grammarName, env, unparse, errors, defs, inputElements, elementNames, elementCount, implementedSig; +tracked nonterminal ProductionRHSElem with config, grammarName, env, unparse, errors, defs, inputElements, elementNames, deterministicCount, implementedSig; flowtype forward {env, signatureName} on ProductionSignature; flowtype forward {env} on ProductionLHS, ProductionRHS; flowtype forward {deterministicCount, env} on ProductionRHSElem; -flowtype decorate {forward, grammarName, flowEnv, implementedSig} on ProductionSignature, ProductionLHS, ProductionRHS, ProductionRHSElem; +flowtype decorate {forward, grammarName, flowEnv, implementedSig} on + ProductionSignature, ProductionLHS, ProductionRHS, ProductionRHSElem; propagate config, grammarName, errors on ProductionImplements, ProductionSignature, ProductionLHS, ProductionRHS, ProductionRHSElem; @@ -147,7 +148,7 @@ top::ProductionSignature ::= cl::ConstraintList '=>' lhs::ProductionLHS '::=' rh lhs.outputElement, foldNamedSignatureElements(annotationsForNonterminal(lhs.outputElement.typerep, top.env))); } action { - sigNames = foldNamedSignatureElements(lhs.outputElement :: rhs.inputElements).elementNames; + sigNames = lhs.elementName :: rhs.elementNames; } concrete production productionSignatureNoCL @@ -157,7 +158,7 @@ top::ProductionSignature ::= lhs::ProductionLHS '::=' rhs::ProductionRHS forwards to productionSignature(nilConstraint(), '=>', @lhs, $2, @rhs); } action { - sigNames = foldNamedSignatureElements(lhs.outputElement :: rhs.inputElements).elementNames; + sigNames = lhs.elementName :: rhs.elementNames; } concrete production productionLHS @@ -167,6 +168,7 @@ top::ProductionLHS ::= id::Name '::' t::TypeExpr propagate env; top.outputElement = namedSignatureElement(id.name, t.typerep, false); + top.elementName = id.name; top.defs := [lhsDef(top.grammarName, id.nameLoc, id.name, t.typerep)]; @@ -192,6 +194,7 @@ top::ProductionRHS ::= top.unparse = ""; top.inputElements = []; + top.elementNames = []; top.elementCount = 0; } @@ -201,6 +204,7 @@ top::ProductionRHS ::= h::ProductionRHSElem t::ProductionRHS top.unparse = h.unparse ++ " " ++ t.unparse; top.inputElements = h.inputElements ++ t.inputElements; + top.elementNames = h.elementNames ++ t.elementNames; top.elementCount = 1 + t.elementCount; h.deterministicCount = t.elementCount; @@ -217,6 +221,7 @@ top::ProductionRHSElem ::= ms::MaybeShared id::Name '::' t::TypeExpr propagate env; top.inputElements = [namedSignatureElement(id.name, t.typerep, ms.isShared)]; + top.elementNames = [id.name]; top.defs := [childDef(top.grammarName, id.nameLoc, id.name, t.typerep, ms.isShared)]; @@ -232,6 +237,7 @@ concrete production productionRHSElemType top::ProductionRHSElem ::= ms::MaybeShared t::TypeExpr { top.unparse = ms.unparse ++ t.unparse; + top.elementNames = []; forwards to productionRHSElem(@ms, name("_G_" ++ toString(top.deterministicCount)), '::', @t); } diff --git a/grammars/silver/compiler/definition/env/DclInfo.sv b/grammars/silver/compiler/definition/env/DclInfo.sv index bfabaa0e1..4491571cd 100644 --- a/grammars/silver/compiler/definition/env/DclInfo.sv +++ b/grammars/silver/compiler/definition/env/DclInfo.sv @@ -38,7 +38,7 @@ synthesized attribute hasForward :: Boolean; -- occurs synthesized attribute attrOccurring :: String; inherited attribute givenNonterminalType :: Type; - +synthesized attribute attrTypeName::String; synthesized attribute isAnnotation :: Boolean; -- also "attrs" -- attrs @@ -359,7 +359,7 @@ top::ProductionAttrDclInfo ::= ns::NamedSignature{-fn::String outty::Type intys: nonterminal OccursDclInfo with sourceGrammar, sourceLocation, fullName, compareTo, isEqual, - typeScheme, givenNonterminalType, attrOccurring, isAnnotation; + typeScheme, givenNonterminalType, attrOccurring, attrTypeName, isAnnotation; propagate compareTo, isEqual on OccursDclInfo excluding occursDcl; aspect default production @@ -395,6 +395,7 @@ top::OccursDclInfo ::= fnnt::String fnat::String ntty::Type atty::Type else monoType(performRenaming(^atty, subst)); top.attrOccurring = fnat; + top.attrTypeName = atty.typeName; } abstract production occursInstConstraintDcl @@ -402,6 +403,7 @@ top::OccursDclInfo ::= fnat::String ntty::Type atty::Type tvs::[TyVar] { top.fullName = ntty.typeName; top.attrOccurring = fnat; + top.attrTypeName = atty.typeName; top.typeScheme = monoType(^atty); @@ -412,6 +414,7 @@ top::OccursDclInfo ::= fnat::String ntty::Type atty::Type ns::NamedSignature { top.fullName = ntty.typeName; top.attrOccurring = fnat; + top.attrTypeName = atty.typeName; top.typeScheme = monoType(^atty); @@ -422,6 +425,7 @@ top::OccursDclInfo ::= fnat::String atty::Type baseDcl::InstDclInfo { top.fullName = baseDcl.typeScheme.typerep.typeName; top.attrOccurring = fnat; + top.attrTypeName = atty.typeName; top.typeScheme = constraintType(baseDcl.typeScheme.boundVars, baseDcl.typeScheme.contexts, ^atty); } @@ -445,6 +449,7 @@ top::OccursDclInfo ::= fnnt::String fnat::String ntty::Type atty::Type else monoType(performRenaming(^atty, subst)); top.attrOccurring = fnat; + top.attrTypeName = atty.typeName; -- UGH - bit of a short hand here... top.isAnnotation = true; @@ -454,6 +459,7 @@ top::OccursDclInfo ::= fnat::String ntty::Type atty::Type tvs::[TyVar] { top.fullName = ntty.typeName; top.attrOccurring = fnat; + top.attrTypeName = atty.typeName; top.isAnnotation = true; top.typeScheme = monoType(^atty); @@ -465,6 +471,7 @@ top::OccursDclInfo ::= fnat::String ntty::Type atty::Type ns::NamedSignature { top.fullName = ntty.typeName; top.attrOccurring = fnat; + top.attrTypeName = atty.typeName; top.isAnnotation = true; top.typeScheme = monoType(^atty); @@ -476,6 +483,7 @@ top::OccursDclInfo ::= fnat::String atty::Type baseDcl::InstDclInfo { top.fullName = baseDcl.typeScheme.typerep.typeName; top.attrOccurring = fnat; + top.attrTypeName = atty.typeName; top.isAnnotation = true; top.typeScheme = constraintType(baseDcl.typeScheme.boundVars, baseDcl.typeScheme.contexts, ^atty); diff --git a/grammars/silver/compiler/definition/env/Env.sv b/grammars/silver/compiler/definition/env/Env.sv index a0c1f359b..8c77d0350 100644 --- a/grammars/silver/compiler/definition/env/Env.sv +++ b/grammars/silver/compiler/definition/env/Env.sv @@ -274,18 +274,24 @@ fun getInhAttrsOn [String] ::= fnnt::String e::Env = - Also includes all inherited attributes occurring on translation attributes on the - nonterminal, when we want to treat these like inherited attributes. -} -fun getInhAndInhOnTransAttrsOn [String] ::= fnnt::String e::Env = - flatMap( - \ o::OccursDclInfo -> - case getAttrDcl(o.attrOccurring, e) of - | at :: _ when at.isInherited -> [o.attrOccurring] - | at :: _ when at.isSynthesized && at.isTranslation -> - map( - \ inh::String -> s"${o.attrOccurring}.${inh}", - getInhAttrsOn(at.typeScheme.typeName, e)) - | _ -> [] - end, - getAttrOccursOn(fnnt, e)); +function getInhAndInhOnTransAttrsOn +[String] ::= fnnt::String e::Env +{ + local recurse::([String] ::= [String] String) = \ seenNts nt -> + if contains(nt, seenNts) then [] + else flatMap( + \ o::OccursDclInfo -> + case getAttrDcl(o.attrOccurring, e) of + | at :: _ when at.isInherited -> [o.attrOccurring] + | at :: _ when at.isSynthesized && at.isTranslation -> + map( + \ inh::String -> s"${o.attrOccurring}.${inh}", + recurse(nt :: seenNts, at.typeScheme.typeName)) + | _ -> [] + end, + getAttrOccursOn(nt, e)); + return recurse([], fnnt); +} -- This ensure the annotation list is in the properly sorted order! function annotationsForNonterminal diff --git a/grammars/silver/compiler/definition/flow/ast/DecSiteTree.sv b/grammars/silver/compiler/definition/flow/ast/DecSiteTree.sv index a96f46055..713023482 100644 --- a/grammars/silver/compiler/definition/flow/ast/DecSiteTree.sv +++ b/grammars/silver/compiler/definition/flow/ast/DecSiteTree.sv @@ -86,10 +86,19 @@ top::DecSiteTree ::= prodName::String vt::VertexType d::DecSiteTree production directDec top::DecSiteTree ::= prodName::String vt::VertexType { - -- TODO: What if vt is an anonVertexType? top.decSitePP = s"${vt.vertexPP} of production ${prodName}"; } +{-- + - An attribute could be supplied via a production that wasn't found in the environment + - (e.g. in a modification that wasn't imported). + -} +production hiddenProdDec +top::DecSiteTree ::= prodName::String vt::VertexType +{ + top.decSitePP = s"${vt.vertexPP} of hidden production ${prodName}"; +} + {-- - An attribute can be supplied via forwarding. - Inherited attributes on a translation attribute are only supplied if this is @@ -128,6 +137,15 @@ top::DecSiteTree ::= prodName::String sigName::String d::DecSiteTree d.maxDepth = top.maxDepth - 1; } +{-- + - Scrutinee of a pattern match on a reference requires the inherited attribute to be in the reference set. + -} +production anonScrutineeRefSetDec +top::DecSiteTree ::= refSet::[String] grammarName::String loc::Location +{ + top.decSitePP = s"reference set {${implode(", ", refSet)}} of pattern match scrutinee at ${grammarName}:${loc.unparse}"; +} + {-- - An inherited attribute on a translation attribute can be supplied via a translation attribute. -} diff --git a/grammars/silver/compiler/definition/flow/ast/Flow.sv b/grammars/silver/compiler/definition/flow/ast/Flow.sv index 364ede63d..76a963d73 100644 --- a/grammars/silver/compiler/definition/flow/ast/Flow.sv +++ b/grammars/silver/compiler/definition/flow/ast/Flow.sv @@ -150,9 +150,11 @@ top::FlowDef ::= nt::String prod::String - - @param dispatchSig The full name of the dispatch signature that is implemented - @param prod The full name of the production + - @param sigNames The names of the RHS elements in the production + - @param extraSigNts Extra nonterminal children that do not correspond to the dispatch signature, and their types -} abstract production implFlowDef -top::FlowDef ::= dispatchSig::String prod::String sigNames::[String] +top::FlowDef ::= dispatchSig::String prod::String sigNames::[String] extraSigNts::[(String, String)] { top.implTreeContribs := [(dispatchSig, prod, sigNames)]; top.prodGraphContribs := [(dispatchSig, top)]; @@ -188,7 +190,7 @@ top::FlowDef ::= nt::String attr::String deps::[FlowVertex] { top.defTreeContribs := [(crossnames(nt, attr), top)]; top.prodGraphContribs := [(nt ++ ":default", top)]; - top.flowEdges = map(pair(fst=lhsSynVertex(attr), snd=_), deps); -- but their edges WILL end up added to graphs in fixup-phase!! + top.flowEdges = zipFst(lhsSynVertex(attr), deps); -- but their edges WILL end up added to graphs in fixup-phase!! } {-- @@ -204,7 +206,7 @@ top::FlowDef ::= prod::String attr::String deps::[FlowVertex] mayAffectFlowTy { top.synTreeContribs := [(crossnames(prod, attr), top)]; top.prodGraphContribs := [(prod, top)]; - local edges :: [(FlowVertex, FlowVertex)] = map(pair(fst=lhsSynVertex(attr), snd=_), deps); + local edges :: [(FlowVertex, FlowVertex)] = zipFst(lhsSynVertex(attr), deps); top.flowEdges = if mayAffectFlowType then edges else []; top.suspectFlowEdges = if mayAffectFlowType then [] else edges; } @@ -216,14 +218,35 @@ top::FlowDef ::= prod::String attr::String deps::[FlowVertex] mayAffectFlowTy - @param sigName the name of the RHS element - @param attr the full name of the attribute - @param deps the dependencies of this equation on other flow graph elements + - @param decSites sharing sites for which this is an override equation - CONTRIBUTIONS ARE POSSIBLE -} abstract production inhEq -top::FlowDef ::= prod::String sigName::String attr::String deps::[FlowVertex] +top::FlowDef ::= prod::String sigName::String attr::String deps::[FlowVertex] decSites::[VertexType] { top.inhTreeContribs := [(crossnames(prod, crossnames(sigName, attr)), top)]; top.prodGraphContribs := [(prod, top)]; - top.flowEdges = map(pair(fst=rhsInhVertex(sigName, attr), snd=_), deps); + top.flowEdges = cartProd( + rhsInhVertex(sigName, attr) :: map(\ v::VertexType -> v.inhVertex(attr), decSites), + deps); +} + +{-- + - The definition of a translation attribute in a production. + - + - @param prod the full name of the production + - @param attr the full name of the attribute + - @param deps the dependencies of this equation on other flow graph elements + - CONTRIBUTIONS ARE *NOT* POSSIBLE + -} +abstract production transEq +top::FlowDef ::= prod::String attr::String deps::[FlowVertex] mayAffectFlowType::Boolean +{ + top.synTreeContribs := [(crossnames(prod, attr), top)]; + top.prodGraphContribs := [(prod, top)]; + local edges :: [(FlowVertex, FlowVertex)] = zipFst(lhsSynVertex(attr), deps); + top.flowEdges = if mayAffectFlowType then edges else []; + top.suspectFlowEdges = if mayAffectFlowType then [] else edges; } {-- @@ -238,7 +261,7 @@ top::FlowDef ::= prod::String deps::[FlowVertex] mayAffectFlowType::Boolean { top.fwdTreeContribs := [(prod, top)]; top.prodGraphContribs := [(prod, top)]; - local edges :: [(FlowVertex, FlowVertex)] = map(pair(fst=forwardEqVertex(), snd=_), deps); + local edges :: [(FlowVertex, FlowVertex)] = zipFst(forwardEqVertex, deps); top.flowEdges = if mayAffectFlowType then edges else []; top.suspectFlowEdges = if mayAffectFlowType then [] else edges; } @@ -271,7 +294,7 @@ top::FlowDef ::= prod::String attr::String deps::[FlowVertex] { top.fwdInhTreeContribs := [(crossnames(prod, attr), top)]; top.prodGraphContribs := [(prod, top)]; - top.flowEdges = map(pair(fst=forwardInhVertex(attr), snd=_), deps); + top.flowEdges = zipFst(forwardInhVertex(attr), deps); } {-- @@ -281,17 +304,17 @@ top::FlowDef ::= prod::String attr::String deps::[FlowVertex] - @param prod the full name of the production - @param fName the name of the local/production attribute - @param typeName the full name of the type, or empty string if not a decorable type! - - @param isNT true if the type is a nonterminal - @param isFwrd true if this is a forward production attribute - @param deps the dependencies of this equation on other flow graph elements + - @param outerDeps the dependencies of the top-level node constructed by this equation - CONTRIBUTIONS ARE POSSIBLE -} abstract production localEq -top::FlowDef ::= prod::String fName::String typeName::String isNT::Boolean isFwrd::Boolean deps::[FlowVertex] +top::FlowDef ::= prod::String fName::String typeName::String isFwrd::Boolean deps::[FlowVertex] { top.localTreeContribs := [(crossnames(prod, fName), top)]; top.prodGraphContribs := [(prod, top)]; - top.flowEdges = map(pair(fst=localEqVertex(fName), snd=_), deps); + top.flowEdges = zipFst(localEqVertex(fName), deps); } {-- @@ -301,16 +324,18 @@ top::FlowDef ::= prod::String fName::String typeName::String isNT::Boolean i - @param fName the name of the local/production attribute - @param attr the full name of the attribute - @param deps the dependencies of this equation on other flow graph elements + - @param decSites sharing sites for which this is an override equation - CONTRIBUTIONS ARE POSSIBLE -} abstract production localInhEq -top::FlowDef ::= prod::String fName::String attr::String deps::[FlowVertex] +top::FlowDef ::= prod::String fName::String attr::String deps::[FlowVertex] decSites::[VertexType] { top.localInhTreeContribs := [(crossnames(prod, crossnames(fName, attr)), top)]; top.prodGraphContribs := [(prod, top)]; - top.flowEdges = map(pair(fst=localInhVertex(fName, attr), snd=_), deps); + top.flowEdges = cartProd( + localInhVertex(fName, attr) :: map(\ v::VertexType -> v.inhVertex(attr), decSites), + deps); } - {-- - The definition of an inherited attribute for a translation attribute - on an rhs signature element in a production. @@ -320,13 +345,20 @@ top::FlowDef ::= prod::String fName::String attr::String deps::[FlowVertex] - @param transAttr the full name of the translation attribute - @param attr the full name of the attribute - @param deps the dependencies of this equation on other flow graph elements + - @param baseDecSites sharing sites for sigName, for which this is an override equation + - @param transDecSites sharing sites for sigName.transAttr, for which this is an override equation -} abstract production transInhEq top::FlowDef ::= prod::String sigName::String transAttr::String attr::String deps::[FlowVertex] + baseDecSites::[VertexType] transDecSites::[VertexType] { top.inhTreeContribs := [(crossnames(prod, crossnames(sigName, s"${transAttr}.${attr}")), top)]; top.prodGraphContribs := [(prod, top)]; - top.flowEdges = map(pair(fst=rhsInhVertex(sigName, s"${transAttr}.${attr}"), snd=_), deps); + top.flowEdges = cartProd( + rhsInhVertex(sigName, s"${transAttr}.${attr}") :: + map(\ v::VertexType -> v.inhVertex(s"${transAttr}.${attr}"), baseDecSites) ++ + map(\ v::VertexType -> v.inhVertex(attr), transDecSites), + deps); } {-- @@ -338,18 +370,26 @@ top::FlowDef ::= prod::String sigName::String transAttr::String attr::String - @param transAttr the full name of the translation attribute - @param attr the full name of the attribute - @param deps the dependencies of this equation on other flow graph elements + - @param baseDecSites sharing sites for fName, for which this is an override equation + - @param transDecSites sharing sites for fName.transAttr, for which this is an override equation -} abstract production localTransInhEq top::FlowDef ::= prod::String fName::String transAttr::String attr::String deps::[FlowVertex] + baseDecSites::[VertexType] transDecSites::[VertexType] { top.localInhTreeContribs := [(crossnames(prod, crossnames(fName, s"${transAttr}.${attr}")), top)]; top.prodGraphContribs := [(prod, top)]; - top.flowEdges = map(pair(fst=localSynVertex(fName, s"${transAttr}.${attr}"), snd=_), deps); + top.flowEdges = cartProd( + localInhVertex(fName, s"${transAttr}.${attr}") :: + map(\ v::VertexType -> v.inhVertex(s"${transAttr}.${attr}"), baseDecSites) ++ + map(\ v::VertexType -> v.inhVertex(attr), transDecSites), + deps); } {-- - Used for contributions to collections. Allows tacking on dependencies - to vertices. + - TODO: Handle contributions for inh collections on shared trees? - - @param prod the full name of the production - @param src the vertex to add dependencies to @@ -359,7 +399,7 @@ abstract production extraEq top::FlowDef ::= prod::String src::FlowVertex deps::[FlowVertex] mayAffectFlowType::Boolean { top.prodGraphContribs := [(prod, top)]; - local edges :: [(FlowVertex, FlowVertex)] = map(pair(fst=src, snd=_), deps); + local edges :: [(FlowVertex, FlowVertex)] = zipFst(src, deps); top.flowEdges = if mayAffectFlowType then edges else []; top.suspectFlowEdges = if mayAffectFlowType then [] else edges; } @@ -369,17 +409,15 @@ top::FlowDef ::= prod::String src::FlowVertex deps::[FlowVertex] mayAffectFlo - - @param prod the full name of the production - @param fName the generated anonymous name for this decoration site - - @param typeName the full name of the type (usually a nonterminal, but may be a decorable type var) - - @param isNT true if the type is a nonterminal - @param deps the dependencies of this equation on other flow graph elements - (no contributions are possible) -} abstract production anonEq -top::FlowDef ::= prod::String fName::String typeName::String isNT::Boolean loc::Location deps::[FlowVertex] +top::FlowDef ::= prod::String fName::String loc::Location deps::[FlowVertex] { top.localTreeContribs := [(crossnames(prod, fName), top)]; top.prodGraphContribs := [(prod, top)]; - top.flowEdges = map(pair(fst=anonEqVertex(fName), snd=_), deps); + top.flowEdges = zipFst(anonEqVertex(fName), deps); } {-- @@ -396,7 +434,23 @@ top::FlowDef ::= prod::String fName::String attr::String deps::[FlowVertex] { top.localInhTreeContribs := [(crossnames(prod, crossnames(fName, attr)), top)]; top.prodGraphContribs := [(prod, top)]; - top.flowEdges = map(pair(fst=anonInhVertex(fName, attr), snd=_), deps); + top.flowEdges = zipFst(anonInhVertex(fName, attr), deps); +} + +{-- + - The definition of a pattern match on an anonymous reference. + - + - @param prod the full name of the production + - @param fName the generated anonymous name for this decoration site + - @param deps the dependencies of this equation on other flow graph elements + - (no contributions are possible) + -} +abstract production anonScrutineeEq +top::FlowDef ::= prod::String fName::String typeName::String isNt::Boolean refSet::[String] gram::String loc::Location deps::[FlowVertex] +{ + top.localTreeContribs := [(crossnames(prod, fName), top)]; + top.prodGraphContribs := [(prod, top)]; + top.flowEdges = zipFst(anonEqVertex(fName), deps); } {-- @@ -411,7 +465,7 @@ abstract production synOccursContextEq top::FlowDef ::= prod::String vt::VertexType attr::String deps::[String] { top.prodGraphContribs := [(prod, top)]; - top.flowEdges = map(pair(fst=vt.synVertex(attr), snd=_), map(vt.inhVertex, deps)); + top.flowEdges = zipFst(vt.synVertex(attr), map(vt.inhVertex, deps)); } {-- @@ -427,22 +481,68 @@ top::FlowDef ::= prod::String matchProd::String scrutinee::VertexType vars::[ } data PatternVarProjection - = patternVarProjection child::String typeName::String patternVar::String; + = patternVarProjection child::String typeName::String; {-- - A sub-term with a flow vertex, that has a known decoration site. - - Like patternRuleEq, this is only used in creating stitch points. + - Also add the outer equation vertex dependencies on the parent. - - @param prod the full name of the production + - @param sigNames the names of the children of prod - @param parent the flow vertex of the enclosing production call - @param termProd the applied production (or dispatch signature) - - @param sigName the name of the child under which this term appears -} abstract production subtermDecEq -top::FlowDef ::= prod::String parent::VertexType termProd::String nt::String sigName::String +top::FlowDef ::= prod::String sigNames::[String] parent::VertexType termProd::String { top.prodGraphContribs := [(prod, top)]; - top.flowEdges = []; + top.flowEdges = + map(\ c -> (subtermOuterEqVertex(parent, termProd, c), parent.outerEqVertex), sigNames); +} + +{-- + - An unknown tree that has a decoration site, e.g. a higher-order attribute access or new(ref). + - Also add the equation vertex dependencies on subterm vertices. + - Other vertex types get their eq deps from a top-level localEq, fwdEq or synEq, + - which also handles suspect edges. + - + - @param prod the full name of the production + - @param typeName the full name of the type (usually a nonterminal, but may be a decorable type var) + - @param isNT true if the type is a nonterminal + - @param vt the decoration site vertex type, for which the stitch point is created + - @param deps the dependencies of the defining expression on other flow graph elements + -} +abstract production holeEq +top::FlowDef ::= prod::String typeName::String isNt::Boolean vt::VertexType deps::[FlowVertex] +{ + top.prodGraphContribs := [(prod, top)]; + top.flowEdges = + case vt of + | subtermVertexType(_, _, _) -> cartProd([vt.eqVertex, vt.outerEqVertex], deps) + | _ -> [] + end; +} + +{-- + - A dependency of a decoration site in a sharing equation, + - e.g. 'f.callProd' in 'f.callProd(@a)`. + - + - @param prod the full name of the production + - @param decSite the decoration site vertex type + - @param deps the dependencies of this decoration site's equation vertex on other flow graph elements + -} +abstract production decSiteDepEq +top::FlowDef ::= prod::String decSite::VertexType deps::[FlowVertex] +{ + top.prodGraphContribs := [(prod, top)]; + top.flowEdges = cartProd( + decSite.outerEqVertex :: + -- The regular equation vertex deps will be added by the local/forward/trans equation, + -- and may need to be added as suspect edges, so don't add them here. + case decSite of + | subtermVertexType(_, _, _) -> [decSite.eqVertex] + | _ -> [] + end, deps); } {-- @@ -471,10 +571,9 @@ top::FlowDef ::= prod::String nt::String ref::VertexType decSite::VertexType - @param sigName the name of the shared child in prod - @param sourceProd the full name of the (dispatching) production that forwarded to prod - @param source the vertex type of the shared tree supplied by sourceProd as the shared child - - @param parent the vertex type of where prod is decorated in sourceProd - should always be forward or a forward prod attr. -} abstract production sigShareSite -top::FlowDef ::= prod::String nt::String sigName::String sourceProd::String source::VertexType parent::VertexType +top::FlowDef ::= prod::String nt::String sigName::String sourceProd::String source::VertexType { top.prodGraphContribs := [(prod, top)]; top.flowEdges = []; @@ -484,18 +583,3 @@ top::FlowDef ::= prod::String nt::String sigName::String sourceProd::String sour -- fun crossnames String ::= a::String b::String = a ++ " @ " ++ b; - --- - --- Used to get better error messages -fun collectAnonOrigin [Pair] ::= f::[FlowDef] = - foldr(collectAnonOriginItem, [], f); -fun collectAnonOriginItem [Pair] ::= f::FlowDef rest::[Pair] = - case f of - | anonEq(_, fN, _, _, l, _) -> - -- Small hack to improve error messages. Ignore anonEq's that come from patterns - if startsWith("__scrutinee", fN) - then rest - else (fN, l) :: rest - | _ -> rest - end; diff --git a/grammars/silver/compiler/definition/flow/ast/Vertex.sv b/grammars/silver/compiler/definition/flow/ast/Vertex.sv index e67cbfbb4..b0dd26899 100644 --- a/grammars/silver/compiler/definition/flow/ast/Vertex.sv +++ b/grammars/silver/compiler/definition/flow/ast/Vertex.sv @@ -6,12 +6,18 @@ grammar silver:compiler:definition:flow:ast; - See VertexType for some extra information organizing these vertexes somewhat. -} data FlowVertex = +{-- +- A vertex representing the signature LHS. +- This exists for convenience when taking a reference to the LHS, to depend on all RHS.EQ vertices. +-} + lhsEqVertex + {-- - A vertex representing a synthesized attribute on the nonterminal being constructed by this production. - - @param attrName the full name of a synthesized attribute on the lhs. -} - lhsSynVertex attrName::String +| lhsSynVertex attrName::String {-- - A vertex representing an inherited attribute on the nonterminal being constructed by this production. @@ -23,6 +29,22 @@ data FlowVertex = -} | lhsInhVertex attrName::String +{-- +- A vertex representing an element of the signature RHS. +- This has no direct dependencies, but is needed to record dependencies on RHS values for tile stitch points. +- +- @param sigName the name given to a signature nonterminal. +-} +| rhsEqVertex sigName::String + +{-- +- A vertex representing the outer dependencies of an element of the signature RHS. +- This has no direct dependencies, but is needed to record outer dependencies on RHS values for tile stitch points. +- +- @param sigName the name given to a signature nonterminal. +-} +| rhsOuterEqVertex sigName::String + {-- - A vertex representing a synthesized attribute on an element of the signature RHS. - @@ -40,7 +62,7 @@ data FlowVertex = | rhsInhVertex sigName::String attrName::String {-- - - A vertex representing a local equation. i.e. forward, local attribute, production + - A vertex representing a local equation. i.e. local attribute, production - attribute, etc. Note that this may be defined for MORE than just those with - decorable type!! (e.g. local foo :: String will appear!) - This is because the dependencies for these local equations still matter, of coursee. @@ -49,6 +71,24 @@ data FlowVertex = -} | localEqVertex fName::String +{-- + - A vertex representing the outer dependencies of a local equation. i.e. local, + - production attribute, etc. This should only be defined for decorable trees. + - + - @param fName the full name of the NTA/FWD being defined + -} +| localOuterEqVertex fName::String + +{-- + - A vertex representing the outer dependencies of a translation attribute, + - just like localOuterEqVertex. The regular eq vertex with the full deps for + - taking a reference is just base.synVertex(transAttr) + - + - @param base the vertex type of the tree with the translation attribute. + - @param transAttr the name of the translation attribute + -} +| transAttrOuterEqVertex base::VertexType transAttr::String + {-- - A vertex representing a synthesized attribute on a local equation. i.e. forward, local - attribute, production attribute, etc. Note this this implies the equation @@ -69,9 +109,53 @@ data FlowVertex = -} | localInhVertex fName::String attrName::String +{-- + - A vertex representing the forward tree. + - Note that this has only the deps for the outer node; + - lhsSynVertex("forward") has the deps for taking a reference to the forward tree. + -} +| forwardOuterEqVertex + +{-- + - A vertex representing a synthesized attribute on the forward tree. + - + - @param attrName the full name of the attribute on the forward + -} +| forwardSynVertex attrName::String + +{-- + - A vertex representing an inherited attribute on the forward tree. + - + - @param attrName the full name of the attribute on the forward + -} +| forwardInhVertex attrName::String + +{-- + - A vertex representing the tree that forwarded to this one. + - Only appears in prods with signature sharing. + -} +| forwardParentEqVertex + +{-- + - A vertex representing a synthesized attribute on the parent that forwarded to this one. + - Only appears in prods with signature sharing. + - + - @param attrName the full name of the attribute on that tree + -} +| forwardParentSynVertex attrName::String + +{-- + - A vertex representing an inherited attribute on the parent that forwarded to this one. + - Only appears in prods with signature sharing. + - + - @param attrName the full name of the attribute on that tree + -} +| forwardParentInhVertex attrName::String + {-- - A vertex representing an anonymous equation. i.e. a 'decorate e with..' - expression, this production will represent 'e'. + - Note we don't bother distinguishing outer eq deps for anon equations. - - @param fName an anonymous name (typically generated with genInt) -} @@ -95,6 +179,25 @@ data FlowVertex = -} | anonInhVertex fName::String attrName::String +{-- + - A vertex corresponding to a sub-term of an expression with a known decoration site. + - e.g. 'local foo::Foo = bar(baz(@x), y.trans);', we need to capture the dependencies of y.trans + - + - @param parent the decoration site of the enclosing term + - @param prodName the full name of the applied production + - @param sigName the name given to the corresponding child + -} +| subtermEqVertex parent::VertexType prodName::String sigName::String + +{-- + - A vertex corresponding to the outer dependencies of a sub-term of an expression with a known decoration site. + - + - @param parent the decoration site of the enclosing term + - @param prodName the full name of the applied production + - @param sigName the name given to the corresponding child + -} +| subtermOuterEqVertex parent::VertexType prodName::String sigName::String + {-- - A vertex corresponding to a synthesized attribute on a sub-term of an expression with a known decoration site. - e.g. 'local foo::Foo = bar(baz(@x));', we need a vertex for the attributes on baz(@x) @@ -120,15 +223,49 @@ data FlowVertex = | subtermInhVertex parent::VertexType prodName::String sigName::String attrName::String ; -derive Eq, Ord on FlowVertex; +attribute vertexName occurs on FlowVertex; +aspect vertexName on FlowVertex of +| lhsEqVertex() -> "!" +| lhsSynVertex(attrName) -> attrName +| lhsInhVertex(attrName) -> attrName +| rhsEqVertex(sigName) -> sigName ++ "!" +| rhsOuterEqVertex(sigName) -> sigName ++ "~" +| rhsSynVertex(sigName, attrName) -> s"${sigName}.${attrName}" +| rhsInhVertex(sigName, attrName) -> s"${sigName}.${attrName}" +| localEqVertex(fName) -> fName ++ "!" +| localOuterEqVertex(fName) -> fName ++ "~" +| localSynVertex(fName, attrName) -> s"${fName}.${attrName}" +| localInhVertex(fName, attrName) -> s"${fName}.${attrName}" +| transAttrOuterEqVertex(vt, fName) -> s"${vt.vertexName}.${fName}~" +| forwardOuterEqVertex() -> "forward~" +| forwardSynVertex(attrName) -> s"forward.${attrName}" +| forwardInhVertex(attrName) -> s"forward.${attrName}" +| forwardParentEqVertex() -> "forwardParent!" +| forwardParentSynVertex(attrName) -> s"forwardParent.${attrName}" +| forwardParentInhVertex(attrName) -> s"forwardParent.${attrName}" +| anonEqVertex(fName) -> fName +| anonSynVertex(fName, attrName) -> s"${fName}.${attrName}" +| anonInhVertex(fName, attrName) -> s"${fName}.${attrName}" +| subtermEqVertex(parent, prodName, sigName) -> + s"${parent.vertexName}[${prodName}:${sigName}]!" +| subtermOuterEqVertex(parent, prodName, sigName) -> + s"${parent.vertexName}[${prodName}:${sigName}]~" +| subtermSynVertex(parent, prodName, sigName, attrName) -> + s"${parent.vertexName}[${prodName}:${sigName}].${attrName}" +| subtermInhVertex(parent, prodName, sigName, attrName) -> + s"${parent.vertexName}[${prodName}:${sigName}].${attrName}" +end; +--derive Eq, Ord on FlowVertex; --- The forward equation for this production. We do not care to distinguish it. -fun forwardEqVertex FlowVertex ::= = localEqVertex("forward"); +-- More efficient equality and ordering by just comparing vertex names: +instance Eq FlowVertex { + eq = \ v1::FlowVertex v2::FlowVertex -> v1.vertexName == v2.vertexName; +} --- An attribute on the forward node for this production -fun forwardSynVertex FlowVertex ::= attrName::String = localSynVertex("forward", attrName); -fun forwardInhVertex FlowVertex ::= attrName::String = localInhVertex("forward", attrName); +instance Ord FlowVertex { + compare = \ v1::FlowVertex v2::FlowVertex -> compare(v1.vertexName, v2.vertexName); +} --- An attribute on the production that forwarded to this one -fun forwardParentSynVertex FlowVertex ::= attrName::String = localSynVertex("forwardParent", attrName); +-- Shorthand for the forward equation vertex +global forwardEqVertex :: FlowVertex = lhsSynVertex("forward"); diff --git a/grammars/silver/compiler/definition/flow/ast/VertexType.sv b/grammars/silver/compiler/definition/flow/ast/VertexType.sv index 5ea2aba09..6c4376bc1 100644 --- a/grammars/silver/compiler/definition/flow/ast/VertexType.sv +++ b/grammars/silver/compiler/definition/flow/ast/VertexType.sv @@ -1,52 +1,76 @@ grammar silver:compiler:definition:flow:ast; +imports silver:langutil only unparse; + {-- - A "classification" of FlowVertex that has ways to map attributes to vertexes. - - Quick reference: - - lhsVertexType, rhsVertexType(sigName), localVertexType(fName), - - forwardVertexType, anonVertexType(x) + - lhsVertexType(), rhsVertexType(sigName), localVertexType(fName), + - transAttrVertexType(v, transAttr), forwardVertexType(), anonVertexType(x), + - anonScrutineeVertexType(x), subtermVertexType(parent, prodName, sigName) -} data nonterminal VertexType with - vertexName, vertexPP, isInhDefVertex, - synVertex, inhVertex, fwdVertex, eqVertex; + vertexName, vertexPP, isInhDefVertex, isFlowTypeDepVertex, + synVertex, inhVertex, eqVertex, outerEqVertex, + eqDeps, outerEqDeps, synDeps, inhDeps, fwdDeps; derive Eq, Ord on VertexType; +{-- Short name of this VertexType -} synthesized attribute vertexName::String; +{-- Expanded representation that indicates the sort of VertexType -} synthesized attribute vertexPP::String; +{-- Can inherited equations be written for this VertexType? -} synthesized attribute isInhDefVertex::Boolean; +{-- Are dependencies on inherited attributes on this VertexType tracked by the flow types? -} +synthesized attribute isFlowTypeDepVertex::Boolean; -{-- FlowVertex for a synthesized attribute for this FlowVertex -} +{-- FlowVertex for a synthesized attribute for this VertexType -} synthesized attribute synVertex :: (FlowVertex ::= String); -{-- FlowVertex for a inherited attribute for this FlowVertex -} +{-- FlowVertex for a inherited attribute for this VertexType -} synthesized attribute inhVertex :: (FlowVertex ::= String); -{-- FlowVertex for the forward flow type for this FlowVertex -} -synthesized attribute fwdVertex :: FlowVertex; -{-- FlowVertex for the equation giving this FlowVertex (there may not be one!) -} -synthesized attribute eqVertex :: [FlowVertex]; - -global lhsVertexType :: VertexType = lhsVertexType_real(); -global forwardVertexType :: VertexType = forwardVertexType_real(); +{-- FlowVertex for the equation giving this VertexType -} +synthesized attribute eqVertex :: FlowVertex; +{-- FlowVertex for the outer dependencies of the equation giving this VertexType -} +synthesized attribute outerEqVertex :: FlowVertex; +{-- FlowVertex dependencies of taking a reference to this VertexType -} +synthesized attribute eqDeps :: [FlowVertex]; +{-- FlowVertex dependencies of constructing the outer node of this VertexType -} +synthesized attribute outerEqDeps :: [FlowVertex]; +{-- FlowVertex dependencies of a synthesized attribute access on this VertexType -} +synthesized attribute synDeps :: ([FlowVertex] ::= String); +{-- FlowVertex dependencies of an inherited attribute access on this VertexType -} +synthesized attribute inhDeps :: ([FlowVertex] ::= String); +{-- FlowVertex dependencies for the forward flow type for this VertexType -} +synthesized attribute fwdDeps :: [FlowVertex]; --- implementation detail, do no use outside this file. -global forwardEqVertex_singleton :: FlowVertex = localEqVertex("forward"); --- forwardEqVertex() == localEqVertex("forward") --- we consider lhsSynVertex("forward") also equivalent, actually. +aspect default production +top::VertexType ::= +{ + top.eqDeps = [top.eqVertex]; + top.outerEqDeps = [top.outerEqVertex]; + top.synDeps = \ attr -> top.synVertex(attr) :: top.outerEqDeps; + top.inhDeps = \ attr -> top.inhVertex(attr) :: top.outerEqDeps; + top.fwdDeps = top.synDeps("forward"); +} {-- - - Represents the vertexes for a production lhs. You can use lhsVertexType instead of this production directly. + - Represents the vertexes for a production lhs. -} -abstract production lhsVertexType_real +abstract production lhsVertexType top::VertexType ::= { top.vertexName = "top"; top.vertexPP = "left-hand side"; top.isInhDefVertex = false; + top.isFlowTypeDepVertex = true; top.synVertex = lhsSynVertex; top.inhVertex = lhsInhVertex; - top.fwdVertex = forwardEqVertex_singleton; - top.eqVertex = []; + top.eqVertex = lhsEqVertex(); + top.outerEqVertex = error("Shouldn't ask for an outerEqVertex on lhsVertexType"); + top.outerEqDeps = []; + top.fwdDeps = [forwardEqVertex]; -- override for better caching } {-- @@ -58,10 +82,11 @@ top::VertexType ::= sigName::String top.vertexName = sigName; top.vertexPP = "child " ++ sigName; top.isInhDefVertex = true; + top.isFlowTypeDepVertex = false; top.synVertex = rhsSynVertex(sigName, _); top.inhVertex = rhsInhVertex(sigName, _); - top.fwdVertex = rhsSynVertex(sigName, "forward"); - top.eqVertex = []; + top.eqVertex = rhsEqVertex(sigName); + top.outerEqVertex = rhsOuterEqVertex(sigName); } {-- @@ -73,10 +98,11 @@ top::VertexType ::= fName::String top.vertexName = fName; top.vertexPP = "local " ++ fName; top.isInhDefVertex = true; + top.isFlowTypeDepVertex = false; top.synVertex = localSynVertex(fName, _); top.inhVertex = localInhVertex(fName, _); - top.fwdVertex = localSynVertex(fName, "forward"); - top.eqVertex = [localEqVertex(fName)]; + top.eqVertex = localEqVertex(fName); + top.outerEqVertex = localOuterEqVertex(fName); } {-- @@ -88,54 +114,79 @@ top::VertexType ::= v::VertexType transAttr::String top.vertexName = s"${v.vertexName}.${transAttr}"; top.vertexPP = s"translation attribute ${transAttr} of ${v.vertexPP}"; top.isInhDefVertex = v.isInhDefVertex; + top.isFlowTypeDepVertex = v.isFlowTypeDepVertex; top.synVertex = \ attr::String -> v.synVertex(s"${transAttr}.${attr}"); top.inhVertex = \ attr::String -> v.inhVertex(s"${transAttr}.${attr}"); - top.fwdVertex = v.synVertex(s"${transAttr}.forward"); - top.eqVertex = v.synVertex(transAttr) :: v.eqVertex; + top.eqVertex = v.synVertex(transAttr); + top.outerEqVertex = transAttrOuterEqVertex(v, transAttr); + top.eqDeps = v.synDeps(transAttr); + top.outerEqDeps = top.outerEqVertex :: v.outerEqDeps; } {-- - - Represents the vertexes for the forward of a production. You can use forwardVertexType instead of this production directly. + - Represents the vertexes for the forward of a production. -} -abstract production forwardVertexType_real +abstract production forwardVertexType top::VertexType ::= { top.vertexName = "forward"; top.vertexPP = "forward"; top.isInhDefVertex = true; + top.isFlowTypeDepVertex = false; top.synVertex = forwardSynVertex; top.inhVertex = forwardInhVertex; - top.fwdVertex = forwardSynVertex("forward"); - top.eqVertex = [forwardEqVertex_singleton]; + top.eqVertex = forwardEqVertex; + top.outerEqVertex = forwardOuterEqVertex(); } abstract production forwardParentVertexType top::VertexType ::= { + -- TODO: Deps on these vertices need to introduce deps on the forward vertices of the remote prod + -- that forwarded to this sig sharing prod, even when there are override eqs. top.vertexName = "forwardParent"; top.vertexPP = "forward parent"; top.isInhDefVertex = false; + top.isFlowTypeDepVertex = true; top.synVertex = forwardParentSynVertex; - top.inhVertex = lhsInhVertex; - -- The forward of the forward parent is the LHS of this production, which doesn't have a vertex! - -- This should never really be consulted in practice. - top.fwdVertex = localEqVertex("__lhs"); - top.eqVertex = []; + top.inhVertex = forwardParentInhVertex; + top.eqVertex = forwardParentEqVertex(); + top.outerEqVertex = error("Shouldn't ask for an outerEqVertex on forwardParentVertexType"); + top.outerEqDeps = []; + -- The forward of the forward parent is the LHS of this production + top.fwdDeps = [lhsEqVertex()]; } {-- - Represents the vertexes for anonymous vertex types somewhere within a production (e.g. 'decorate with' expressions). -} abstract production anonVertexType -top::VertexType ::= x::String +top::VertexType ::= x::String grammarName::String loc::Location { - top.vertexName = x; - top.vertexPP = s"anonymous decoration site ${x}"; + top.vertexName = s"${grammarName}:${loc.unparse}:${x}"; + top.vertexPP = s"anonymous decoration site at ${grammarName}:${loc.unparse}"; top.isInhDefVertex = true; + top.isFlowTypeDepVertex = false; top.synVertex = anonSynVertex(x, _); top.inhVertex = anonInhVertex(x, _); - top.fwdVertex = anonSynVertex(x, "forward"); - top.eqVertex = [anonEqVertex(x)]; + top.eqVertex = anonEqVertex(x); + top.outerEqVertex = anonEqVertex(x); -- We don't distinguish the outer eq for anon vertexes +} + +{-- + - Represents the vertexes for the scrutinee when pattern matching on a reference that lacks a vertex type. + -} +abstract production anonScrutineeVertexType +top::VertexType ::= x::String grammarName::String loc::Location +{ + top.vertexName = s"${grammarName}:${loc.unparse}:${x}"; + top.vertexPP = s"anonymous scrutinee ${grammarName}:${loc.unparse}"; + top.isInhDefVertex = false; + top.isFlowTypeDepVertex = false; + top.synVertex = anonSynVertex(top.vertexName, _); + top.inhVertex = anonInhVertex(top.vertexName, _); + top.eqVertex = anonEqVertex(top.vertexName); + top.outerEqVertex = anonEqVertex(top.vertexName); -- We don't distinguish the outer eq for anon vertexes } {-- @@ -147,8 +198,9 @@ top::VertexType ::= parent::VertexType prodName::String sigName::String top.vertexName = s"${parent.vertexName}[${prodName}:${sigName}]"; top.vertexPP = top.vertexName; -- Shouldn't appear in error messages? Gets too long to spell out anyway. top.isInhDefVertex = false; + top.isFlowTypeDepVertex = false; top.synVertex = subtermSynVertex(parent, prodName, sigName, _); top.inhVertex = subtermInhVertex(parent, prodName, sigName, _); - top.fwdVertex = subtermSynVertex(parent, prodName, sigName, "forward"); - top.eqVertex = []; + top.eqVertex = subtermEqVertex(parent, prodName, sigName); + top.outerEqVertex = subtermOuterEqVertex(parent, prodName, sigName); } diff --git a/grammars/silver/compiler/definition/flow/driver/DumpGraph.sv b/grammars/silver/compiler/definition/flow/driver/DumpGraph.sv index 9b0420089..eb700f44b 100644 --- a/grammars/silver/compiler/definition/flow/driver/DumpGraph.sv +++ b/grammars/silver/compiler/definition/flow/driver/DumpGraph.sv @@ -7,11 +7,13 @@ import silver:util:treemap as rtm; -- This isn't exactly a warning, but it can live here for now... synthesized attribute dumpFlowGraph :: Boolean occurs on CmdArgs; +synthesized attribute dumpProds :: [String] occurs on CmdArgs; aspect production endCmdArgs top::CmdArgs ::= _ { top.dumpFlowGraph = false; + top.dumpProds = []; } abstract production dumpFlowGraphFlag top::CmdArgs ::= rest::CmdArgs @@ -19,6 +21,13 @@ top::CmdArgs ::= rest::CmdArgs top.dumpFlowGraph = true; forwards to @rest; } +abstract production dumpProdsFlag +top::CmdArgs ::= prods::String rest::CmdArgs +{ + top.dumpFlowGraph = true; + top.dumpProds = explode(",", prods) ++ rest.dumpProds; + forwards to @rest; +} aspect function parseArgs Either ::= args::[String] { @@ -29,6 +38,9 @@ Either ::= args::[String] , flagSpec(name="--dump-flow-graphs", paramString=nothing(), help="a typo of --dump-flow-graph", flagParser=flag(dumpFlowGraphFlag)) + , flagSpec(name="--dump-prods", paramString=just(""), + help="productions to include in the flow graph dump (comma-separated)", + flagParser=option(dumpProdsFlag)) ]; -- not omitting descriptions deliberately! } @@ -36,9 +48,14 @@ Either ::= args::[String] aspect production compilation top::Compilation ::= g::Grammars _ _ a::Decorated CmdArgs benv::BuildEnv { + local includeInDump :: (Boolean ::= ProductionGraph) = \ pg::ProductionGraph -> + null(a.dumpProds) || any(map(endsWith(_, pg.prod), a.dumpProds)); top.postOps <- if a.dumpFlowGraph - then [dumpFlowGraphAction(prodGraph, rtm:values(finalGraphEnv), unList(rtm:toList(flowTypes)))] + then [dumpFlowGraphAction( + filter(includeInDump, prodGraph), + filter(includeInDump, rtm:values(finalGraphEnv)), + unList(rtm:toList(flowTypes)))] else []; } @@ -64,8 +81,11 @@ top::DriverAction ::= prodGraph::[ProductionGraph] finalGraph::[ProductionGraph { top.run = do { eprintln("Generating flow graphs"); - writeFile("flow-deps-transitive.dot", "digraph flow {\n" ++ generateDotGraph(finalGraph) ++ "}"); - writeFile("flow-deps-direct.dot", "digraph flow {\n" ++ generateDotGraph(prodGraph) ++ "}"); + writeFile("stitch-points.txt", generateStitchPointsDump(prodGraph)); + writeDotGraphs("flow-deps-direct.dot", prodGraph); + writeTileDotGraphs("flow-deps-tile-direct.dot", prodGraph); + writeDotGraphs("flow-deps-transitive.dot", finalGraph); + writeTileDotGraphs("flow-deps-tile.dot", finalGraph); writeFile("flow-types.dot", "digraph flow {\n" ++ generateFlowDotGraph(flowTypes) ++ "}"); return 0; }; @@ -99,16 +119,28 @@ String ::= nt::String attr::String fun makeNtFlow String ::= nt::String e::Pair = "\"" ++ nt ++ "/" ++ e.fst ++ "\" -> \"" ++ nt ++ "/" ++ e.snd ++ "\";\n"; -fun generateDotGraph String ::= specs::[ProductionGraph] = - case specs of - | [] -> "" - | productionGraph(prod, _, _, graph, suspect, _) :: t -> - "subgraph \"cluster:" ++ prod ++ "\" {\n" ++ - implode("", map(makeDotArrow(prod, _, ""), g:toList(graph))) ++ - implode("", map(makeDotArrow(prod, _, " [style=dotted]"), suspect)) ++ - "}\n" ++ - generateDotGraph(t) - end; +fun writeDotGraphs IO ::= fileName::String specs::[ProductionGraph] = do { + writeFile(fileName, "digraph flow {\n"); + traverse_(\ spec::ProductionGraph -> + appendFile(fileName, + "subgraph \"cluster:" ++ spec.prod ++ "\" {\n" ++ + implode("", map(makeDotArrow(spec.prod, _, ""), g:toList(spec.graph))) ++ + implode("", map(makeDotArrow(spec.prod, _, " [style=dotted]"), spec.suspectEdges)) ++ + "}\n"), + specs); + appendFile(fileName, "}\n"); +}; + +fun writeTileDotGraphs IO ::= fileName::String specs::[ProductionGraph] = do { + writeFile(fileName, "digraph flow {\n"); + traverse_(\ spec::ProductionGraph -> + appendFile(fileName, + "subgraph \"cluster:" ++ spec.prod ++ "\" {\n" ++ + implode("", map(makeDotArrow(spec.prod, _, ""), g:toList(spec.tileGraph))) ++ + "}\n"), + specs); + appendFile(fileName, "}\n"); +}; -- "production/flowvertex" -> "production/flowvertex" fun makeDotArrow String ::= p::String e::(FlowVertex, FlowVertex) style::String = @@ -121,66 +153,53 @@ fun makeDotArrow String ::= p::String e::(FlowVertex, FlowVertex) style::String -} synthesized attribute dotName :: String occurs on FlowVertex; -aspect production lhsSynVertex -top::FlowVertex ::= attrName::String -{ - top.dotName = attrName; -} -aspect production lhsInhVertex -top::FlowVertex ::= attrName::String -{ - top.dotName = attrName; -} -aspect production rhsSynVertex -top::FlowVertex ::= sigName::String attrName::String -{ - top.dotName = sigName ++ "/" ++ attrName; -} -aspect production rhsInhVertex -top::FlowVertex ::= sigName::String attrName::String -{ - top.dotName = sigName ++ "/" ++ attrName; -} -aspect production localEqVertex -top::FlowVertex ::= fName::String -{ - top.dotName = fName; -} -aspect production localSynVertex -top::FlowVertex ::= fName::String attrName::String -{ - top.dotName = fName ++ "/" ++ attrName; -} -aspect production localInhVertex -top::FlowVertex ::= fName::String attrName::String -{ - top.dotName = fName ++ "/" ++ attrName; -} -aspect production anonEqVertex -top::FlowVertex ::= fName::String -{ - top.dotName = fName; -} -aspect production anonSynVertex -top::FlowVertex ::= fName::String attrName::String -{ - top.dotName = fName ++ "/" ++ attrName; -} -aspect production anonInhVertex -top::FlowVertex ::= fName::String attrName::String -{ - top.dotName = fName ++ "/" ++ attrName; -} -aspect production subtermSynVertex -top::FlowVertex ::= parent::VertexType prodName::String sigName::String attrName::String -{ - top.dotName = parent.synVertex(prodName ++ "@" ++ sigName ++ "/" ++ attrName).dotName; -- Hack! -} -aspect production subtermInhVertex -top::FlowVertex ::= parent::VertexType prodName::String sigName::String attrName::String -{ - top.dotName = parent.inhVertex(prodName ++ "@" ++ sigName ++ "/" ++ attrName).dotName; -- Hack! -} - - - +aspect dotName on FlowVertex of +| lhsEqVertex() -> "!" +| lhsSynVertex(attrName) -> attrName +| lhsInhVertex(attrName) -> attrName +| rhsEqVertex(sigName) -> sigName ++ "!" +| rhsOuterEqVertex(sigName) -> sigName ++ "~" +| rhsSynVertex(sigName, attrName) -> sigName ++ "/" ++ attrName +| rhsInhVertex(sigName, attrName) -> sigName ++ "/" ++ attrName +| localEqVertex(fName) -> fName ++ "!" +| localOuterEqVertex(fName) -> fName ++ "~" +| localSynVertex(fName, attrName) -> fName ++ "/" ++ attrName +| localInhVertex(fName, attrName) -> fName ++ "/" ++ attrName +| transAttrOuterEqVertex(vt, fName) -> vt.synVertex(fName).dotName ++ "~" +| forwardOuterEqVertex() -> "forward~" +| forwardSynVertex(attrName) -> "forward/" ++ attrName +| forwardInhVertex(attrName) -> "forward/" ++ attrName +| forwardParentEqVertex() -> "forwardParent!" +| forwardParentSynVertex(attrName) -> "forwardParent/" ++ attrName +| forwardParentInhVertex(attrName) -> "forwardParent/" ++ attrName +| anonEqVertex(fName) -> fName ++ "!" +| anonSynVertex(fName, attrName) -> fName ++ "/" ++ attrName +| anonInhVertex(fName, attrName) -> fName ++ "/" ++ attrName +| subtermEqVertex(parent, prodName, sigName) -> + parent.synVertex(prodName ++ "@" ++ sigName ++ "!").dotName -- Hack! +| subtermOuterEqVertex(parent, prodName, sigName) -> + parent.synVertex(prodName ++ "@" ++ sigName ++ "~").dotName -- Hack! +| subtermSynVertex(parent, prodName, sigName, attrName) -> + parent.synVertex(prodName ++ "@" ++ sigName ++ "/" ++ attrName).dotName -- Hack! +| subtermInhVertex(parent, prodName, sigName, attrName) -> + parent.synVertex(prodName ++ "@" ++ sigName ++ "/" ++ attrName).dotName -- Hack! +end; + +fun generateStitchPointsDump String ::= specs::[ProductionGraph] = + flatMap(dumpGraphStitchPoints, specs); + +fun dumpGraphStitchPoints String ::= g::ProductionGraph = + s"${g.prod}\n${flatMap((.showStitchPoint), g.stitchPoints)}" ++ + (if null(g.sigNtStitchPoints) then "" + else s"from signature nts\n${flatMap((.showStitchPoint), g.sigNtStitchPoints)}") ++ + "\n"; + +synthesized attribute showStitchPoint :: String occurs on StitchPoint; +aspect showStitchPoint on StitchPoint of +| nonterminalStitchPoint(nt, vertexType) -> + s"\tnonterminal ${nt} at ${vertexType.vertexName}\n" +| projectionStitchPoint(prod, sourceType, targetType, prodType, attrs) -> + s"\tprojection ${prod}@${prodType.vertexName} at ${sourceType.vertexName}, ${targetType.vertexName}\n\t\tattrs ${implode(", ", attrs)}\n" +| tileStitchPoint(prod, parentType) -> + s"\ttile ${prod} at ${parentType.vertexName}\n" +end; diff --git a/grammars/silver/compiler/definition/flow/driver/FlowGraph.sv b/grammars/silver/compiler/definition/flow/driver/FlowGraph.sv index c6ea46b21..d79348bcd 100644 --- a/grammars/silver/compiler/definition/flow/driver/FlowGraph.sv +++ b/grammars/silver/compiler/definition/flow/driver/FlowGraph.sv @@ -1,5 +1,7 @@ grammar silver:compiler:definition:flow:driver; +import silver:util:idcache as i; + type FlowType = g:Graph; function findFlowType @@ -21,12 +23,27 @@ function expandGraph { -- look up each vertex, uniq it down. local initial :: set:Set = - set:add(v, foldr(set:union, set:empty(), map(e.edgeMap, v))); + set:add(v, foldr(set:union, set:emptyWith(compareVertexId), map(e.edgeMap, v))); return set:toList(expandSuspectEdges(set:toList(initial), initial, e)); } fun onlyLhsInh set:Set ::= s::[FlowVertex] = set:add(filterLhsInh(s), set:empty()); +fun expandTileGraphSigDeps +set:Set ::= v::[FlowVertex] rhsNames::[String] g::ProductionGraph = + set:filter(isSigVertex(rhsNames, _), + set:add(v, flatMap(g.tileEdgeMap, v))); + +fun isSigVertex Boolean ::= rhsNames::[String] v::FlowVertex = + case v of + | lhsSynVertex(_) -> true + | lhsInhVertex(_) -> true + | rhsEqVertex(sigName) -> contains(sigName, rhsNames) + | rhsSynVertex(sigName, _) -> contains(sigName, rhsNames) + | rhsInhVertex(sigName, _) -> contains(sigName, rhsNames) + | _ -> false + end; + -- suspect edges are not in the standard graph, so iteratively add them -- call like expandSuspectEdges(p.edges.toList, p.edges, p) function expandSuspectEdges @@ -61,17 +78,15 @@ fun isLhsInhSet Boolean ::= v::FlowVertex inhSet::set:Set = | _ -> false end; -fun createFlowGraph g:Graph ::= l::[(FlowVertex, FlowVertex)] = g:add(l, g:empty()); - -fun extendFlowGraph g:Graph ::= l::[(FlowVertex, FlowVertex)] g::g:Graph = - g:add(l, g); +fun createFlowGraph g:Graph ::= l::[(FlowVertex, FlowVertex)] = + g:transitiveClosure(g:add(l, g:emptyWith(compareVertexId))); -fun transitiveClose -g:Graph ::= - graph::g:Graph = g:transitiveClosure(graph); -fun repairClosure -g:Graph ::= - newEdges::[(FlowVertex, FlowVertex)] - graph::g:Graph = g:repairClosure(newEdges, graph); +global vertexCache::i:IdCache = i:empty(); +synthesized attribute vertexId::Integer occurs on FlowVertex; +aspect default production +top::FlowVertex ::= +{ top.vertexId = i:lookup(top, vertexCache); } +fun compareVertexId Integer ::= a::FlowVertex b::FlowVertex = + a.vertexId - b.vertexId; diff --git a/grammars/silver/compiler/definition/flow/driver/FlowTypes.sv b/grammars/silver/compiler/definition/flow/driver/FlowTypes.sv index e29c350e0..b358a89a1 100644 --- a/grammars/silver/compiler/definition/flow/driver/FlowTypes.sv +++ b/grammars/silver/compiler/definition/flow/driver/FlowTypes.sv @@ -19,9 +19,12 @@ type NtName = String; function computeInitialFlowTypes EnvTree ::= specDefs::[(String, String, [String], [String])] { - -- We don't care what flow specs reference what + -- We don't care what flow specs reference what. + -- Also, exclude specs for 'decorate' which isn't a real attribute. local dropRefs::[(String, String, [String])] = - map(\ d::(String, String, [String], [String]) -> (d.1, d.2, d.3), specDefs); + filterMap(\ d::(String, String, [String], [String]) -> + if d.2 == "decorate" then nothing() else just((d.1, d.2, d.3)), + specDefs); local specs :: [(NtName, [(String, [String])])] = ntListCoalesce(groupBy(ntListEq, sortBy(ntListLte, dropRefs))); @@ -29,14 +32,12 @@ EnvTree ::= specDefs::[(String, String, [String], [String])] return rtm:add(map(initialFlowType, specs), rtm:empty()); } fun initialFlowType Pair ::= x::(NtName, [(String, [String])]) = - (x.fst, g:add(flatMap(toFlatEdges, x.snd), g:empty())); + (x.fst, g:add(concat(unzipWith(zipFst, x.snd)), g:empty())); fun ntListLte Boolean ::= a::Pair b::Pair = a.fst <= b.fst; fun ntListEq Boolean ::= a::Pair b::Pair = a.fst == b.fst; fun ntListCoalesce [(NtName, [(String, [String])])] ::= l::[[(NtName, String, [String])]] = if null(l) then [] else (head(head(l)).fst, map(snd, head(l))) :: ntListCoalesce(tail(l)); -fun toFlatEdges [Pair] ::= x::Pair = - map(pair(fst=x.fst, snd=_), x.snd); fun runFlowTypeInference (EnvTree, EnvTree) ::= @@ -70,7 +71,8 @@ fun fullySolveFlowTypes InferState<()> ::= prods::[ProdName] = do { }; {-- - - Update a production graph using the current flow types. + - Update a production graph using the current flow types and graphs, + - including tile graphs and stitch points. -} production updateProdGraph top::InferState ::= prod::ProdName @@ -95,16 +97,15 @@ top::InferState<()> ::= prod::ProdName local graph :: ProductionGraph = findProductionGraph(prod, top.stateIn.1); local currentFlowType :: FlowType = findFlowType(graph.lhsNt, top.stateIn.2); local newFlowType :: FlowType = g:add( - flatMap(expandVertexFilterTo(_, graph), graph.flowTypeVertexes), + flatMap(expandVertexFilterTo(_, graph), graph.flowTypeAttrs), currentFlowType); top.stateOut = (top.stateIn.1, rtm:update(graph.lhsNt, [newFlowType], top.stateIn.2)); top.stateVal = (); } --- Expand 'ver' using 'graph', then filter down to just those in 'inhs' -fun expandVertexFilterTo [(String, String)] ::= ver::FlowVertex graph::ProductionGraph = - map(pair(fst=ver.flowTypeName, snd=_), - filterLhsInh(set:toList(graph.edgeMap(ver)))); +-- Expand 'lhsSynVertex(syn)' using 'graph', then filter down to just those in 'inhs' +fun expandVertexFilterTo [(String, String)] ::= syn::String graph::ProductionGraph = + zipFst(syn, filterLhsInh(set:toList(graph.edgeMap(lhsSynVertex(syn))))); {-- - Filters vertexes down to just the names of inherited attributes on the LHS @@ -122,70 +123,3 @@ fun collectInhs [String] ::= f::FlowVertex = | lhsInhVertex(a) -> [a] | _ -> [] end; - - -{-- - - Flow type lookup names for vertices - -} -synthesized attribute flowTypeName :: String occurs on FlowVertex; - -aspect production lhsSynVertex -top::FlowVertex ::= attrName::String -{ - top.flowTypeName = attrName; -} -aspect production lhsInhVertex -top::FlowVertex ::= attrName::String -{ - top.flowTypeName = error("Internal compiler error: shouldn't be solving flow types for inherited attributes?"); -} -aspect production rhsSynVertex -top::FlowVertex ::= sigName::String attrName::String -{ - top.flowTypeName = error("Internal compiler error: shouldn't be solving flow types for child synthesized attributes?"); -} -aspect production rhsInhVertex -top::FlowVertex ::= sigName::String attrName::String -{ - top.flowTypeName = error("Internal compiler error: shouldn't be solving flow types for child inherited attributes?"); -} -aspect production localEqVertex -top::FlowVertex ::= fName::String -{ - top.flowTypeName = fName; -- secretly only ever "forward" when we actually demand flowTypeName -} -aspect production localSynVertex -top::FlowVertex ::= fName::String attrName::String -{ - top.flowTypeName = error("Internal compiler error: shouldn't be solving flow types for local synthesized attributes?"); -} -aspect production localInhVertex -top::FlowVertex ::= fName::String attrName::String -{ - top.flowTypeName = error("Internal compiler error: shouldn't be solving flow types for local inherited attributes?"); -} -aspect production anonEqVertex -top::FlowVertex ::= fName::String -{ - top.flowTypeName = error("Internal compiler error: shouldn't be solving flow types for anon equations?"); -} -aspect production anonSynVertex -top::FlowVertex ::= fName::String attrName::String -{ - top.flowTypeName = error("Internal compiler error: shouldn't be solving flow types for anon synthesized attributes?"); -} -aspect production anonInhVertex -top::FlowVertex ::= fName::String attrName::String -{ - top.flowTypeName = error("Internal compiler error: shouldn't be solving flow types for anon inherited attributes?"); -} -aspect production subtermSynVertex -top::FlowVertex ::= parent::VertexType prodName::String sigName::String attrName::String -{ - top.flowTypeName = error("Internal compiler error: shouldn't be solving flow types for subterm synthesized attributes?"); -} -aspect production subtermInhVertex -top::FlowVertex ::= parent::VertexType prodName::String sigName::String attrName::String -{ - top.flowTypeName = error("Internal compiler error: shouldn't be solving flow types for subterm inherited attributes?"); -} diff --git a/grammars/silver/compiler/definition/flow/driver/ProductionGraph.sv b/grammars/silver/compiler/definition/flow/driver/ProductionGraph.sv index 81a01b9d6..1c48fa115 100644 --- a/grammars/silver/compiler/definition/flow/driver/ProductionGraph.sv +++ b/grammars/silver/compiler/definition/flow/driver/ProductionGraph.sv @@ -2,89 +2,106 @@ grammar silver:compiler:definition:flow:driver; import silver:compiler:definition:type only isNonterminal, typerep; -data nonterminal ProductionGraph with stitchedGraph, prod, lhsNt, transitiveClosure, edgeMap, suspectEdgeMap, cullSuspect, flowTypeVertexes; +data nonterminal ProductionGraph with + prod, lhsNt, flowTypeAttrs, graph, tileGraph, suspectEdges, + stitchPoints, sigNtStitchPoints, + stitchedGraph, tileEdges, edgeMap, tileEdgeMap, suspectEdgeMap, cullSuspect; + +-- The full name of this production +-- This is, apparently, only used to look up production by name +annotation prod::String; + +-- The full name of the nonterminal this production constructs +-- Only used by solveFlowTypes() +annotation lhsNt::String; + +-- The attributes that we are inferring the flow types of. +-- (Syns and optionally fwd, minus those that are specified.) +-- Used in solveFlowTypes +annotation flowTypeAttrs::[String]; +-- I'd prefer this not exist, but... + +-- The edges within this production +annotation graph::g:Graph; + +-- The edges used for tile stitch points, excluding edges from sigNtStitchPoints. +annotation tileGraph::g:Graph; + +-- Edges that are not permitted to affect their OWN flow types (but perhaps some unknown other flowtypes) +annotation suspectEdges::[(FlowVertex, FlowVertex)]; + +-- Places where current flow types need grafting to this graph to yield a full flow graph +annotation stitchPoints::[StitchPoint]; + +-- Stitch points that arise from signature nonterminals, only used in graph and not tileGraph. +annotation sigNtStitchPoints::[StitchPoint]; --- TODO: future me note: these are good candidates to be "static attributes" maybe? {-- - Given a set of flow types, stitches those edges into the graph for - all stitch points (i.e. children, locals, forward). - Either just a new graph, or nothing if no new edges were added. -} synthesized attribute stitchedGraph :: (Maybe ::= EnvTree EnvTree); + {-- - - Just compute the transitive closure of the edge set + - All edges between LHS and RHS vertices of the tile graph. -} -synthesized attribute transitiveClosure :: ProductionGraph; +synthesized attribute tileEdges :: [(FlowVertex, FlowVertex)]; {-- - Edge mapper -} synthesized attribute edgeMap :: (set:Set ::= FlowVertex); +synthesized attribute tileEdgeMap :: (set:Set ::= FlowVertex); synthesized attribute suspectEdgeMap :: ([FlowVertex] ::= FlowVertex); synthesized attribute cullSuspect :: (Maybe ::= EnvTree); --- This is, apparently, only used to look up production by name -synthesized attribute prod::String; --- Only used by solveFlowTypes() -synthesized attribute lhsNt::String; --- Used in solveFlowTypes -synthesized attribute flowTypeVertexes::[FlowVertex]; --- I'd prefer this not exist, but... - {-- - An object for representing a production's flow graph. - Should ALWAYS be a transitive closure over the edges for 'vertexes'. - - - @param prod The full name of this production - - @param lhsNt The full name of the nonterminal this production constructs - - @param flowTypeVertexes The vertexes that we are inferring the flow types of. - - (Syns and optionally fwd, minus those that are specified.) - - @param graph The edges within this production - - @param suspectEdges Edges that are not permitted to affect their OWN flow types (but perhaps some unknown other flowtypes) - - @param stitchPoints Places where current flow types need grafting to this graph to yield a full flow graph - - - @see constructProductionGraph for how to go about getting an object of this type -} abstract production productionGraph top::ProductionGraph ::= - prod::String - lhsNt::String - flowTypeVertexes::[FlowVertex] - graph::g:Graph - suspectEdges::[(FlowVertex, FlowVertex)] - stitchPoints::[StitchPoint] { - top.prod = prod; - top.lhsNt = lhsNt; - top.flowTypeVertexes = flowTypeVertexes; - top.stitchedGraph = \ flowTypes::EnvTree prodGraphs::EnvTree -> - let newEdges :: [(FlowVertex, FlowVertex)] = - filter(edgeIsNew(_, graph), - flatMap(stitchEdgesFor(_, flowTypes, prodGraphs), stitchPoints)) - in let repaired :: g:Graph = - repairClosure(newEdges, graph) - in if null(newEdges) then nothing() else - just(productionGraph(prod, lhsNt, flowTypeVertexes, repaired, suspectEdges, stitchPoints)) - end end; - - top.transitiveClosure = - let transitiveClosure :: g:Graph = - transitiveClose(graph) + let + edges :: [(FlowVertex, FlowVertex)] = + flatMap(stitchEdgesFor(_, flowTypes, prodGraphs), top.stitchPoints), + sigEdges :: [(FlowVertex, FlowVertex)] = + flatMap(stitchEdgesFor(_, flowTypes, prodGraphs), top.sigNtStitchPoints) + in let + newEdges :: [(FlowVertex, FlowVertex)] = + filter(edgeIsNew(_, top.graph), filter(notSigEqDep, edges) ++ sigEdges), + newTileEdges :: [(FlowVertex, FlowVertex)] = + filter(edgeIsNew(_, top.tileGraph), edges) -- sigEdges not included in tileGraph + in let + repaired :: g:Graph = + g:repairClosure(newEdges, top.graph), + repairedTile :: g:Graph = + g:repairClosure(newTileEdges, top.tileGraph) in - productionGraph(prod, lhsNt, flowTypeVertexes, transitiveClosure, suspectEdges, stitchPoints) end; - - top.edgeMap = g:edgesFrom(_, graph); - top.suspectEdgeMap = lookupAll(_, suspectEdges); + if null(newEdges) && null(newTileEdges) + then nothing() + else just(top(graph=repaired, tileGraph=repairedTile)) + end end end; + + top.tileEdges = filter(isSigEdge, g:toList(top.tileGraph)); + + top.edgeMap = g:edgesFrom(_, top.graph); + top.tileEdgeMap = g:edgesFrom(_, top.tileGraph); + top.suspectEdgeMap = lookupAll(_, top.suspectEdges); top.cullSuspect = \ flowTypes::EnvTree -> + -- Only update the regular graph, suspect edges are initially included in the tile graph. -- this potentially introduces the same edge twice, but that's a nonissue let newEdges :: [(FlowVertex, FlowVertex)] = - flatMap(findAdmissibleEdges(_, graph, findFlowType(lhsNt, flowTypes)), suspectEdges) + flatMap(findAdmissibleEdges(_, top.graph, findFlowType(top.lhsNt, flowTypes)), top.suspectEdges) in let repaired :: g:Graph = - repairClosure(newEdges, graph) + g:repairClosure(newEdges, top.graph) in if null(newEdges) then nothing() else - just(productionGraph(prod, lhsNt, flowTypeVertexes, repaired, suspectEdges, stitchPoints)) + just(top(graph=repaired)) end end; } @@ -163,12 +180,11 @@ ProductionGraph ::= dcl::ValueDclInfo flowEnv::FlowEnv realEnv::Env normalEdges ++ (if nonForwarding then addDefEqs(prod, nt, syns, flowEnv) - else -- This first pair is used sometimes as an alias: - (lhsSynVertex("forward"), forwardEqVertex()) :: - addFwdSynEqs(prod, synsBySuspicion.fst, flowEnv) ++ + else addFwdSynEqs(prod, synsBySuspicion.fst, flowEnv) ++ addFwdInhEqs(prod, inhs, flowEnv)) ++ flatMap(addFwdProdAttrInhEqs(prod, _, inhs, flowEnv), allFwdProdAttrs(defs)) ++ - flatMap(addSharingEqs(flowEnv, realEnv, _), defs); + flatMap(addSharingEqs(flowEnv, realEnv, _), defs) ++ + map(addLhsEqRhsEq, dcl.namedSignature.inputElements); -- (safe, suspect) local synsBySuspicion :: Pair<[String] [String]> = @@ -180,39 +196,39 @@ ProductionGraph ::= dcl::ValueDclInfo flowEnv::FlowEnv realEnv::Env -- If it's forwarding .snd is attributes not known at forwarding time. If it's non, then actually .snd is all attributes. Ignore. if nonForwarding then [] else addFwdSynEqs(prod, synsBySuspicion.snd, flowEnv); - -- RHS and locals and forward. + -- RHS only. + local sigNtStitchPoints :: [StitchPoint] = + flatMap(rhsStitchPoints(realEnv, _), dcl.namedSignature.inputElements); + + -- locals and forward. local stitchPoints :: [StitchPoint] = - flatMap(rhsStitchPoints(realEnv, _), dcl.namedSignature.inputElements) ++ - localStitchPoints(realEnv, nt, defs) ++ + localStitchPoints(realEnv, defs) ++ patternStitchPoints(realEnv, defs) ++ - subtermDecSiteStitchPoints(flowEnv, realEnv, defs) ++ - sigSharingStitchPoints(flowEnv, realEnv, defs) ++ + subtermDecSiteStitchPoints(defs) ++ + sigSharingStitchPoints(realEnv, defs) ++ case dcl.implementedSignature of | just(sig) -> concat(zipWith( - implementedSigStitchPoints(realEnv, _, sig.fullName, _), + implementedSigStitchPoints(realEnv, nt, _, sig.fullName, _), dcl.namedSignature.inputElements, sig.inputElements)) | nothing() -> [] - end ++ - if any(map((.elementShared), dcl.namedSignature.inputElements)) - -- TODO: We could be more precise here by only considering the productions - -- that could have actually forwarded to this one. But that would require - -- introducing a new sort of stitch point. - then nonterminalStitchPoints(realEnv, nt, forwardParentVertexType()) - else []; - - local flowTypeVertexesOverall :: [FlowVertex] = - (if nonForwarding then [] else [forwardEqVertex()]) ++ - map(lhsSynVertex, syns); + end; + local flowTypeSpecs :: [String] = getSpecifiedSynsForNt(nt, flowEnv); - local flowTypeVertexes :: [FlowVertex] = - filter(\x::FlowVertex -> !contains(x.flowTypeName, flowTypeSpecs), flowTypeVertexesOverall); + local flowTypeAttrs :: [String] = + filter(!contains(_, flowTypeSpecs), + (if nonForwarding then [] else ["forward"]) ++ syns); local initialGraph :: g:Graph = - createFlowGraph(fixedEdges); - - return productionGraph(prod, nt, flowTypeVertexes, initialGraph, suspectEdges, stitchPoints).transitiveClosure; + createFlowGraph(filter(notSigEqDep, fixedEdges)); -- deps on LHS/RHS.EQ don't matter in the regular graph + local initialTileGraph :: g:Graph = + createFlowGraph(suspectEdges ++ fixedEdges); + + return productionGraph( + prod=prod, lhsNt=nt, flowTypeAttrs=flowTypeAttrs, + graph=initialGraph, tileGraph=initialTileGraph, suspectEdges=suspectEdges, + stitchPoints=stitchPoints, sigNtStitchPoints=sigNtStitchPoints); } {-- @@ -245,19 +261,27 @@ ProductionGraph ::= ns::NamedSignature flowEnv::FlowEnv realEnv::Env prodEnv: flatMap((.suspectFlowEdges), defs); local initialGraph :: g:Graph = - createFlowGraph(fixedEdges); + createFlowGraph(filter(notSigEqDep, fixedEdges)); -- deps on LHS/RHS.EQ don't matter in the regular graph + -- TODO: functions shouldn't have a tile graph + local initialTileGraph :: g:Graph = + createFlowGraph(suspectEdges ++ fixedEdges); -- suspect edges included in tile graph initially + + -- Just included as regular stitch points. + local sigNtStitchPoints :: [StitchPoint] = []; -- RHS and locals and forward. local stitchPoints :: [StitchPoint] = flatMap(rhsStitchPoints(realEnv, _), ns.inputElements) ++ - localStitchPoints(realEnv, error("functions shouldn't have a forwarding equation?"), defs) ++ + localStitchPoints(realEnv, defs) ++ patternStitchPoints(realEnv, defs) ++ - subtermDecSiteStitchPoints(flowEnv, realEnv, defs); + subtermDecSiteStitchPoints(defs); - local flowTypeVertexes :: [FlowVertex] = []; -- Not used as part of inference. + local flowTypeAttrs :: [String] = []; -- Not used as part of inference. - local g :: ProductionGraph = - productionGraph(prod, nt, flowTypeVertexes, initialGraph, suspectEdges, stitchPoints).transitiveClosure; + local g :: ProductionGraph = productionGraph( + prod=prod, lhsNt=nt, flowTypeAttrs=flowTypeAttrs, + graph=initialGraph, tileGraph=initialTileGraph, suspectEdges=suspectEdges, + stitchPoints=stitchPoints, sigNtStitchPoints=sigNtStitchPoints); return fromMaybe(g, updateGraph(g, prodEnv, ntEnv)); } @@ -288,13 +312,16 @@ ProductionGraph ::= defs::[FlowDef] realEnv::Env prodEnv::EnvTree !contains(x.flowTypeName, flowTypeSpecs), flowTypeVertexesOverall); + local flowTypeAttrs :: [String] = + filter(!contains(_, flowTypeSpecs), syns); - local g :: ProductionGraph = - productionGraph(prod, nt, flowTypeVertexes, initialGraph, suspectEdges, stitchPoints).transitiveClosure; + local g :: ProductionGraph = productionGraph( + prod=prod, lhsNt=nt, flowTypeAttrs=flowTypeAttrs, + graph=initialGraph, tileGraph=initialGraph, suspectEdges=suspectEdges, + stitchPoints=stitchPoints, sigNtStitchPoints=sigNtStitchPoints); -- Optimization: omit the default graph if there are no default equations for the NT. return if null(defs) then [] else [g]; @@ -359,26 +387,28 @@ function constructPhantomProductionGraph -- Those syns that are not part of the host, and so should have edges to fwdeq local extSyns :: [String] = removeAll(getHostSynsFor(nt, flowEnv), syns); - -- The phantom edges: ext syn -> fwd.eq + -- The phantom edges: ext syn -> fwd local phantomEdges :: [(FlowVertex, FlowVertex)] = - -- apparently this alias may sometimes be used. we should get rid of this by making good use of vertex types - (lhsSynVertex("forward"), forwardEqVertex()) :: map(getPhantomEdge, extSyns); -- The stitch point: oddball. LHS stitch point. Normally, the LHS is not. - local stitchPoints :: [StitchPoint] = nonterminalStitchPoints(realEnv, nt, lhsVertexType); + local stitchPoints :: [StitchPoint] = nonterminalStitchPoints(realEnv, nt, lhsVertexType()); + local sigNtStitchPoints :: [StitchPoint] = []; - local flowTypeVertexes :: [FlowVertex] = [forwardEqVertex()] ++ map(lhsSynVertex, syns); + local flowTypeAttrs :: [String] = syns; local initialGraph :: g:Graph = createFlowGraph(phantomEdges); local suspectEdges :: [(FlowVertex, FlowVertex)] = []; - local g::ProductionGraph = - productionGraph("Phantom for " ++ nt, nt, flowTypeVertexes, initialGraph, suspectEdges, stitchPoints).transitiveClosure; + local g :: ProductionGraph = productionGraph( + prod="Phantom for " ++ nt, lhsNt=nt, flowTypeAttrs=flowTypeAttrs, + graph=initialGraph, tileGraph=initialGraph, suspectEdges=suspectEdges, + stitchPoints=stitchPoints, sigNtStitchPoints=sigNtStitchPoints); -- Optimization: omit the phantom graph if there are no extension syns for the NT. return if null(extSyns) then [] else [g]; } + {-- - Constructs a graph for a dispatch signature. - @@ -394,34 +424,65 @@ ProductionGraph ::= ns::NamedSignature flowEnv::FlowEnv realEnv::Env local nt :: NtName = ns.outputElement.typerep.typeName; local defs :: [FlowDef] = getGraphContribsFor(dispatch, flowEnv); - -- The graph has no normal edges, only projection stitch points! - local normalEdges :: [(FlowVertex, FlowVertex)] = []; + local normalEdges :: [(FlowVertex, FlowVertex)] = + flatMap(addDispatchEqs(flowEnv, realEnv, ns, _), defs); local stitchPoints :: [StitchPoint] = - sigSharingStitchPoints(flowEnv, realEnv, defs) ++ -- where this dispatch is applied + sigSharingStitchPoints(realEnv, defs) ++ -- where this dispatch is applied dispatchStitchPoints(flowEnv, realEnv, ns, defs); -- impls of this dispatch + local sigNtStitchPoints :: [StitchPoint] = []; - local flowTypeVertexes :: [FlowVertex] = []; -- Doesn't (directly) affect flow types + local flowTypeAttrs :: [String] = []; -- Doesn't (directly) affect flow types local initialGraph :: g:Graph = createFlowGraph(normalEdges); local suspectEdges :: [(FlowVertex, FlowVertex)] = []; - return productionGraph(dispatch, nt, flowTypeVertexes, initialGraph, suspectEdges, stitchPoints).transitiveClosure; + return productionGraph( + prod=dispatch, lhsNt=nt, flowTypeAttrs=flowTypeAttrs, + graph=initialGraph, tileGraph=initialGraph, suspectEdges=suspectEdges, + stitchPoints=stitchPoints, sigNtStitchPoints=sigNtStitchPoints); } fun getPhantomEdge (FlowVertex, FlowVertex) ::= at::String = - (lhsSynVertex(at), forwardEqVertex()); + (lhsSynVertex(at), forwardEqVertex); + +fun notSigEqDep Boolean ::= e::(FlowVertex, FlowVertex) = + case e of + | (_, lhsEqVertex()) -> false + | (_, rhsEqVertex(_)) -> false + | (_, rhsOuterEqVertex(_)) -> false + | _ -> true + end; + +fun isSigEdge Boolean ::= edge::(FlowVertex, FlowVertex) = + edge.1.isSigVertex && edge.2.isSigVertex; + +synthesized attribute isSigVertex :: Boolean occurs on FlowVertex; +aspect isSigVertex on FlowVertex of +-- Note that deps on lhsEqVertex are not included in tile stitch points, +-- as it is only used to locally collect the deps for taking a reference to the LHS. +| lhsSynVertex(_) -> true +| lhsInhVertex(_) -> true +| rhsEqVertex(_) -> true +| rhsOuterEqVertex(_) -> true +| rhsSynVertex(_, _) -> true +| rhsInhVertex(_, _) -> true +| forwardParentEqVertex() -> true +| forwardParentSynVertex(_) -> true +| forwardParentInhVertex(_) -> true +| _ -> false +end; ---- Begin helpers for fixing up graphs ---------------------------------------- {-- - - Introduces implicit 'lhs.syn -> forward.syn' (& forward.eq) equations. + - Introduces implicit 'lhs.syn -> forward.syn' (& forward.outerEq) equations. - Called twice: once for safe edges, later for SUSPECT edges! -} fun addFwdSynEqs [(FlowVertex, FlowVertex)] ::= prod::ProdName syns::[String] flowEnv::FlowEnv = if null(syns) then [] else (if null(lookupSyn(prod, head(syns), flowEnv)) then [(lhsSynVertex(head(syns)), forwardSynVertex(head(syns))), - (lhsSynVertex(head(syns)), forwardEqVertex())] else []) ++ + (lhsSynVertex(head(syns)), forwardOuterEqVertex())] else []) ++ addFwdSynEqs(prod, tail(syns), flowEnv); {-- - Introduces implicit 'forward.inh = lhs.inh' equations. @@ -443,7 +504,7 @@ fun addFwdProdAttrInhEqs fun allFwdProdAttrs [String] ::= d::[FlowDef] = case d of | [] -> [] - | localEq(_, fN, _, true, true, _) :: rest -> fN :: allFwdProdAttrs(rest) + | localEq(_, fN, _, true, _) :: rest -> fN :: allFwdProdAttrs(rest) | _ :: rest -> allFwdProdAttrs(rest) end; {-- @@ -459,7 +520,7 @@ fun addDefEqs else []) ++ addDefEqs(prod, nt, tail(syns), flowEnv); {-- - - Introduce edges for inherited attributes on shared references to their decoration sites. + - Introduce edges for inh/syn attributes on shared references to/from their decoration sites. -} fun addSharingEqs [(FlowVertex, FlowVertex)] ::= flowEnv::FlowEnv realEnv::Env d::FlowDef = case d of @@ -471,12 +532,43 @@ fun addDefEqs filterMap( \ attr::String -> if vertexHasInhEq(prod, ref, attr, flowEnv) - -- There is an override equation, so the attribute isn't supplied through sharing + -- There is an override equation, so the attribute isn't supplied through sharing. + -- Note that the reverse equation is introduced by the override eq. then nothing() else just((ref.inhVertex(attr), decSite.inhVertex(attr))), - getInhAndInhOnTransAttrsOn(nt, realEnv)) + getInhAndInhOnTransAttrsOn(nt, realEnv)) ++ + map( + \ attr::String -> (decSite.synVertex(attr), ref.synVertex(attr)), + "forward" :: getSynAttrsOn(nt, realEnv)) | _ -> [] end; +{-- + - Introduce edges between lhs/rhs syn/inh and subterm vertices with tile deps. + -} +fun addDispatchEqs +[(FlowVertex, FlowVertex)] ::= flowEnv::FlowEnv realEnv::Env dispatch::NamedSignature d::FlowDef = + case d of + | implFlowDef(_, prod, sigNames, _) -> concat(zipWith( + \ ie::NamedSignatureElement sigName::String -> + (rhsEqVertex(ie.elementName), subtermEqVertex(lhsVertexType(), prod, sigName)) :: + (subtermEqVertex(lhsVertexType(), prod, sigName), rhsEqVertex(ie.elementName)) :: + map(\ attr::String -> + (subtermSynVertex(lhsVertexType(), prod, sigName, attr), rhsSynVertex(ie.elementName, attr)), + "forward" :: getSynAttrsOn(ie.typerep.typeName, realEnv)) ++ + flatMap(\ attr::String -> + [(rhsInhVertex(ie.elementName, attr), subtermInhVertex(lhsVertexType(), prod, sigName, attr)), + -- We always include the subterm -> RHS inh dep, because we are trying to determine + -- what RHS inh are allowable deps in dispatch impl override eqs. + (subtermInhVertex(lhsVertexType(), prod, sigName, attr), rhsInhVertex(ie.elementName, attr))], + getInhAndInhOnTransAttrsOn(ie.typerep.typeName, realEnv)), + dispatch.inputElements, sigNames)) + | _ -> [] + end; +{-- + - Introduce 'lhs.eq -> rhs.eq' edges, to capture the deps of taking a reference to the LHS. + -} +fun addLhsEqRhsEq (FlowVertex, FlowVertex) ::= ne::NamedSignatureElement = + (lhsEqVertex(), rhsEqVertex(ne.elementName)); ---- End helpers for fixing up graphs ------------------------------------------ @@ -492,32 +584,26 @@ fun nonterminalStitchPoints [StitchPoint] ::= realEnv::Env nt::NtName vertexTy case getAttrDcl(o.attrOccurring, realEnv) of | at :: _ when at.isSynthesized && at.isTranslation -> nonterminalStitchPoints( - realEnv, at.typeScheme.typeName, + realEnv, o.attrTypeName, transAttrVertexType(vertexType, o.attrOccurring)) | _ -> [] end, getAttrOccursOn(nt, realEnv)); -fun localStitchPoints [StitchPoint] ::= realEnv::Env nt::NtName ds::[FlowDef] = +fun localStitchPoints [StitchPoint] ::= realEnv::Env ds::[FlowDef] = flatMap(\ d::FlowDef -> case d of - -- We add the forward stitch point here, too! - | fwdEq(_, _, _) -> nonterminalStitchPoints(realEnv, nt, forwardVertexType) - -- Add locals that are nonterminal types. - | localEq(_, fN, tN, true, _, _) -> nonterminalStitchPoints(realEnv, tN, localVertexType(fN)) - -- Add anon decoration sites that are nonterminal types - | anonEq(_, fN, tN, true, _, _) -> nonterminalStitchPoints(realEnv, tN, anonVertexType(fN)) + -- Add stitch points for holes that are nonterminal types + | holeEq(_, tN, true, vt, _) -> nonterminalStitchPoints(realEnv, tN, vt) + | anonScrutineeEq(_, x, tN, true, _, gram, l, _) -> + nonterminalStitchPoints(realEnv, tN, anonScrutineeVertexType(x, gram, l)) -- Ignore all other flow def info | _ -> [] end, ds); -function rhsStitchPoints -[StitchPoint] ::= realEnv::Env rhs::NamedSignatureElement -{ - return - -- We want only NONTERMINAL stitch points! - if rhs.typerep.isNonterminal - then nonterminalStitchPoints(realEnv, rhs.typerep.typeName, rhsVertexType(rhs.elementName)) - else []; -} +fun rhsStitchPoints [StitchPoint] ::= realEnv::Env rhs::NamedSignatureElement = + -- We want only NONTERMINAL stitch points! + if rhs.typerep.isNonterminal + then nonterminalStitchPoints(realEnv, rhs.typerep.typeName, rhsVertexType(rhs.elementName)) + else []; fun patternStitchPoints [StitchPoint] ::= realEnv::Env defs::[FlowDef] = case defs of | [] -> [] @@ -528,58 +614,48 @@ fun patternStitchPoints [StitchPoint] ::= realEnv::Env defs::[FlowDef] = end; fun patVarStitchPoints [StitchPoint] ::= matchProd::String scrutinee::VertexType realEnv::Env var::PatternVarProjection = case var of - | patternVarProjection(child, typeName, patternVar) -> + | patternVarProjection(child, typeName) -> projectionStitchPoint( - matchProd, anonVertexType(patternVar), scrutinee, rhsVertexType(child), + matchProd, subtermVertexType(scrutinee, matchProd, child), scrutinee, rhsVertexType(child), getInhAndInhOnTransAttrsOn(typeName, realEnv)) :: - nonterminalStitchPoints(realEnv, typeName, anonVertexType(patternVar)) + nonterminalStitchPoints(realEnv, typeName, subtermVertexType(scrutinee, matchProd, child)) end; -- deps for subterm vertex of applied prod -fun subtermDecSiteStitchPoints [StitchPoint] ::= flowEnv::FlowEnv realEnv::Env defs::[FlowDef] = +fun subtermDecSiteStitchPoints [StitchPoint] ::= defs::[FlowDef] = flatMap(\ d::FlowDef -> case d of - | subtermDecEq(prodName, parent, termProdName, nt, sigName) -> - [projectionStitchPoint( - termProdName, subtermVertexType(parent, termProdName, sigName), parent, rhsVertexType(sigName), - getInhAndInhOnTransAttrsOn(nt, realEnv))] + | subtermDecEq(_, _, parent, termProdName) -> + [tileStitchPoint(termProdName, parent)] | _ -> [] end, defs); -- deps for prod/dispatch sig, from prods that forwarded to it -fun sigSharingStitchPoints [StitchPoint] ::= flowEnv::FlowEnv realEnv::Env defs::[FlowDef] = +fun sigSharingStitchPoints [StitchPoint] ::= realEnv::Env defs::[FlowDef] = flatMap(\ d::FlowDef -> case d of - | sigShareSite(_, nt, sigName, sourceProd, vt, parent) -> + | sigShareSite(_, sigNt, sigName, sourceProd, vt) -> [projectionStitchPoint( - sourceProd, rhsVertexType(sigName), lhsVertexType, vt, - getInhAndInhOnTransAttrsOn(nt, realEnv))] + sourceProd, rhsVertexType(sigName), lhsVertexType(), vt, + getInhAndInhOnTransAttrsOn(sigNt, realEnv))] | _ -> [] end, defs); -- deps for child of prod, from dispatch sig that prod implements -fun implementedSigStitchPoints [StitchPoint] ::= realEnv::Env ie::NamedSignatureElement prod::String se::NamedSignatureElement = - if ie.typerep.isNonterminal +fun implementedSigStitchPoints [StitchPoint] ::= realEnv::Env nt::NtName ie::NamedSignatureElement dispatch::String se::NamedSignatureElement = + if ie.elementShared || ie.typerep.isNonterminal then [projectionStitchPoint( - prod, rhsVertexType(ie.elementName), lhsVertexType, - rhsVertexType(se.elementName), + dispatch, rhsVertexType(ie.elementName), lhsVertexType(), rhsVertexType(se.elementName), getInhAndInhOnTransAttrsOn(ie.typerep.typeName, realEnv))] else []; -- deps for dispatch sig, from prods that implement it fun dispatchStitchPoints [StitchPoint] ::= flowEnv::FlowEnv realEnv::Env dispatch::NamedSignature defs::[FlowDef] = flatMap(\ d::FlowDef -> case d of - | implFlowDef(_, prod, _) when getValueDcl(prod, realEnv) matches dcl :: _ -> - flatMap(\ ie::NamedSignatureElement -> - if ie.elementDclType.isNonterminal -- Dispatch sigs can't have occurs-on constraints - then [projectionStitchPoint( - prod, rhsVertexType(ie.elementName), lhsVertexType, - rhsVertexType( - head(drop(positionOf(ie.elementName, dispatch.inputNames), dcl.namedSignature.inputNames))), - getInhAndInhOnTransAttrsOn( - lookupSignatureInputElem(ie.elementName, dispatch).typerep.typeName, - realEnv))] - else [], - dispatch.inputElements) + | implFlowDef(_, prod, sigNames, extraSigNts) -> + tileStitchPoint(prod, lhsVertexType()) :: + concat(unzipWith(\ sigName::String nt::String -> + nonterminalStitchPoints(realEnv, nt, subtermVertexType(lhsVertexType(), prod, sigName)), + extraSigNts)) | _ -> [] end, defs); @@ -622,9 +698,15 @@ fun prodGraphToEnv Pair ::= p::ProductionGraph = (p.prod function findAdmissibleEdges [(FlowVertex, FlowVertex)] ::= edge::(FlowVertex, FlowVertex) graph::g:Graph ft::FlowType { + local edgeSyn::String = + case edge.1 of + | lhsSynVertex(at) -> at + | v -> error("Suspect edge source vertex is not lhsSynVertex: " ++ v.vertexName) + end; + -- The current flow type of the edge's source vertex (which is always a thing in the flow type) local currentDeps :: set:Set = - g:edgesFrom(edge.fst.flowTypeName, ft); + g:edgesFrom(edgeSyn, ft); local targetNotSource :: set:Set = set:difference( @@ -636,6 +718,6 @@ function findAdmissibleEdges filter(isLhsInhSet(_, currentDeps), set:toList(targetNotSource)); return if set:isEmpty(currentDeps) then [] -- just a quick optimization. - else map(pair(fst=edge.fst, snd=_), validDeps); + else zipFst(edge.fst, validDeps); } diff --git a/grammars/silver/compiler/definition/flow/driver/StitchPoint.sv b/grammars/silver/compiler/definition/flow/driver/StitchPoint.sv index acf2cd075..61e2ec713 100644 --- a/grammars/silver/compiler/definition/flow/driver/StitchPoint.sv +++ b/grammars/silver/compiler/definition/flow/driver/StitchPoint.sv @@ -34,7 +34,7 @@ top::StitchPoint ::= nt::String vertexType::VertexType - @param prod The production (or dispatch signature) we're projecting - @param sourceType The "vertexType" of this stitchPoint - @param targetType The "vertexType" of where this stitchPoint should proxy to - - @param prodType The "vertexType" in the other production to use + - @param prodType The "vertexType" of 'prod' (e.g. rhsVertex("rhs1", _)) - @param attrs The attributes we want to project to LHS inhs -} abstract production projectionStitchPoint @@ -42,12 +42,12 @@ top::StitchPoint ::= prod::String -- pattern match on this production sourceType::VertexType -- the pattern Variable vertex type targetType::VertexType -- the scruntinee vertex type - prodType::VertexType -- a rhsVertex of 'prod' - attrs::[String] -- all inhs on the NT type of prodType/sourceType + prodType::VertexType -- a vertex type of 'prod' + attrs::[String] -- all inhs on the NT type of sigName/sourceType { top.stitchEdges = \ flowTypes::EnvTree prodGraphs::EnvTree -> flatMap( - projectAttribute(_, sourceType, targetType, prodType, findProductionGraph(prod, prodGraphs)), + projectInh(_, sourceType, targetType, prodType, findProductionGraph(prod, prodGraphs)), attrs); } @@ -56,11 +56,11 @@ top::StitchPoint ::= - @param attr An inherited attribute - @param sourceType "pattern variable" vertex type - @param targetType "scrutinee" vertex type - - @param prodType the "child" vertex type... - - @param prod ...of this production (prodType in here, others in original prod graph) + - @param sigName the child name... + - @param prod ...of this production (sigName in here, others in original prod graph) - @return edges from 'sourceType.inhVertex(attr)' to 'targetType.inhVertex(??)' -} -fun projectAttribute +fun projectInh [(FlowVertex, FlowVertex)] ::= attr::String sourceType::VertexType @@ -76,6 +76,57 @@ fun projectAttribute set:toList(prod.edgeMap(prodType.inhVertex(attr)))))); +{-- + - Given production 'prod :: LHS ::= rhs1::RHS1' + - with all synthesized attributes on 'LHS' as 'syns' + - and all inherited attributes on 'RHS1' as 'inhs'. + - + - Finds all edges for inhs from RHS for each 'childInhs' (here, "rhs1") and 'syns' from LHS + - to LHS INH/RHS SYN/RHS EQ in the production 'prod'. + - + - @param prod The production (or dispatch signature) we're projecting + - @param parentType The decoration site of the tree being constructed + - @param childTypes A map from children in prod to the corresponding vertex types in the current production + -} +abstract production tileStitchPoint +top::StitchPoint ::= + prod::String -- production being constructed + parentType::VertexType -- the parent tree vertex type in the current production +{ + top.stitchEdges = \ flowTypes::EnvTree prodGraphs::EnvTree -> + map(fromSigEdge(prod, parentType, _), + findProductionGraph(prod, prodGraphs).tileEdges); +} + +fun fromSigEdge +(FlowVertex, FlowVertex) ::= prodName::String parentType::VertexType e::(FlowVertex, FlowVertex) = + (fromSigVertex(prodName, parentType, e.1), fromSigVertex(prodName, parentType, e.2)); + +fun fromSigVertex +FlowVertex ::= prodName::String parentType::VertexType v::FlowVertex = + case v of + -- Note that deps on lhsEqVertex are not included in tile stitch points, + -- as it is only used to locally collect the deps for taking a reference to the LHS. + | lhsSynVertex(attr) -> parentType.synVertex(attr) + | lhsInhVertex(attr) -> parentType.inhVertex(attr) + | rhsEqVertex(sigName) -> + subtermEqVertex(parentType, prodName, sigName) + | rhsOuterEqVertex(sigName) -> + subtermOuterEqVertex(parentType, prodName, sigName) + | rhsSynVertex(sigName, attr) -> + subtermSynVertex(parentType, prodName, sigName, attr) + | rhsInhVertex(sigName, attr) -> + subtermInhVertex(parentType, prodName, sigName, attr) + -- Deps on forward parent vertices are only allowed in sig sharing prods, + -- which must be applied in the root of the forward tree, + -- thus forward parent vertices in the remote production always map to the LHS vertices. + | forwardParentEqVertex() -> lhsEqVertex() + | forwardParentSynVertex(attr) -> lhsSynVertex(attr) + | forwardParentInhVertex(attr) -> lhsInhVertex(attr) + | _ -> error("Unexpected non-signature vertex in tileEdges: " ++ v.dotName) + end; + + -- Useful for mapping fun stitchEdgesFor [(FlowVertex, FlowVertex)] ::= sp::StitchPoint ntEnv::EnvTree prodEnv::EnvTree = @@ -86,14 +137,10 @@ fun edgeIsNew Boolean ::= edge::(FlowVertex, FlowVertex) e::g:Graph {-- - Creates edges from a "flow type" source to a "flow type" sink. - - Special case: have to spot forwards and handle them correctly. This stinks. - - @param vt The vertex type we're creating edges within - @param edge pair of syn/fwd and inh. The edge. -} fun flowTypeEdge (FlowVertex, FlowVertex) ::= vt::VertexType edge::Pair = - if edge.fst == "forward" then - (vt.fwdVertex, vt.inhVertex(edge.snd)) - else - (vt.synVertex(edge.fst), vt.inhVertex(edge.snd)); + (vt.synVertex(edge.fst), vt.inhVertex(edge.snd)); diff --git a/grammars/silver/compiler/definition/flow/env/DecSites.sv b/grammars/silver/compiler/definition/flow/env/DecSites.sv index bbfdc048d..d44af91e3 100644 --- a/grammars/silver/compiler/definition/flow/env/DecSites.sv +++ b/grammars/silver/compiler/definition/flow/env/DecSites.sv @@ -26,7 +26,7 @@ DecSiteTree ::= prodName::String vt::VertexType flowEnv::FlowEnv realEnv::Env end; local ntName::String = case vt of - | forwardVertexType_real() -> ns.outputElement.typerep.typeName + | forwardVertexType() -> ns.outputElement.typerep.typeName | localVertexType(fName) when getValueDcl(fName, realEnv) matches dcl :: _ -> dcl.typeScheme.typeName | rhsVertexType(sigName) -> lookupSignatureInputElem(sigName, ns).typerep.typeName | _ -> "" @@ -42,17 +42,16 @@ DecSiteTree ::= prodName::String vt::VertexType flowEnv::FlowEnv realEnv::Env return viaProdVertexDec(prodName, vt, - -- Direct inherited equation at a decoration site (if vt.isInhDefVertex + -- Direct inherited equation at a decoration site then directDec(prodName, vt) + else if vt.isFlowTypeDepVertex + -- Tracked via a flow type, don't need to check here + then alwaysDec() else neverDec()) + case vt of - -- Via flow type - | lhsVertexType_real() -> error("findDecSites: lhsVertexType") -- Should never actually be a decoration site - | transAttrVertexType(lhsVertexType_real(), attrName) -> alwaysDec() -- Via forwarding - | forwardVertexType_real() -> forwardDec(prodName, nothing()) - | localVertexType("forward") -> forwardDec(prodName, nothing()) + | forwardVertexType() -> forwardDec(prodName, nothing()) | localVertexType(fName) when isForwardProdAttr(prodName, fName, flowEnv) -> forwardDec(prodName, just(fName)) -- Via projected remote equation @@ -74,17 +73,21 @@ DecSiteTree ::= prodName::String vt::VertexType flowEnv::FlowEnv realEnv::Env viaProdVertexDec( prodOrSig, rhsVertexType(sigName), product(map(\ prod::(String, [String]) -> - case getTypeDcl(prodOrSig, realEnv) of - | sigDcl :: _ - when drop(positionOf(sigName, sigDcl.dispatchSignature.inputNames), prod.2) - matches sn :: _ -> recurse(prod.1, rhsVertexType(sn)) + case drop(positionOf(sigName, sigDcl.dispatchSignature.inputNames), prod.2) of + | sn :: _ -> recurse(prod.1, rhsVertexType(sn)) | _ -> error(s"findDecSites: Couldn't resolve ${sigName} in ${prodOrSig}") end, -- Look at all the (host) productions that implement this dispatch signature getImplementingProds(prodOrSig, flowEnv)))) - | _ -> error(s"findDecSites: Couldn't find dispatch ${sigName}") + -- TODO: This could be a production in a grammar that isn't in scope in the local environment, + -- e.g. in a modification, that was missed in the above getValueDcl(prodOrSig, realEnv). + -- We really should be using the global env here. + | _ -> hiddenProdDec(prodOrSig, rhsVertexType(sigName)) end) * projectedDepsDec(prodOrSig, sigName, recurse(prodName, parent)) + -- Via the reference set of a pattern match scrutinee + | anonScrutineeVertexType(_, grammarName, l) -> + anonScrutineeRefSetDec(getAnonScrutineeRefSet(prodName, vt.vertexName, flowEnv), grammarName, l) -- Via signature/dispatch sharing | rhsVertexType(sigName) when lookupSignatureInputElem(sigName, ns).elementShared -> product(unzipWith(recurse, @@ -143,7 +146,7 @@ State ::= end; local ntName::String = case vt of - | forwardVertexType_real() -> ns.outputElement.typerep.typeName + | forwardVertexType() -> ns.outputElement.typerep.typeName | localVertexType(fName) when getValueDcl(fName, realEnv) matches dcl :: _ -> dcl.typeScheme.typeName | rhsVertexType(sigName) -> lookupSignatureInputElem(sigName, ns).typerep.typeName | _ -> "" @@ -161,8 +164,7 @@ State ::= viaVertex :: DecSiteTree <- case vt of -- Via forwarding - | forwardVertexType_real() -> pure(forwardDec(prodName, nothing())) - | localVertexType("forward") -> pure(forwardDec(prodName, nothing())) + | forwardVertexType() -> pure(forwardDec(prodName, nothing())) | localVertexType(fName) when isForwardProdAttr(prodName, fName, flowEnv) -> pure(forwardDec(prodName, just(fName))) -- Via projected remote equation @@ -178,18 +180,26 @@ State ::= -- This is a dispatch that we have already tried to resolve. then pure(neverDec()) -- Otherwise, look at all the (host) productions that implement this dispatch signature - else map(sum, traverseA( - \ prod::(String, [String]) -> - case getTypeDcl(prodOrSig, realEnv) of - | sigDcl :: _ - when drop(positionOf(sigName, sigDcl.dispatchSignature.inputNames), prod.2) - matches sn :: _ -> do { + else + case getTypeDcl(prodOrSig, realEnv) of + | sigDcl :: _ -> map(sum, traverseA( + \ prod::(String, [String]) -> + case drop(positionOf(sigName, sigDcl.dispatchSignature.inputNames), prod.2) of + | sn :: _ -> do { modifyState(\ seen::PDSState -> (seen.1, (prod.1, sn) :: seen.2)); recurse(prod.1, rhsVertexType(sn)); } - | _ -> error(s"findDecSites: Couldn't resolve ${sigName} in ${prodOrSig}") - end, - getImplementingProds(prodOrSig, flowEnv)))) + | _ -> error(s"findPossibleDecSites: Couldn't resolve ${sigName} in ${prodOrSig}") + end, + getImplementingProds(prodOrSig, flowEnv))) + -- TODO: This could be a production in a grammar that isn't in scope in the local environment, + -- e.g. in a modification, that was missed in the above getValueDcl(prodOrSig, realEnv). + -- We really should be using the global env here. + | _ -> pure(alwaysDec()) + end) + -- Via the reference set of a pattern match scrutinee + | anonScrutineeVertexType(_, grammarName, l) -> + pure(anonScrutineeRefSetDec(getAnonScrutineeRefSet(prodName, vt.vertexName, flowEnv), grammarName, l)) -- Via signature/dispatch sharing | rhsVertexType(sigName) when lookupSignatureInputElem(sigName, ns).elementShared -> map(sum, sequence(unzipWith(recurse, @@ -210,9 +220,12 @@ State ::= end, getSynAttrsOn(ntName, realEnv)); return + (if vt.isInhDefVertex -- Direct inherited equation at a decoration site - (if vt.isInhDefVertex then directDec(prodName, vt) + else if vt.isFlowTypeDepVertex + -- May be supplied non-locally + then alwaysDec() else neverDec()) + viaVertex + sum(viaDirectShare) + sum(concat(viaTransAttrShare)); }; @@ -293,6 +306,8 @@ partial strategy attribute lookupDecSiteStep = product(map(depAttrDec(_, ^d), set:toList(onlyLhsInh(expandGraph( [rhsInhVertex(sigName, top.attrToResolve)], findProductionGraph(prodName, top.productionFlowGraphs)))))) + | anonScrutineeRefSetDec(refSet, _, _) when contains(top.attrToResolve, refSet) -> + alwaysDec() | transAttrDec(attrName, d) -> case splitTransAttrInh(top.attrToResolve) of | just((transAttr, inhAttr)) when transAttr == attrName -> depAttrDec(inhAttr, ^d) @@ -386,7 +401,7 @@ fun decSiteHasInhEq Boolean ::= prodName::String vt::VertexType attrName::String prodGraphs::EnvTree flowEnv::FlowEnv realEnv::Env = - resolveInhEq(attrName, vt, attrName, prodGraphs, flowEnv, realEnv) == alwaysDec(); + resolveInhEq(prodName, vt, attrName, prodGraphs, flowEnv, realEnv) == alwaysDec(); -- Helper for checking multiple inh attributes function decSitesMissingInhEqs diff --git a/grammars/silver/compiler/definition/flow/env/Expr.sv b/grammars/silver/compiler/definition/flow/env/Expr.sv index a164068ac..3e1001cd7 100644 --- a/grammars/silver/compiler/definition/flow/env/Expr.sv +++ b/grammars/silver/compiler/definition/flow/env/Expr.sv @@ -68,13 +68,9 @@ attribute flowDeps, flowDefs, flowEnv, lexicalLocalDecSites, lexicalLocalAlwaysD occurs on Expr, ExprInhs, ExprInh, Exprs, AppExprs, AppExpr, AnnoAppExprs, AnnoExpr; attribute flowVertexInfo occurs on Expr; -{-- - - The direct dependencies of applied dispatch signatures - - that have this expression as an argument. - -} -inherited attribute dispatchFlowDeps :: [FlowVertex]; - -flowtype flowVertexInfo {forward} on Expr; +flowtype Expr = + flowVertexInfo {forward}, flowDeps {forward}, flowDefs {forward, alwaysDecorated}, + lexicalLocalDecSites {forward}, lexicalLocalAlwaysDecorated {forward, alwaysDecorated}; propagate flowDeps on Expr, ExprInhs, ExprInh, Exprs, AppExprs, AppExpr, AnnoAppExprs, AnnoExpr excluding @@ -83,8 +79,8 @@ propagate flowDeps on Expr, ExprInhs, ExprInh, Exprs, AppExprs, AppExpr, AnnoApp propagate flowDefs, flowEnv, lexicalLocalDecSites, lexicalLocalAlwaysDecorated on Expr, ExprInhs, ExprInh, Exprs, AppExprs, AppExpr, AnnoAppExprs, AnnoExpr; -attribute decSiteVertexInfo, alwaysDecorated, dispatchFlowDeps occurs on Expr, AppExprs, AppExpr; -propagate decSiteVertexInfo, alwaysDecorated, dispatchFlowDeps on AppExprs; +attribute decSiteVertexInfo, alwaysDecorated occurs on Expr, AppExprs, AppExpr; +propagate decSiteVertexInfo, alwaysDecorated on AppExprs; attribute appDecSiteVertexInfo occurs on Expr; @@ -103,10 +99,9 @@ top::Expr ::= @q::QName -- Note that q should find the actual type written in the signature, and so -- isDecorable on that indeed tells us whether it's something autodecorated. production refSet::Maybe<[String]> = getMaxRefSet(top.finalType, top.env); - production origRefSet::[String] = getMinRefSet(q.lookupValue.typeScheme.monoType, top.env); - top.flowDeps <- + top.flowDeps <- rhsEqVertex(q.lookupValue.fullName) :: if isDecorable(q.lookupValue.typeScheme.monoType, top.env) && top.finalType.isDecorated - then map(rhsVertexType(q.lookupValue.fullName).inhVertex, removeAll(origRefSet, fromMaybe([], refSet))) + then map(rhsInhVertex(q.lookupValue.fullName, _), fromMaybe([], refSet)) else []; top.flowVertexInfo = if isDecorable(q.lookupValue.typeScheme.monoType, top.env) && top.finalType.isDecorated @@ -116,15 +111,15 @@ top::Expr ::= @q::QName aspect production lhsReference top::Expr ::= @q::QName { - -- Always a decorable type, so just check how it's being used: + -- Always a nonterminal type, but check if it's decorated in case it's a data NT: production refSet::Maybe<[String]> = getMaxRefSet(top.finalType, top.env); - top.flowDeps <- + top.flowDeps <- lhsEqVertex() :: if top.finalType.isDecorated - then map(lhsVertexType.inhVertex, fromMaybe([], refSet)) + then map(lhsInhVertex, fromMaybe([], refSet)) else []; top.flowVertexInfo = if top.finalType.isDecorated - then just(lhsVertexType) + then just(lhsVertexType()) else nothing(); } aspect production localReference @@ -132,10 +127,9 @@ top::Expr ::= @q::QName { -- Again, q give the actual type written. production refSet::Maybe<[String]> = getMaxRefSet(top.finalType, top.env); - production origRefSet::[String] = getMinRefSet(q.lookupValue.typeScheme.monoType, top.env); top.flowDeps <- localEqVertex(q.lookupValue.fullName) :: if isDecorable(q.lookupValue.typeScheme.monoType, top.env) && top.finalType.isDecorated - then map(localVertexType(q.lookupValue.fullName).inhVertex, removeAll(origRefSet, fromMaybe([], refSet))) + then map(localInhVertex(q.lookupValue.fullName, _), fromMaybe([], refSet)) else []; top.flowVertexInfo = if isDecorable(q.lookupValue.typeScheme.monoType, top.env) && top.finalType.isDecorated @@ -148,20 +142,19 @@ top::Expr ::= @q::QName -- Never decorated - just the equation vertex. top.flowDeps <- [localEqVertex(q.lookupValue.fullName)]; top.flowVertexInfo = nothing(); + top.flowDefs <- + case top.decSiteVertexInfo of + | just(v) -> [holeEq(top.frame.fullName, top.typerep.typeName, top.typerep.isNonterminal, v, top.flowDeps)] + | nothing() -> [] + end; } aspect production forwardReference top::Expr ::= @q::QName { - -- Again, always a decorable type. + -- Always a non-data nonterminal type. production refSet::Maybe<[String]> = getMaxRefSet(top.finalType, top.env); - top.flowDeps <- forwardEqVertex() :: - if top.finalType.isDecorated - then map(forwardVertexType.inhVertex, fromMaybe([], refSet)) - else []; - top.flowVertexInfo = - if top.finalType.isDecorated - then just(forwardVertexType) - else nothing(); + top.flowDeps <- forwardEqVertex :: map(forwardInhVertex, fromMaybe([], refSet)); + top.flowVertexInfo = just(forwardVertexType()); } aspect production forwardParentReference top::Expr ::= 'forwardParent' @@ -190,12 +183,23 @@ top::Expr ::= e::Expr '(' es::AppExprs ',' anns::AnnoAppExprs ')' { propagate flowEnv; e.appDecSiteVertexInfo = top.decSiteVertexInfo; - -- Seed flow graphs with deps on top for decSiteVertexInfo, alwaysDecorated, dispatchFlowDeps - -- needed to avoid hidden transitive deps for override eqs in curriedDispatchApplication. - -- TODO: Perhaps possible to infer this by changing how projection stitch points work? - e.decSiteVertexInfo = if true then nothing() else top.decSiteVertexInfo; - e.alwaysDecorated = false && top.alwaysDecorated; - e.dispatchFlowDeps = [] ++ if false then top.dispatchFlowDeps else []; + e.decSiteVertexInfo = nothing(); + e.alwaysDecorated = false; + + es.appProd = + case e, e.finalType of + | productionReference(q), _ -> just(q.lookupValue.dcl.namedSignature) + | _, dispatchType(ns) -> just(ns) + | _, _ -> nothing() + end; + + top.flowDefs <- + case es.appProd, top.decSiteVertexInfo of + | just(ns), just(v) -> + [subtermDecEq(top.frame.fullName, ns.inputNames, v, ns.fullName)] + | _, just(v) -> [holeEq(top.frame.fullName, top.finalType.typeName, top.finalType.isNonterminal, v, top.flowDeps)] + | _, _ -> [] + end; } aspect production errorApplication @@ -203,20 +207,19 @@ top::Expr ::= @e::Expr @es::AppExprs @anns::AnnoAppExprs { es.decSiteVertexInfo = nothing(); es.alwaysDecorated = false; - es.appProd = nothing(); es.appIndexOffset = 0; - es.dispatchFlowDeps = []; } aspect production functionInvocation top::Expr ::= @e::Expr @es::AppExprs @anns::AnnoAppExprs { - top.flowVertexInfo = top.decSiteVertexInfo; - es.appProd = - case e of - | productionReference(q) -> just(q.lookupValue.dcl.namedSignature) - | _ -> nothing() + top.flowDefs <- + case e, top.decSiteVertexInfo of + | productionReference(q), just(v) when !null(anns.flowDeps) -> + [decSiteDepEq(top.frame.fullName, v, anns.flowDeps)] + | _, _ -> [] end; + es.appIndexOffset = case e of | productionReference(q) when q.lookupValue.dcl.implementedSignature matches just(dSig) -> @@ -227,18 +230,11 @@ top::Expr ::= @e::Expr @es::AppExprs @anns::AnnoAppExprs end; es.decSiteVertexInfo = top.decSiteVertexInfo; es.alwaysDecorated = top.alwaysDecorated; - -- If sharing is permitted in es, then e is a prod reference and e.flowDeps must be empty. - es.dispatchFlowDeps = top.dispatchFlowDeps; } aspect production partialApplication top::Expr ::= @e::Expr @es::AppExprs @anns::AnnoAppExprs { - es.appProd = - case e of - | productionReference(q) -> just(q.lookupValue.dcl.namedSignature) - | _ -> nothing() - end; es.appIndexOffset = case e of | productionReference(q) when q.lookupValue.dcl.implementedSignature matches just(dSig) -> @@ -249,21 +245,14 @@ top::Expr ::= @e::Expr @es::AppExprs @anns::AnnoAppExprs end; es.decSiteVertexInfo = nothing(); es.alwaysDecorated = false; - es.dispatchFlowDeps = []; } aspect production curriedDispatchApplication top::Expr ::= @e::Expr @es::AppExprs @anns::AnnoAppExprs { - es.appProd = - case e of - | productionReference(q) -> just(q.lookupValue.dcl.namedSignature) - | _ -> nothing() - end; es.appIndexOffset = 0; es.decSiteVertexInfo = top.decSiteVertexInfo; es.alwaysDecorated = top.alwaysDecorated; - es.dispatchFlowDeps = top.dispatchFlowDeps ++ e.flowDeps; -- We override these attributes in what we forward to, as a special case to -- be more precise about what production is being applied. @@ -271,28 +260,24 @@ top::Expr ::= @e::Expr @es::AppExprs @anns::AnnoAppExprs dispatchArgs.appIndexOffset = 0; dispatchArgs.decSiteVertexInfo = top.decSiteVertexInfo; dispatchArgs.alwaysDecorated = top.alwaysDecorated; - dispatchArgs.dispatchFlowDeps = es.dispatchFlowDeps; extraArgs.appProd = es.appProd; extraArgs.appIndexOffset = dispatchArgs.appExprSize; extraArgs.decSiteVertexInfo = top.decSiteVertexInfo; extraArgs.alwaysDecorated = top.alwaysDecorated; - extraArgs.dispatchFlowDeps = es.dispatchFlowDeps; } aspect production dispatchApplication top::Expr ::= @e::Expr @es::AppExprs @anns::AnnoAppExprs { - top.flowVertexInfo = top.decSiteVertexInfo; - es.appProd = - case e, e.finalType of - | productionReference(q), _ -> just(q.lookupValue.dcl.namedSignature) - | _, dispatchType(ns) -> just(ns) - | _, _ -> error("dispatchApplication: unexpected type") + top.flowDefs <- + case top.decSiteVertexInfo of + | just(v) -> [decSiteDepEq(top.frame.fullName, v, e.flowDeps ++ anns.flowDeps)] + | nothing() -> [] end; + es.appIndexOffset = 0; es.decSiteVertexInfo = top.decSiteVertexInfo; es.alwaysDecorated = top.alwaysDecorated; - es.dispatchFlowDeps = top.dispatchFlowDeps ++ e.flowDeps; } aspect production annoUpdatePositionalErrorApplication @@ -300,9 +285,7 @@ top::Expr ::= @e::Expr @es::AppExprs @anns::AnnoAppExprs { es.decSiteVertexInfo = nothing(); es.alwaysDecorated = false; - es.appProd = nothing(); es.appIndexOffset = 0; - es.dispatchFlowDeps = []; } aspect production annoUpdateInvocation @@ -310,9 +293,7 @@ top::Expr ::= @e::Expr @es::AppExprs @anns::AnnoAppExprs { es.decSiteVertexInfo = nothing(); es.alwaysDecorated = false; - es.appProd = nothing(); es.appIndexOffset = 0; - es.dispatchFlowDeps = []; } aspect production annoUpdatePartialApplication @@ -320,9 +301,7 @@ top::Expr ::= @e::Expr @es::AppExprs @anns::AnnoAppExprs { es.decSiteVertexInfo = nothing(); es.alwaysDecorated = false; - es.appProd = nothing(); es.appIndexOffset = 0; - es.dispatchFlowDeps = []; } aspect production annoExpr @@ -332,7 +311,6 @@ top::AnnoExpr ::= qn::QName '=' e::AppExpr e.appProd = nothing(); e.appIndexOffset = 0; e.alwaysDecorated = false; - e.dispatchFlowDeps = []; } aspect production presentAppExpr @@ -344,26 +322,36 @@ top::AppExpr ::= e::Expr | just(ns) when sigIndex < length(ns.inputNames) -> head(drop(sigIndex, ns.inputNames)) | _ -> "err" end; + + -- Capture the equation dependencies for non-decorable children. + -- Additional optimization: if the expression is a "boring" tree literal with no flow + -- dependencies or sharing, just treat it as a hole. + -- Using the flow type is less precise than a tile stitch point, but this + -- avoids a massive blowup in the size of the flow graph when constructing + -- large trees. top.flowDefs <- - case e.decSiteVertexInfo of - | just(subtermVertexType(parent, prodName, sigName)) -> - [subtermDecEq(top.frame.fullName, parent, prodName, e.finalType.typeName, sigName)] - | _ -> [] + case top.decSiteVertexInfo, top.appProd of + | just(parent), just(ns) when + !sigIsShared && + (!isDecorable(top.appExprTyperep, top.env) || + (null(e.flowDeps) && null(e.sharedRefs))) -> + [holeEq( + top.frame.fullName, top.appExprTyperep.typeName, false, + subtermVertexType(parent, ns.fullName, sigName), + e.flowDeps)] + | _, _ -> [] end; e.decSiteVertexInfo = case top.decSiteVertexInfo, top.appProd of - | just(parent), just(ns) - when isDecorable( - if sigIsShared - then top.appExprTyperep.decoratedType - else top.appExprTyperep, - top.env) -> + | just(parent), just(ns) when + !sigIsShared && + isDecorable(top.appExprTyperep, top.env) && + !(null(e.flowDeps) && null(e.sharedRefs)) -> just(subtermVertexType(parent, ns.fullName, sigName)) | _, _ -> nothing() end; e.alwaysDecorated = top.alwaysDecorated && e.decSiteVertexInfo.isJust; e.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = top.dispatchFlowDeps; production inputSigIsShared::Boolean = case e.flowVertexInfo of @@ -377,21 +365,26 @@ top::AppExpr ::= e::Expr sigIndex < length(ns.inputNames) && head(drop(sigIndex, ns.inputElements)).elementShared | _ -> false end; + production sigDecSite::Maybe = + case top.decSiteVertexInfo, top.appProd of + | just(parent), just(ns) when sigIsShared -> + just(subtermVertexType(parent, ns.fullName, sigName)) + | _, _ -> nothing() + end; production isForwardParam::Boolean = -- Don't try to share if someone uses a signature sharing prod somewhere invalid. case top.decSiteVertexInfo of - | just(forwardVertexType_real()) -> true + | just(forwardVertexType()) -> true | just(localVertexType(fName)) when isForwardProdAttr(top.frame.fullName, fName, top.flowEnv) -> true | _ -> false end; top.flowDefs <- - case top.decSiteVertexInfo, top.appProd, e.flowVertexInfo of - | just(parent), just(ns), just(v) when sigIsShared -> - refDecSiteEq( - top.frame.fullName, e.finalType.typeName, v, - subtermVertexType(parent, ns.fullName, sigName), top.alwaysDecorated) :: + case sigDecSite, top.appProd, e.flowVertexInfo of + | just(decSite), just(ns), just(v) -> + refDecSiteEq(top.frame.fullName, e.finalType.typeName, v, decSite, top.alwaysDecorated) :: if inputSigIsShared then [] - else [sigShareSite(ns.fullName, e.finalType.typeName, sigName, top.frame.fullName, v, parent)] + -- TODO: Should only introduce projected deps in appProd's graph here if we are exported by appProd! + else [sigShareSite(ns.fullName, e.finalType.typeName, sigName, top.frame.fullName, v)] | _, _, _ -> [] end; } @@ -399,14 +392,18 @@ top::AppExpr ::= e::Expr aspect production noteAttachment top::Expr ::= 'attachNote' note::Expr 'on' e::Expr 'end' { + top.flowDefs <- + case top.decSiteVertexInfo of + | just(v) when !null(note.flowDeps) -> + [decSiteDepEq(top.frame.fullName, v, note.flowDeps)] + | _ -> [] + end; note.decSiteVertexInfo = nothing(); e.decSiteVertexInfo = top.decSiteVertexInfo; note.alwaysDecorated = false; e.alwaysDecorated = top.alwaysDecorated; note.appDecSiteVertexInfo = nothing(); e.appDecSiteVertexInfo = top.appDecSiteVertexInfo; - note.dispatchFlowDeps = []; - e.dispatchFlowDeps = top.dispatchFlowDeps; } aspect production access @@ -416,7 +413,6 @@ top::Expr ::= e::Expr '.' q::QNameAttrOccur e.alwaysDecorated = false; e.decSiteVertexInfo = nothing(); e.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = []; } aspect production accessBouncer @@ -426,7 +422,6 @@ top::Expr ::= e::Expr @q::QNameAttrOccur target::Access e.alwaysDecorated = false; e.decSiteVertexInfo = nothing(); e.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = []; } aspect production forwardAccess @@ -434,13 +429,17 @@ top::Expr ::= e::Expr '.' 'forward' { top.flowDeps := case e.flowVertexInfo of - | just(vertex) -> vertex.fwdVertex :: vertex.eqVertex + | just(vertex) -> vertex.fwdDeps | nothing() -> e.flowDeps end; + top.flowDefs <- + case top.decSiteVertexInfo of + | just(v) -> [holeEq(top.frame.fullName, top.typerep.typeName, top.typerep.isNonterminal, v, top.flowDeps)] + | nothing() -> [] + end; e.decSiteVertexInfo = nothing(); e.alwaysDecorated = false; e.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = []; } @@ -451,18 +450,28 @@ top::Expr ::= @e::Expr @q::QNameAttrOccur { top.flowDeps := case e.flowVertexInfo of - | just(vertex) -> vertex.synVertex(q.attrDcl.fullName) :: vertex.eqVertex + | just(vertex) -> vertex.synDeps(q.attrDcl.fullName) | nothing() -> e.flowDeps end; + top.flowDefs <- + case top.decSiteVertexInfo of + | just(v) -> [holeEq(top.frame.fullName, top.typerep.typeName, top.typerep.isNonterminal, v, top.flowDeps)] + | nothing() -> [] + end; } aspect production inhDecoratedAccessHandler top::Expr ::= @e::Expr @q::QNameAttrOccur { top.flowDeps := case e.flowVertexInfo of - | just(vertex) -> vertex.inhVertex(q.attrDcl.fullName) :: vertex.eqVertex + | just(vertex) -> vertex.inhDeps(q.attrDcl.fullName) | nothing() -> e.flowDeps end; + top.flowDefs <- + case top.decSiteVertexInfo of + | just(v) -> [holeEq(top.frame.fullName, top.typerep.typeName, top.typerep.isNonterminal, v, top.flowDeps)] + | nothing() -> [] + end; } aspect production transDecoratedAccessHandler top::Expr ::= @e::Expr @q::QNameAttrOccur @@ -471,7 +480,7 @@ top::Expr ::= @e::Expr @q::QNameAttrOccur top.flowVertexInfo = map(transAttrVertexType(_, q.attrDcl.fullName), e.flowVertexInfo); top.flowDeps := case e.flowVertexInfo of - | just(vertex) -> vertex.synVertex(q.attrDcl.fullName) :: vertex.eqVertex ++ + | just(vertex) -> vertex.synDeps(q.attrDcl.fullName) ++ map(transAttrVertexType(vertex, q.attrDcl.fullName).inhVertex, fromMaybe([], refSet)) | nothing() -> e.flowDeps end; @@ -491,32 +500,34 @@ top::Expr ::= 'decorate' e::Expr 'with' '{' inh::ExprInhs '}' -- this as to the flow analysis, and justifies all the choices below: -- First, generate our "anonymous" flow vertex name: - inh.decorationVertex = "__decorate" ++ toString(genInt()) ++ ":line" ++ toString(getParsedOriginLocationOrFallback(top).line); + local vt::VertexType = + anonVertexType(s"__decorate${toString(genInt())}", top.grammarName, getParsedOriginLocationOrFallback(top)); + inh.decorationVertex = vt.vertexName; -- Next, emit the "local equation" for this anonymous flow vertex. -- This means only the deps in 'e', see above conceptual transformation to see why. -- N.B. 'inh.flowDefs' will emit 'localInhEq's for this anonymous flow vertex. local eTy::Type = e.finalType; top.flowDefs <- - [anonEq(top.frame.fullName, inh.decorationVertex, eTy.typeName, eTy.isNonterminal, getParsedOriginLocationOrFallback(top), e.flowDeps)]; + [anonEq(top.frame.fullName, inh.decorationVertex, getParsedOriginLocationOrFallback(top), e.flowDeps)]; -- Now, we represent ourselves to anything that might use us specially -- as though we were a reference to this anonymous local - top.flowVertexInfo = just(anonVertexType(inh.decorationVertex)); - e.decSiteVertexInfo = just(anonVertexType(inh.decorationVertex)); + local loc::Location = getParsedOriginLocationOrFallback(top); + top.flowVertexInfo = just(vt); + e.decSiteVertexInfo = just(vt); -- The type of decorate ... with ... is a normal reference for now, so this should always be false, but that could change. e.alwaysDecorated = top.alwaysDecorated; e.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = []; -- Finally, our standard flow deps mimic those of a local: "taking a reference" -- This are of course ignored when treated specially. production refSet::Maybe<[String]> = getMaxRefSet(top.finalType, top.env); - top.flowDeps := [anonEqVertex(inh.decorationVertex)] ++ - map(anonVertexType(inh.decorationVertex).inhVertex, fromMaybe([], refSet)); + top.flowDeps := vt.eqVertex :: + map(vt.inhVertex, fromMaybe([], refSet)); -- If we have a type var with occurs-on contexts, add the specified syn -> inh deps for the new vertex - top.flowDefs <- occursContextDeps(top.frame.signature, top.env, top.finalType, anonVertexType(inh.decorationVertex)); + top.flowDefs <- occursContextDeps(top.frame.signature, top.env, top.finalType, vt); } inherited attribute decorationVertex :: String occurs on ExprInhs, ExprInh; @@ -533,7 +544,6 @@ top::ExprInh ::= lhs::ExprLHSExpr '=' e1::Expr ';' e1.decSiteVertexInfo = nothing(); e1.alwaysDecorated = false; e1.appDecSiteVertexInfo = nothing(); - e1.dispatchFlowDeps = []; } aspect production decorationSiteExpr @@ -543,7 +553,6 @@ top::Expr ::= '@' e::Expr e.decSiteVertexInfo = nothing(); e.alwaysDecorated = false; e.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = []; top.flowDefs <- case e.flowVertexInfo, top.decSiteVertexInfo of @@ -556,6 +565,11 @@ top::Expr ::= '@' e::Expr aspect production ifThenElse top::Expr ::= 'if' e1::Expr 'then' e2::Expr 'else' e3::Expr { + top.flowDefs <- + case top.decSiteVertexInfo of + | just(v) -> [decSiteDepEq(top.frame.fullName, v, e1.flowDeps)] + | nothing() -> [] + end; e1.decSiteVertexInfo = nothing(); e2.decSiteVertexInfo = top.decSiteVertexInfo; e3.decSiteVertexInfo = top.decSiteVertexInfo; @@ -565,10 +579,6 @@ top::Expr ::= 'if' e1::Expr 'then' e2::Expr 'else' e3::Expr e1.appDecSiteVertexInfo = nothing(); e2.appDecSiteVertexInfo = nothing(); e3.appDecSiteVertexInfo = nothing(); - e1.dispatchFlowDeps = []; - -- Nothing can depend on inhs supplied via sharing under a conditional. - e2.dispatchFlowDeps = []; - e3.dispatchFlowDeps = []; } aspect production terminalConstructor @@ -580,8 +590,6 @@ top::Expr ::= 'terminal' '(' t::TypeExpr ',' es::Expr ',' el::Expr ')' el.alwaysDecorated = false; es.appDecSiteVertexInfo = nothing(); el.appDecSiteVertexInfo = nothing(); - es.dispatchFlowDeps = []; - el.dispatchFlowDeps = []; } aspect production exprsSingle @@ -590,7 +598,6 @@ top::Exprs ::= e::Expr e.decSiteVertexInfo = nothing(); e.alwaysDecorated = false; e.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = []; } aspect production exprsCons top::Exprs ::= e1::Expr ',' e2::Exprs @@ -598,7 +605,6 @@ top::Exprs ::= e1::Expr ',' e2::Exprs e1.decSiteVertexInfo = nothing(); e1.alwaysDecorated = false; e1.appDecSiteVertexInfo = nothing(); - e1.dispatchFlowDeps = []; } aspect production lambdap @@ -607,7 +613,6 @@ top::Expr ::= params::LambdaRHS e::Expr e.decSiteVertexInfo = nothing(); e.alwaysDecorated = false; e.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = []; } -- FROM LET TODO @@ -628,7 +633,6 @@ top::Expr ::= la::AssignExpr e::Expr e.decSiteVertexInfo = top.decSiteVertexInfo; e.alwaysDecorated = top.alwaysDecorated; e.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = top.dispatchFlowDeps; } aspect production assignExpr @@ -641,11 +645,10 @@ top::AssignExpr ::= id::Name '::' t::TypeExpr '=' e::Expr end; e.alwaysDecorated = lookupAll(fName, top.bodyAlwaysDecorated) == [true]; e.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = []; } aspect production lexicalLocalReference -top::Expr ::= @q::QName fi::Maybe fd::[FlowVertex] +top::Expr ::= @q::QName fi::Maybe fd::[FlowVertex] _ { top.flowDeps := fd; top.flowVertexInfo = fi; @@ -656,10 +659,12 @@ top::Expr ::= @q::QName fi::Maybe fd::[FlowVertex] -- FROM PATTERN TODO -attribute flowDeps, flowDefs, flowEnv, decSiteVertexInfo, alwaysDecorated, appDecSiteVertexInfo, dispatchFlowDeps, scrutineeVertexType +attribute flowDeps, flowDefs, flowEnv, decSiteVertexInfo, alwaysDecorated, appDecSiteVertexInfo, scrutineeVertexType occurs on PrimPatterns, PrimPattern; -propagate flowDeps, flowDefs, flowEnv, decSiteVertexInfo, alwaysDecorated, appDecSiteVertexInfo, dispatchFlowDeps, scrutineeVertexType +propagate flowDeps, flowDefs, flowEnv, decSiteVertexInfo, alwaysDecorated, appDecSiteVertexInfo, scrutineeVertexType on PrimPatterns, PrimPattern; +attribute scrutineeVertexType occurs on VarBinders, VarBinder; +propagate scrutineeVertexType on VarBinders, VarBinder; inherited attribute scrutineeVertexType :: VertexType; @@ -674,28 +679,37 @@ top::Expr ::= e::Expr t::TypeExpr pr::PrimPatterns f::Expr -- consider 'case e of prod(x) -> decorate x.syn with ...' -- that introduces the use of 'x.syn' in a flowDef, and then emits the anonEq in flowDep -- so we DO need to be transitive. Unfortunately. - - -- hack note: there's a test that depends on this name starting with __scrutinee. grep for it if you have to change this - local anonName :: String = "__scrutinee" ++ toString(genInt()) ++ ":line" ++ toString(getParsedOriginLocationOrFallback(e).line); + + local eLoc::Location = getParsedOriginLocationOrFallback(e); pr.scrutineeVertexType = case e.flowVertexInfo of | just(vertex) -> vertex - | nothing() -> anonVertexType(anonName) + | nothing() -> anonScrutineeVertexType( + s"__scrutinee${toString(genInt())}", top.grammarName, eLoc) end; -- Let's make sure for decorated types, we only demand what's necessary for forward -- evaluation. - top.flowDeps := pr.flowDeps ++ f.flowDeps ++ - (pr.scrutineeVertexType.fwdVertex :: pr.scrutineeVertexType.eqVertex); + top.flowDeps := pr.flowDeps ++ f.flowDeps ++ pr.scrutineeVertexType.fwdDeps; local eTy::Type = e.finalType; top.flowDefs <- case e.flowVertexInfo of | just(vertex) -> [] - | nothing() -> [anonEq(top.frame.fullName, anonName, eTy.typeName, eTy.isNonterminal, getParsedOriginLocationOrFallback(top), e.flowDeps)] + | nothing() -> + -- Add the dependencies and nonterminal stitch point for the anon vertex we created: + [anonScrutineeEq( + top.frame.fullName, pr.scrutineeVertexType.vertexName, eTy.typeName, eTy.isNonterminal, + getMinRefSet(^eTy, top.env), + top.grammarName, eLoc, e.flowDeps)] + end; + + top.flowDefs <- + case top.decSiteVertexInfo of + | just(v) -> [decSiteDepEq(top.frame.fullName, v, pr.scrutineeVertexType.fwdDeps)] + | nothing() -> [] end; - -- We want to use anonEq here because that introduces the nonterminal stitch point for our vertex. e.decSiteVertexInfo = nothing(); pr.decSiteVertexInfo = top.decSiteVertexInfo; @@ -706,9 +720,6 @@ top::Expr ::= e::Expr t::TypeExpr pr::PrimPatterns f::Expr e.appDecSiteVertexInfo = nothing(); pr.appDecSiteVertexInfo = nothing(); f.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = []; - pr.dispatchFlowDeps = []; - f.dispatchFlowDeps = []; } aspect production prodPattern @@ -718,5 +729,4 @@ top::PrimPattern ::= qn::QName '(' ns::VarBinders ')' _ e::Expr top.flowDefs <- [patternRuleEq(top.frame.fullName, qn.lookupValue.fullName, top.scrutineeVertexType, ns.flowProjections)]; e.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = []; } diff --git a/grammars/silver/compiler/definition/flow/env/FlowEnv.sv b/grammars/silver/compiler/definition/flow/env/FlowEnv.sv index 411653315..99927c27f 100644 --- a/grammars/silver/compiler/definition/flow/env/FlowEnv.sv +++ b/grammars/silver/compiler/definition/flow/env/FlowEnv.sv @@ -130,7 +130,7 @@ fun vertexHasInhEq Boolean ::= prodName::String vt::VertexType attrName::Strin case vt of | rhsVertexType(sigName) -> !null(lookupInh(prodName, sigName, attrName, flowEnv)) | localVertexType(fName) -> !null(lookupLocalInh(prodName, fName, attrName, flowEnv)) - | forwardVertexType_real() -> true + | forwardVertexType() -> true -- Note that we only support inh equations on trans attrs directly on a child/local, -- and not chained trans attrs. | transAttrVertexType(rhsVertexType(sigName), transAttr) -> @@ -138,14 +138,15 @@ fun vertexHasInhEq Boolean ::= prodName::String vt::VertexType attrName::Strin | transAttrVertexType(localVertexType(fName), transAttr) -> !null(lookupLocalInh(prodName, fName, s"${transAttr}.${attrName}", flowEnv)) | transAttrVertexType(_, _) -> false - | anonVertexType(fName) -> !null(lookupLocalInh(prodName, fName, attrName, flowEnv)) + | anonVertexType(_, _, _) -> !null(lookupLocalInh(prodName, vt.vertexName, attrName, flowEnv)) + | anonScrutineeVertexType(_, _, _) -> false | subtermVertexType(_, remoteProdName, sigName) -> vertexHasInhEq(remoteProdName, rhsVertexType(sigName), attrName, flowEnv) -- This is a tricky case since we don't know what decorated this prod. - -- checkEqDeps can count on missing LHS inh eqs being caught as flow issues elsewhere, + -- We can count on missing LHS inh eqs being caught as flow issues elsewhere, -- but here we are remotely looking for equations that might not be the direct dependency of -- anything in the prod flow graph. - | lhsVertexType_real() -> false -- Shouldn't ever be directly needed, since the LHS is never the dec site for another vertex. + | lhsVertexType() -> false -- Shouldn't ever be directly needed, since the LHS is never the dec site for another vertex. | forwardParentVertexType() -> false -- Same as LHS - the thing that forwarded to us. end; @@ -167,11 +168,12 @@ fun countVertexEqs Integer ::= prodName::String vt::VertexType attrName::Strin | transAttrVertexType(localVertexType(fName), transAttr) -> length(lookupLocalInh(prodName, fName, s"${transAttr}.${attrName}", flowEnv)) | transAttrVertexType(_, _) -> 0 - | anonVertexType(fName) -> length(lookupLocalInh(prodName, fName, attrName, flowEnv)) + | anonVertexType(_, _, _) -> length(lookupLocalInh(prodName, vt.vertexName, attrName, flowEnv)) + | anonScrutineeVertexType(_, _, _) -> 0 | subtermVertexType(_, remoteProdName, sigName) -> 0 - | lhsVertexType_real() -> length(lookupSyn(prodName, attrName, flowEnv)) + | lhsVertexType() -> length(lookupSyn(prodName, attrName, flowEnv)) | forwardParentVertexType() -> 0 - | forwardVertexType_real() -> length(lookupFwdInh(prodName, attrName, flowEnv)) + | forwardVertexType() -> length(lookupFwdInh(prodName, attrName, flowEnv)) end; -- Check if a production attribute is a forward production attribute. @@ -179,10 +181,16 @@ fun countVertexEqs Integer ::= prodName::String vt::VertexType attrName::Strin -- If looking up in another prod, need to get the prod attr defs for the prod. fun isForwardProdAttr Boolean ::= prod::String fName::String e::FlowEnv = case lookupLocalEq(prod, fName, e) of - | localEq(_, _, _, _, isFwrd, _) :: _ -> isFwrd + | localEq(_, _, _, isFwrd, _) :: _ -> isFwrd | _ -> false end; +fun getAnonScrutineeRefSet [String] ::= prod::String fName::String e::FlowEnv = + case lookupLocalEq(prod, fName, e) of + | anonScrutineeEq(_, _, _, _, refSet, _, _, _) :: _ -> refSet + | _ -> [] + end; + -- default set of inherited attributes required/assumed to exist for references fun getInhsForNtRef [[String]] ::= nt::String e::FlowEnv = searchEnvTree(nt, e.refTree); diff --git a/grammars/silver/compiler/definition/flow/env/FunctionDcl.sv b/grammars/silver/compiler/definition/flow/env/FunctionDcl.sv index d63ae890e..15ccf76ea 100644 --- a/grammars/silver/compiler/definition/flow/env/FunctionDcl.sv +++ b/grammars/silver/compiler/definition/flow/env/FunctionDcl.sv @@ -42,7 +42,6 @@ top::AGDcl ::= 'fun' id::Name ns::FunctionSignature '=' e::Expr ';' e.decSiteVertexInfo = nothing(); e.alwaysDecorated = false; e.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = []; -- oh no again! local myFlow :: EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).grammarFlowTypes; diff --git a/grammars/silver/compiler/definition/flow/env/ProductionBody.sv b/grammars/silver/compiler/definition/flow/env/ProductionBody.sv index 8452b52eb..5a6cf01e2 100644 --- a/grammars/silver/compiler/definition/flow/env/ProductionBody.sv +++ b/grammars/silver/compiler/definition/flow/env/ProductionBody.sv @@ -36,7 +36,6 @@ top::ProductionStmt ::= 'attachNote' note::Expr ';' note.decSiteVertexInfo = nothing(); note.alwaysDecorated = false; note.appDecSiteVertexInfo = nothing(); - note.dispatchFlowDeps = []; } aspect production forwardsTo @@ -59,10 +58,9 @@ top::ProductionStmt ::= 'forwards' 'to' e::Expr ';' filter(isAffectable(top.grammarName, ntDefGram, top.compiledGrammars, _), getAttrOccursOn(top.frame.lhsNtName, top.env))))]; - e.decSiteVertexInfo = just(forwardVertexType); + e.decSiteVertexInfo = just(forwardVertexType()); e.alwaysDecorated = true; e.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = []; } aspect production forwardInh top::ForwardInh ::= lhs::ForwardLHSExpr '=' e::Expr ';' @@ -76,7 +74,6 @@ top::ForwardInh ::= lhs::ForwardLHSExpr '=' e::Expr ';' e.decSiteVertexInfo = nothing(); e.alwaysDecorated = false; e.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = []; } aspect production returnDef top::ProductionStmt ::= 'return' e::Expr ';' @@ -84,14 +81,12 @@ top::ProductionStmt ::= 'return' e::Expr ';' e.decSiteVertexInfo = nothing(); e.alwaysDecorated = false; e.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = []; } aspect production attributeDef top::ProductionStmt ::= dl::DefLHS '.' attr::QNameAttrOccur '=' e::Expr ';' { propagate flowEnv; - e.dispatchFlowDeps = []; } aspect production errorAttributeDef top::ProductionStmt ::= @dl::DefLHS @attr::QNameAttrOccur e::Expr msg::[Message] @@ -100,7 +95,6 @@ top::ProductionStmt ::= @dl::DefLHS @attr::QNameAttrOccur e::Expr msg::[Message] e.decSiteVertexInfo = nothing(); e.alwaysDecorated = false; e.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = []; } aspect production synthesizedAttributeDef top::ProductionStmt ::= @dl::DefLHS @attr::QNameAttrOccur e::Expr @@ -114,7 +108,9 @@ top::ProductionStmt ::= @dl::DefLHS @attr::QNameAttrOccur e::Expr top.flowDefs <- if top.frame.hasPartialSignature then - [synEq(top.frame.fullName, attr.attrDcl.fullName, e.flowDeps, mayAffectFlowType)] + if attr.found && attr.attrDcl.isTranslation + then [transEq(top.frame.fullName, attr.attrDcl.fullName, e.flowDeps, mayAffectFlowType)] + else [synEq(top.frame.fullName, attr.attrDcl.fullName, e.flowDeps, mayAffectFlowType)] else [defaultSynEq(top.frame.lhsNtName, attr.attrDcl.fullName, e.flowDeps)]; e.decSiteVertexInfo = @@ -123,7 +119,6 @@ top::ProductionStmt ::= @dl::DefLHS @attr::QNameAttrOccur e::Expr else nothing(); e.alwaysDecorated = attr.found && attr.attrDcl.isTranslation; e.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = []; } aspect production inheritedAttributeDef top::ProductionStmt ::= @dl::DefLHS @attr::QNameAttrOccur e::Expr @@ -132,36 +127,51 @@ top::ProductionStmt ::= @dl::DefLHS @attr::QNameAttrOccur e::Expr e.decSiteVertexInfo = nothing(); e.alwaysDecorated = false; e.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = []; } -- The flow vertex type corresponding to attributes on this DefLHS synthesized attribute defLHSVertex::VertexType occurs on DefLHS; +-- Dependencies of the attribute supplied where this tree is shared +synthesized attribute defLHSDecSites::[VertexType] occurs on DefLHS; + +-- Dependencies of the attribute supplied where the base of this translation attribute LHS is shared +synthesized attribute defLHSTransBaseDecSites::[VertexType] occurs on DefLHS; + -- The constructor for inherited equations on this DefLHS synthesized attribute defLHSInhEq::[(FlowDef ::= [FlowVertex])] occurs on DefLHS; -- The name of the inherited attribute described by this DefLHS. May be syn.inh for translation attributes. synthesized attribute inhAttrName::String occurs on DefLHS; +flowtype DefLHS = defLHSDecSites {grammarName, frame, env, flowEnv}; + aspect default production top::DefLHS ::= { top.defLHSVertex = localVertexType("bogus:lhs:vertex"); top.defLHSInhEq = []; top.inhAttrName = ""; + top.defLHSDecSites = + lookupRefPossibleDecSites(top.frame.fullName, top.defLHSVertex, top.flowEnv); + top.defLHSTransBaseDecSites = error("Not a trans attr inh def LHS"); } aspect production childDefLHS top::DefLHS ::= @q::QName { top.defLHSVertex = rhsVertexType(q.lookupValue.fullName); - top.defLHSInhEq = [inhEq(top.frame.fullName, q.lookupValue.fullName, top.defLHSattr.attrDcl.fullName, _)]; + top.defLHSInhEq = + [inhEq(top.frame.fullName, q.lookupValue.fullName, top.defLHSattr.attrDcl.fullName, _, + -- Only record override deps if the equation will be visible everywhere that the sharing site is visible + if isExportedBy(top.grammarName, [top.defLHSattr.dcl.sourceGrammar], top.compiledGrammars) + then top.defLHSDecSites + else [])]; top.inhAttrName = top.defLHSattr.attrDcl.fullName; } aspect production lhsDefLHS top::DefLHS ::= @q::QName { - top.defLHSVertex = lhsVertexType; + top.defLHSVertex = lhsVertexType(); top.defLHSInhEq = []; top.inhAttrName = ""; } @@ -169,13 +179,17 @@ aspect production localDefLHS top::DefLHS ::= @q::QName { top.defLHSVertex = localVertexType(q.lookupValue.fullName); - top.defLHSInhEq = [localInhEq(top.frame.fullName, q.lookupValue.fullName, top.defLHSattr.attrDcl.fullName, _)]; + top.defLHSInhEq = + [localInhEq(top.frame.fullName, q.lookupValue.fullName, top.defLHSattr.attrDcl.fullName, _, + if isExportedBy(top.grammarName, [top.defLHSattr.dcl.sourceGrammar], top.compiledGrammars) + then top.defLHSDecSites + else [])]; top.inhAttrName = top.defLHSattr.attrDcl.fullName; } aspect production forwardDefLHS top::DefLHS ::= @q::QName { - top.defLHSVertex = forwardVertexType; + top.defLHSVertex = forwardVertexType(); top.defLHSInhEq = [fwdInhEq(top.frame.fullName, top.defLHSattr.attrDcl.fullName, _)]; top.inhAttrName = top.defLHSattr.attrDcl.fullName; } @@ -183,15 +197,29 @@ aspect production childTransAttrDefLHS top::DefLHS ::= @q::QName @attr::QNameAttrOccur { top.defLHSVertex = transAttrVertexType(rhsVertexType(q.lookupValue.fullName), attr.attrDcl.fullName); - top.defLHSInhEq = [transInhEq(top.frame.fullName, q.lookupValue.fullName, attr.attrDcl.fullName, top.defLHSattr.attrDcl.fullName, _)]; + local isExportedByOccurs::Boolean = + isExportedBy(top.grammarName, [attr.dcl.sourceGrammar, top.defLHSattr.dcl.sourceGrammar], top.compiledGrammars); + top.defLHSInhEq = + [transInhEq(top.frame.fullName, q.lookupValue.fullName, attr.attrDcl.fullName, top.defLHSattr.attrDcl.fullName, _, + if isExportedByOccurs then top.defLHSTransBaseDecSites else [], + if isExportedByOccurs then top.defLHSDecSites else [])]; top.inhAttrName = s"${attr.attrDcl.fullName}.${top.defLHSattr.attrDcl.fullName}"; + top.defLHSTransBaseDecSites = + lookupRefPossibleDecSites(top.frame.fullName, rhsVertexType(q.lookupValue.fullName), top.flowEnv); } aspect production localTransAttrDefLHS top::DefLHS ::= @q::QName @attr::QNameAttrOccur { top.defLHSVertex = transAttrVertexType(localVertexType(q.lookupValue.fullName), attr.attrDcl.fullName); - top.defLHSInhEq = [localTransInhEq(top.frame.fullName, q.lookupValue.fullName, attr.attrDcl.fullName, top.defLHSattr.attrDcl.fullName, _)]; + local isExportedByOccurs::Boolean = + isExportedBy(top.grammarName, [attr.dcl.sourceGrammar, top.defLHSattr.dcl.sourceGrammar], top.compiledGrammars); + top.defLHSInhEq = + [localTransInhEq(top.frame.fullName, q.lookupValue.fullName, attr.attrDcl.fullName, top.defLHSattr.attrDcl.fullName, _, + if isExportedByOccurs then top.defLHSTransBaseDecSites else [], + if isExportedByOccurs then top.defLHSDecSites else [])]; top.inhAttrName = s"${attr.attrDcl.fullName}.${top.defLHSattr.attrDcl.fullName}"; + top.defLHSTransBaseDecSites = + lookupRefPossibleDecSites(top.frame.fullName, localVertexType(q.lookupValue.fullName), top.flowEnv); } aspect production errorValueDef @@ -200,7 +228,6 @@ top::ProductionStmt ::= @val::QName e::Expr e.decSiteVertexInfo = nothing(); e.alwaysDecorated = false; e.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = []; } aspect production localValueDef @@ -212,7 +239,7 @@ top::ProductionStmt ::= @val::QName e::Expr top.flowDefs <- [localEq( top.frame.fullName, val.lookupValue.fullName, val.lookupValue.typeScheme.typeName, - val.lookupValue.typeScheme.typerep.isNonterminal, val.lookupValue.found && val.lookupValue.dcl.hasForward, e.flowDeps)]; + val.lookupValue.found && val.lookupValue.dcl.hasForward, e.flowDeps)]; -- If we have a type var with occurs-on contexts, add the specified syn -> inh deps for the new vertex top.flowDefs <- occursContextDeps(top.frame.signature, top.env, val.lookupValue.typeScheme.typerep, localVertexType(val.lookupValue.fullName)); @@ -224,7 +251,6 @@ top::ProductionStmt ::= @val::QName e::Expr e.alwaysDecorated = isDecorable(e.finalType, top.env) && val.lookupValue.found && !val.lookupValue.dcl.isNondec; e.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = []; } -- FROM COLLECTIONS TODO @@ -242,7 +268,6 @@ top::ProductionStmt ::= @dl::DefLHS @attr::QNameAttrOccur {- <- -} e::Expr e.decSiteVertexInfo = nothing(); e.alwaysDecorated = false; e.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = []; } aspect production inhAppendColAttributeDef @@ -252,7 +277,6 @@ top::ProductionStmt ::= @dl::DefLHS @attr::QNameAttrOccur {- <- -} e::Expr e.decSiteVertexInfo = nothing(); e.alwaysDecorated = false; e.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = []; } aspect production synBaseColAttributeDef top::ProductionStmt ::= @dl::DefLHS @attr::QNameAttrOccur e::Expr @@ -272,7 +296,6 @@ top::ProductionStmt ::= @dl::DefLHS @attr::QNameAttrOccur e::Expr e.decSiteVertexInfo = nothing(); e.alwaysDecorated = false; e.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = []; } aspect production inhBaseColAttributeDef top::ProductionStmt ::= @dl::DefLHS @attr::QNameAttrOccur e::Expr @@ -281,7 +304,6 @@ top::ProductionStmt ::= @dl::DefLHS @attr::QNameAttrOccur e::Expr e.decSiteVertexInfo = nothing(); e.alwaysDecorated = false; e.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = []; } aspect production baseCollectionValueDef @@ -292,7 +314,6 @@ top::ProductionStmt ::= @val::QName e::Expr e.decSiteVertexInfo = nothing(); e.alwaysDecorated = false; e.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = []; } aspect production appendCollectionValueDef top::ProductionStmt ::= @val::QName e::Expr @@ -317,7 +338,6 @@ top::ProductionStmt ::= @val::QName e::Expr e.decSiteVertexInfo = nothing(); e.alwaysDecorated = false; e.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = []; } -- TODO: flowDefs for Copper ProductionStmts @@ -327,7 +347,6 @@ top::ProductionStmt ::= 'pluck' e::Expr ';' e.decSiteVertexInfo = nothing(); e.alwaysDecorated = false; e.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = []; } aspect production printStmt top::ProductionStmt ::= 'print' e::Expr ';' @@ -335,7 +354,6 @@ top::ProductionStmt ::= 'print' e::Expr ';' e.decSiteVertexInfo = nothing(); e.alwaysDecorated = false; e.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = []; } aspect production parserAttributeValueDef top::ProductionStmt ::= @val::QName e::Expr @@ -343,7 +361,6 @@ top::ProductionStmt ::= @val::QName e::Expr e.decSiteVertexInfo = nothing(); e.alwaysDecorated = false; e.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = []; } aspect production pushTokenStmt top::ProductionStmt ::= 'pushToken' '(' val::QName ',' lexeme::Expr ')' ';' @@ -351,7 +368,6 @@ top::ProductionStmt ::= 'pushToken' '(' val::QName ',' lexeme::Expr ')' ';' lexeme.decSiteVertexInfo = nothing(); lexeme.alwaysDecorated = false; lexeme.appDecSiteVertexInfo = nothing(); - lexeme.dispatchFlowDeps = []; } aspect production insertSemanticTokenStmt top::ProductionStmt ::= 'insert' 'semantic' 'token' n::QNameType 'at' loc::Expr ';' @@ -359,7 +375,6 @@ top::ProductionStmt ::= 'insert' 'semantic' 'token' n::QNameType 'at' loc::Expr loc.decSiteVertexInfo = nothing(); loc.alwaysDecorated = false; loc.appDecSiteVertexInfo = nothing(); - loc.dispatchFlowDeps = []; } aspect production ifElseStmt top::ProductionStmt ::= 'if' '(' condition::Expr ')' th::ProductionStmt 'else' el::ProductionStmt @@ -367,7 +382,6 @@ top::ProductionStmt ::= 'if' '(' condition::Expr ')' th::ProductionStmt 'else' e condition.decSiteVertexInfo = nothing(); condition.alwaysDecorated = false; condition.appDecSiteVertexInfo = nothing(); - condition.dispatchFlowDeps = []; } aspect production termAttrValueValueDef top::ProductionStmt ::= @val::QName e::Expr @@ -375,7 +389,6 @@ top::ProductionStmt ::= @val::QName e::Expr e.decSiteVertexInfo = nothing(); e.alwaysDecorated = false; e.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = []; } -- We're in the unfortunate position of HAVING to compute values for 'flowDefs' diff --git a/grammars/silver/compiler/definition/flow/env/ProductionDcl.sv b/grammars/silver/compiler/definition/flow/env/ProductionDcl.sv index 79cdfa934..cfba77a07 100644 --- a/grammars/silver/compiler/definition/flow/env/ProductionDcl.sv +++ b/grammars/silver/compiler/definition/flow/env/ProductionDcl.sv @@ -36,7 +36,12 @@ top::AGDcl ::= 'abstract' 'production' id::Name d::ProductionImplements ns::Prod case d.implementsSig of | just(dSig) when isExportedBy(top.grammarName, [implode(":", init(explode(":", dSig.fullName)))], top.compiledGrammars) -> - [implFlowDef(dSig.fullName, fName, namedSig.inputNames)] + [implFlowDef(dSig.fullName, fName, namedSig.inputNames, + filterMap(\ ie::NamedSignatureElement -> + if ie.typerep.isNonterminal + then just((ie.elementName, ie.typerep.typeName)) + else nothing(), + drop(length(dSig.inputElements), namedSig.inputElements)))] | _ -> [] end; diff --git a/grammars/silver/compiler/definition/flow/env/Root.sv b/grammars/silver/compiler/definition/flow/env/Root.sv index bcc13be0c..7900aa62c 100644 --- a/grammars/silver/compiler/definition/flow/env/Root.sv +++ b/grammars/silver/compiler/definition/flow/env/Root.sv @@ -27,5 +27,4 @@ top::AGDcl ::= 'global' id::Name '::' cl::ConstraintList '=>' t::TypeExpr '=' e: e.decSiteVertexInfo = nothing(); e.alwaysDecorated = false; e.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = []; } diff --git a/grammars/silver/compiler/definition/flow/env/TypeClasses.sv b/grammars/silver/compiler/definition/flow/env/TypeClasses.sv index bb5aa8bc0..c3717bc79 100644 --- a/grammars/silver/compiler/definition/flow/env/TypeClasses.sv +++ b/grammars/silver/compiler/definition/flow/env/TypeClasses.sv @@ -13,7 +13,6 @@ top::ClassBodyItem ::= id::Name '::' cl::ConstraintList '=>' ty::TypeExpr '=' e: e.decSiteVertexInfo = nothing(); e.alwaysDecorated = false; e.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = []; } aspect production instanceBodyItem top::InstanceBodyItem ::= id::QName '=' e::Expr ';' @@ -21,5 +20,4 @@ top::InstanceBodyItem ::= id::QName '=' e::Expr ';' e.decSiteVertexInfo = nothing(); e.alwaysDecorated = false; e.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = []; } diff --git a/grammars/silver/compiler/driver/CompileLibrary.sv b/grammars/silver/compiler/driver/CompileLibrary.sv index f5c004992..4e55ed09a 100644 --- a/grammars/silver/compiler/driver/CompileLibrary.sv +++ b/grammars/silver/compiler/driver/CompileLibrary.sv @@ -16,6 +16,7 @@ MaybeT ::= grammarName::String libs::[String] -- IO Step 3: Perhaps complain it failed to deserialize. -- A failure to deserialize here is a fatal error, as it indicates a problem with the library jar file. + -- TODO: Calling exit here sometimes doesn't work right due to unsafeInterleaveIO. case ir of | left(msg) -> lift( do { diff --git a/grammars/silver/compiler/driver/util/FlowTypes.sv b/grammars/silver/compiler/driver/util/FlowTypes.sv index a9df6b1ec..3dc35ab57 100644 --- a/grammars/silver/compiler/driver/util/FlowTypes.sv +++ b/grammars/silver/compiler/driver/util/FlowTypes.sv @@ -34,7 +34,7 @@ top::Compilation ::= g::Grammars r::Grammars buildGrammars::[String] a::Decor -- Construct production graphs. production prodGraph :: [ProductionGraph] = map(constructProductionGraph(_, allFlowEnv, allRealEnv), allProds) ++ - -- Add in phantom, default and dispatch graphs + -- Add in phantom, default, tile and dispatch graphs flatMap(constructPhantomProductionGraph(_, allFlowEnv, allRealEnv), allNts) ++ flatMap(constructDefaultProductionGraph(_, allFlowEnv, allRealEnv), allNts) ++ map(constructDispatchGraph(_, allFlowEnv, allRealEnv), allDispatchSigs); diff --git a/grammars/silver/compiler/extension/autoattr/Monoid.sv b/grammars/silver/compiler/extension/autoattr/Monoid.sv index 429572c2f..56155a750 100644 --- a/grammars/silver/compiler/extension/autoattr/Monoid.sv +++ b/grammars/silver/compiler/extension/autoattr/Monoid.sv @@ -56,7 +56,6 @@ top::AGDcl ::= 'monoid' 'attribute' a::Name tl::BracketedOptTypeExprs '::' te::T e.decSiteVertexInfo = nothing(); e.alwaysDecorated = false; e.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = []; forwards to collectionAttributeDclSyn( diff --git a/grammars/silver/compiler/extension/autoattr/MonoidTrans.sv b/grammars/silver/compiler/extension/autoattr/MonoidTrans.sv index 88b3a7bf3..bceff31cb 100644 --- a/grammars/silver/compiler/extension/autoattr/MonoidTrans.sv +++ b/grammars/silver/compiler/extension/autoattr/MonoidTrans.sv @@ -51,7 +51,6 @@ top::AGDcl ::= 'monoid' 'translation' 'attribute' a::Name tl::BracketedOptTypeEx e.decSiteVertexInfo = nothing(); e.alwaysDecorated = false; e.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = []; forwards to defsAGDcl( [attrDef(defaultEnvItem(monoidTransDcl(fName, tl.freeVariables, te.typerep, ^e, app.lookupValue.fullName, sourceGrammar=top.grammarName, sourceLocation=a.nameLoc)))]); diff --git a/grammars/silver/compiler/extension/autoattr/Propagate.sv b/grammars/silver/compiler/extension/autoattr/Propagate.sv index 29874d74b..0e6f96507 100644 --- a/grammars/silver/compiler/extension/autoattr/Propagate.sv +++ b/grammars/silver/compiler/extension/autoattr/Propagate.sv @@ -148,6 +148,9 @@ dispatch Propagate = ProductionStmt ::= includeShared::Boolean @attr::QName; abstract production propagateError implements Propagate top::ProductionStmt ::= includeShared::Boolean @attr::QName { + -- Seeding flow deps + top.errors <- if false then [] else error(hackUnparse((attr.lookupAttribute, includeShared))); + forwards to errorProductionStmt( [errFromOrigin(attr, s"Attribute ${attr.name} cannot be propagated")]); diff --git a/grammars/silver/compiler/extension/easyterminal/TerminalDcl.sv b/grammars/silver/compiler/extension/easyterminal/TerminalDcl.sv index 30f16ce88..36415512e 100644 --- a/grammars/silver/compiler/extension/easyterminal/TerminalDcl.sv +++ b/grammars/silver/compiler/extension/easyterminal/TerminalDcl.sv @@ -86,6 +86,7 @@ concrete production aspectRHSElemEasyReg top::AspectRHSElem ::= reg::EasyTerminalRef { top.unparse = reg.unparse; + top.elementNames = []; propagate env; top.errors <- reg.errors; diff --git a/grammars/silver/compiler/extension/implicit_monads/Case.sv b/grammars/silver/compiler/extension/implicit_monads/Case.sv index 389c8c2a4..371fd482b 100644 --- a/grammars/silver/compiler/extension/implicit_monads/Case.sv +++ b/grammars/silver/compiler/extension/implicit_monads/Case.sv @@ -109,7 +109,6 @@ top::Expr ::= 'case' es::Exprs 'of' vbar::Opt_Vbar_t ml::MRuleList 'end' monadLocal.decSiteVertexInfo = nothing(); monadLocal.alwaysDecorated = false; monadLocal.appDecSiteVertexInfo = nothing(); - monadLocal.dispatchFlowDeps = []; monadLocal.isRoot = false; top.monadRewritten = monadLocal.monadRewritten; top.mtyperep = monadLocal.mtyperep; @@ -124,7 +123,7 @@ top::Expr ::= 'case' es::Exprs 'of' vbar::Opt_Vbar_t ml::MRuleList 'end' frame=top.frame; grammarName=top.grammarName; downSubst=top.mDownSubst; finalSubst=top.mDownSubst; compiledGrammars=top.compiledGrammars; config=top.config; decSiteVertexInfo = nothing(); alwaysDecorated = false; - appDecSiteVertexInfo = nothing(); dispatchFlowDeps = []; flowEnv=top.flowEnv; expectedMonad=top.expectedMonad; + appDecSiteVertexInfo = nothing(); flowEnv=top.flowEnv; expectedMonad=top.expectedMonad; isRoot=top.isRoot;} in if isMonad(a.mtyperep, top.env) && monadsMatch(a.mtyperep, top.expectedMonad, top.mDownSubst).fst && !isMonad(performSubstitution(x.snd, top.mDownSubst), top.env) @@ -134,7 +133,7 @@ top::Expr ::= 'case' es::Exprs 'of' vbar::Opt_Vbar_t ml::MRuleList 'end' config=top.config; flowEnv=top.flowEnv; monadicallyUsed=true; expectedMonad=top.expectedMonad; decSiteVertexInfo = nothing(); alwaysDecorated = false; - appDecSiteVertexInfo = nothing(); dispatchFlowDeps = []; isRoot=top.isRoot;}.monadicNames + appDecSiteVertexInfo = nothing(); isRoot=top.isRoot;}.monadicNames else [] end ++ l, monadLocal.monadicNames, zipWith(\x::Expr y::Type -> (x,y), es.rawExprs, ml.patternTypeList)); @@ -150,7 +149,8 @@ Boolean ::= elst::[Expr] env::Env sub::Substitution f::BlockContext gn::String | e::etl -> let etyp::Type = decorate e with {env=env; mDownSubst=sub; frame=f; grammarName=gn; downSubst=sub; finalSubst=sub; - compiledGrammars=cg; config=c; alwaysDecorated = false; flowEnv=fe; + compiledGrammars=cg; config=c; flowEnv=fe; + alwaysDecorated=false; decSiteVertexInfo=nothing(); appDecSiteVertexInfo=nothing(); expectedMonad=em; isRoot=iR;}.mtyperep in fst(monadsMatch(etyp, em, sub)) || monadicallyUsedExpr(etl, env, sub, f, gn, cg, c, fe, em, iR) @@ -419,7 +419,6 @@ top::Expr ::= 'case_any' es::Exprs 'of' vbar::Opt_Vbar_t ml::MRuleList 'end' decSiteVertexInfo = nothing(); alwaysDecorated = false; appDecSiteVertexInfo = nothing(); - dispatchFlowDeps = []; isRoot = top.isRoot; }.monadRewritten, caseExprs); @@ -435,7 +434,7 @@ top::Expr ::= 'case_any' es::Exprs 'of' vbar::Opt_Vbar_t ml::MRuleList 'end' compiledGrammars=top.compiledGrammars; grammarName=top.grammarName; frame=top.frame; downSubst=top.mDownSubst; finalSubst=top.mDownSubst; decSiteVertexInfo = top.decSiteVertexInfo; - appDecSiteVertexInfo = top.appDecSiteVertexInfo; dispatchFlowDeps = []; isRoot=top.isRoot; + appDecSiteVertexInfo = top.appDecSiteVertexInfo; isRoot=top.isRoot; }.typerep in if isMonad(ty, top.env) && monadsMatch(ty, top.expectedMonad, top.mDownSubst).fst @@ -490,8 +489,7 @@ Expr ::= exprs::[Expr] names::[String] base::Expr compiledGrammars=cg; config=c; flowEnv=fe; expectedMonad=^em; isRoot = iR; decSiteVertexInfo = nothing(); alwaysDecorated = false; - appDecSiteVertexInfo = nothing(); - dispatchFlowDeps = []; }.mtyperep + appDecSiteVertexInfo = nothing(); }.mtyperep in if isMonad(ety, env) && fst(monadsMatch(ety, ^em, sub)) then buildApplication( @@ -598,7 +596,6 @@ top::MatchRule ::= pt::PatternList arr::Arrow_kwd e::Expr ne.decSiteVertexInfo = nothing(); ne.appDecSiteVertexInfo = nothing(); ne.alwaysDecorated = false; - ne.dispatchFlowDeps = []; ne.isRoot = false; top.patternTypeList = pt.patternTypeList; @@ -621,7 +618,6 @@ top::MatchRule ::= pt::PatternList 'when' cond::Expr arr::Arrow_kwd e::Expr ncond.decSiteVertexInfo = nothing(); ncond.alwaysDecorated = false; ncond.appDecSiteVertexInfo = nothing(); - ncond.dispatchFlowDeps = []; ncond.isRoot = false; local ne::Expr = ^e; ne.flowEnv = top.temp_flowEnv; @@ -635,7 +631,6 @@ top::MatchRule ::= pt::PatternList 'when' cond::Expr arr::Arrow_kwd e::Expr ne.decSiteVertexInfo = nothing(); ne.alwaysDecorated = false; ne.appDecSiteVertexInfo = nothing(); - ne.dispatchFlowDeps = []; ne.isRoot = false; top.patternTypeList = pt.patternTypeList; @@ -658,7 +653,6 @@ top::MatchRule ::= pt::PatternList 'when' cond::Expr 'matches' p::Pattern arr::A ncond.decSiteVertexInfo = nothing(); ncond.alwaysDecorated = false; ncond.appDecSiteVertexInfo = nothing(); - ncond.dispatchFlowDeps = []; ncond.isRoot = false; local ne::Expr = ^e; ne.flowEnv = top.temp_flowEnv; @@ -672,7 +666,6 @@ top::MatchRule ::= pt::PatternList 'when' cond::Expr 'matches' p::Pattern arr::A ne.decSiteVertexInfo = nothing(); ne.alwaysDecorated = false; ne.appDecSiteVertexInfo = nothing(); - ne.dispatchFlowDeps = []; ne.isRoot = false; top.patternTypeList = pt.patternTypeList; @@ -725,7 +718,6 @@ top::AbstractMatchRule ::= pl::[Decorated Pattern] cond::Maybe<(Expr, Maybe syntaxDisambiguationGroup( s"Prefer_${toString(loc.line)}_${tName}__${implode("__", tsNames)}", - tName :: tsNames, false, pluckTAction.translation, + tName :: tsNames, false, actionCode(acodeSrc=pluckTAction.unparse, acodeTrans=pluckTAction.translation), location=loc, sourceGrammar=top.grammarName), tail(powerSet(ts.termList))); } action { diff --git a/grammars/silver/compiler/modification/defaultattr/DefaultAttr.sv b/grammars/silver/compiler/modification/defaultattr/DefaultAttr.sv index 85a935a23..8c9e7848e 100644 --- a/grammars/silver/compiler/modification/defaultattr/DefaultAttr.sv +++ b/grammars/silver/compiler/modification/defaultattr/DefaultAttr.sv @@ -107,7 +107,7 @@ top::DefLHS ::= @q::QName top.typerep = q.lookupValue.typeScheme.monoType; - top.defLHSVertex = lhsVertexType; + top.defLHSVertex = lhsVertexType(); top.defLHSInhEq = []; top.inhAttrName = ""; diff --git a/grammars/silver/compiler/modification/let_fix/DclInfo.sv b/grammars/silver/compiler/modification/let_fix/DclInfo.sv index 74a438e71..eb1ba7fe7 100644 --- a/grammars/silver/compiler/modification/let_fix/DclInfo.sv +++ b/grammars/silver/compiler/modification/let_fix/DclInfo.sv @@ -1,27 +1,28 @@ grammar silver:compiler:modification:let_fix; import silver:compiler:definition:flow:ast only VertexType, FlowVertex; +import silver:compiler:analysis:uniqueness only SharedRefSite; abstract production lexicalLocalDcl -top::ValueDclInfo ::= fn::String ty::Type fi::Maybe fd::[FlowVertex] +top::ValueDclInfo ::= fn::String ty::Type fi::Maybe fd::[FlowVertex] sr::[(String, SharedRefSite)] { top.fullName = fn; top.isEqual = -- Should never show up in an interface file anyway... case top.compareTo of - | lexicalLocalDcl(fn2, ty2, _, _) -> fn == fn2 && ^ty == ^ty2 + | lexicalLocalDcl(fn2, ty2, _, _, _) -> fn == fn2 && ^ty == ^ty2 | _ -> false end; top.typeScheme = monoType(^ty); - top.refDispatcher = lexicalLocalReference(fi, fd); + top.refDispatcher = lexicalLocalReference(fi, fd, sr); top.defDispatcher = errorValueDef; -- should be impossible (never in scope at production level?) top.defLHSDispatcher = errorDefLHS; -- ditto top.transDefLHSDispatcher = errorTransAttrDefLHS; } fun lexicalLocalDef -Def ::= sg::String sl::Location fn::String ty::Type fi::Maybe fd::[FlowVertex] = - valueDef(defaultEnvItem(lexicalLocalDcl(fn,ty,fi,fd,sourceGrammar=sg,sourceLocation=sl))); +Def ::= sg::String sl::Location fn::String ty::Type fi::Maybe fd::[FlowVertex] sr::[(String, SharedRefSite)] = + valueDef(defaultEnvItem(lexicalLocalDcl(fn,ty,fi,fd,sr,sourceGrammar=sg,sourceLocation=sl))); diff --git a/grammars/silver/compiler/modification/let_fix/Let.sv b/grammars/silver/compiler/modification/let_fix/Let.sv index eca650b8f..6570e3bf4 100644 --- a/grammars/silver/compiler/modification/let_fix/Let.sv +++ b/grammars/silver/compiler/modification/let_fix/Let.sv @@ -1,6 +1,7 @@ grammar silver:compiler:modification:let_fix; import silver:compiler:definition:flow:ast only VertexType, FlowVertex; +import silver:compiler:analysis:uniqueness only SharedRefSite; import silver:util:treeset as ts; --- Concrete Syntax for lets @@ -100,7 +101,7 @@ top::AssignExpr ::= id::Name '::' t::TypeExpr '=' e::Expr -- auto-undecorate feature, so that's why we bother substituting. -- (er, except that we're starting with t, which is a Type... must be because we fake these -- in e.g. the pattern matching code, so type variables might appear there?) - top.defs <- [lexicalLocalDef(top.grammarName, id.nameLoc, fName, semiTy, e.flowVertexInfo, e.flowDeps)]; + top.defs <- [lexicalLocalDef(top.grammarName, id.nameLoc, fName, semiTy, e.flowVertexInfo, e.flowDeps, e.sharedRefs)]; -- TODO: At present, this isn't working properly, because the local scope is -- whatever scope encloses the real local scope... hrmm! @@ -125,7 +126,7 @@ top::AssignExpr ::= id::Name '::' t::TypeExpr '=' e::Expr } abstract production lexicalLocalReference implements Reference -top::Expr ::= @q::QName fi::Maybe fd::[FlowVertex] +top::Expr ::= @q::QName fi::Maybe fd::[FlowVertex] sr::[(String, SharedRefSite)] { top.unparse = q.unparse; top.errors := []; diff --git a/grammars/silver/compiler/modification/let_fix/java/Let.sv b/grammars/silver/compiler/modification/let_fix/java/Let.sv index a401cf75e..348555981 100644 --- a/grammars/silver/compiler/modification/let_fix/java/Let.sv +++ b/grammars/silver/compiler/modification/let_fix/java/Let.sv @@ -55,7 +55,7 @@ fun makeSpecialLocalBinding String ::= fn::String et::String ty::String = s"final common.Thunk<${ty}> ${makeLocalValueName(fn)} = ${wrapThunkText(et, ty)};\n"; aspect production lexicalLocalReference -top::Expr ::= @q::QName _ _ +top::Expr ::= @q::QName _ _ _ { top.translation = makeLocalValueName(q.lookupValue.fullName) ++ ".eval()"; diff --git a/grammars/silver/compiler/modification/primitivepattern/PrimitiveMatch.sv b/grammars/silver/compiler/modification/primitivepattern/PrimitiveMatch.sv index 3c09838ff..19ce0f03d 100644 --- a/grammars/silver/compiler/modification/primitivepattern/PrimitiveMatch.sv +++ b/grammars/silver/compiler/modification/primitivepattern/PrimitiveMatch.sv @@ -33,6 +33,11 @@ tracked nonterminal PrimPattern with unparse, errors, freeVars, downSubst, upSubst, downSubst2, upSubst2, finalSubst, scrutineeType, returnType, translation, initTransDecSites, originRules; +flowtype PrimPattern = decorate { + env, config, compiledGrammars, grammarName, frame, originRules, finalSubst, downSubst, + flowEnv, decSiteVertexInfo, appDecSiteVertexInfo, alwaysDecorated, scrutineeVertexType, + scrutineeType, returnType +}; inherited attribute scrutineeType :: Type; inherited attribute returnType :: Type; @@ -59,7 +64,6 @@ top::Expr ::= e::Expr t::TypeExpr pr::PrimPatterns f::Expr propagate config, grammarName, env, freeVars, frame, compiledGrammars, finalSubst, originRules, flowEnv; e.decSiteVertexInfo = nothing(); e.appDecSiteVertexInfo = nothing(); - e.dispatchFlowDeps = []; e.isRoot = false; e.downSubst = top.downSubst; @@ -550,8 +554,8 @@ top::PrimPattern ::= h::Name t::Name e::Expr propagate finalSubst; local consdefs :: [Def] = - [lexicalLocalDef(top.grammarName, h.nameLoc, h_fName, elemType, nothing(), []), - lexicalLocalDef(top.grammarName, t.nameLoc, t_fName, top.scrutineeType, nothing(), [])]; + [lexicalLocalDef(top.grammarName, h.nameLoc, h_fName, elemType, nothing(), [], []), + lexicalLocalDef(top.grammarName, t.nameLoc, t_fName, top.scrutineeType, nothing(), [], [])]; e.env = newScopeEnv(consdefs, top.env); e.isRoot = false; diff --git a/grammars/silver/compiler/modification/primitivepattern/Types.sv b/grammars/silver/compiler/modification/primitivepattern/Types.sv index 00c0bfc35..912b5feab 100644 --- a/grammars/silver/compiler/modification/primitivepattern/Types.sv +++ b/grammars/silver/compiler/modification/primitivepattern/Types.sv @@ -397,6 +397,7 @@ top::OccursDclInfo ::= fnat::String ntty::Type atty::Type oc::Context tvs::[TyVa top.fullName = ntty.typeName; propagate compareTo, isEqual; top.attrOccurring = fnat; + top.attrTypeName = atty.typeName; top.typeScheme = monoType(^atty); oc.boundVariables = tvs; @@ -413,6 +414,7 @@ top::OccursDclInfo ::= fnat::String ntty::Type atty::Type oc::Context tvs::[TyVa top.fullName = ntty.typeName; propagate compareTo, isEqual; top.attrOccurring = fnat; + top.attrTypeName = atty.typeName; top.typeScheme = monoType(^atty); top.isAnnotation = true; diff --git a/grammars/silver/compiler/modification/primitivepattern/VarBinders.sv b/grammars/silver/compiler/modification/primitivepattern/VarBinders.sv index 7269761dd..a82fd7342 100644 --- a/grammars/silver/compiler/modification/primitivepattern/VarBinders.sv +++ b/grammars/silver/compiler/modification/primitivepattern/VarBinders.sv @@ -1,17 +1,14 @@ grammar silver:compiler:modification:primitivepattern; -option silver:compiler:analysis:warnings:flow; -- needed due to receivedDeps attribute - import silver:compiler:translation:java:core; import silver:compiler:translation:java:type; import silver:compiler:modification:let_fix only makeSpecialLocalBinding, lexicalLocalDef; -import silver:compiler:definition:flow:ast only just, PatternVarProjection, patternVarProjection, anonVertexType, VertexType, FlowVertex, inhVertex; +import silver:compiler:definition:flow:ast only just, PatternVarProjection, patternVarProjection, subtermVertexType, VertexType, FlowVertex, inhVertex; +import silver:compiler:definition:flow:env only scrutineeVertexType; -- also unfortunately placed references to flowEnv -import silver:compiler:analysis:warnings:flow only receivedDeps; -- Used in computing flow errors - tracked nonterminal VarBinders with config, grammarName, env, compiledGrammars, frame, unparse, errors, defs, boundNames, @@ -23,11 +20,17 @@ tracked nonterminal VarBinder with bindingType, bindingIndex, translation, finalSubst, flowProjections, bindingName, flowEnv, matchingAgainst; -flowtype decorate {grammarName, env, flowEnv, finalSubst, frame, compiledGrammars, config, bindingTypes, bindingIndex, bindingNames, matchingAgainst} on VarBinders; -flowtype decorate {grammarName, env, flowEnv, finalSubst, frame, compiledGrammars, config, bindingType, bindingIndex, bindingName, matchingAgainst} on VarBinder; +flowtype decorate { + grammarName, env, flowEnv, finalSubst, frame, compiledGrammars, config, + bindingTypes, bindingIndex, bindingNames, matchingAgainst, scrutineeVertexType +} on VarBinders; +flowtype decorate { + grammarName, env, flowEnv, finalSubst, frame, compiledGrammars, config, + bindingType, bindingIndex, bindingName, matchingAgainst, scrutineeVertexType +} on VarBinder; flowtype forward {decorate} on VarBinders, VarBinder; -flowtype errors {decorate, receivedDeps} on VarBinders, VarBinder; +flowtype errors {decorate} on VarBinders, VarBinder; flowtype defs {decorate} on VarBinders, VarBinder; flowtype boundNames {} on VarBinders, VarBinder; @@ -142,23 +145,26 @@ top::VarBinder ::= n::Name -- if it's not, then we treat it like a generic reference. top.flowProjections = if isDecorable(top.bindingType, top.env) - then [patternVarProjection(top.bindingName, top.bindingType.typeName, fName)] + then [patternVarProjection(top.bindingName, top.bindingType.typeName)] else []; -- because we don't have an 'anonEq' (the nonterminal stitch point gets generated for us by the above contribution) we won't be reported as missing in this production. Checks for presence in remote productions have to be done explicitly -- Recall that we emit (vertex, [reference set]) for expressions with a vertex. -- and the correct value is computed based on how this gets used. - -- TODO: Could this be simplified by using subtermVertexType instead of an anon vertex here? - local vt :: Maybe = - if isDecorable(top.bindingType, top.env) - then just(anonVertexType(fName)) + production vt :: Maybe = + if isDecorable(top.bindingType, top.env) && top.matchingAgainst.isJust + then just(subtermVertexType( + top.scrutineeVertexType, + top.matchingAgainst.fromJust.fullName, + top.bindingName)) else nothing(); local deps :: [FlowVertex] = - if isDecorable(top.bindingType, top.env) - then map(anonVertexType(fName).inhVertex, fromMaybe([], refSet)) - else []; + case vt of + | just(svt) -> map(svt.inhVertex, fromMaybe([], refSet)) + | _ -> [] + end; - top.defs <- [lexicalLocalDef(top.grammarName, n.nameLoc, fName, ty, vt, deps)]; + top.defs <- [lexicalLocalDef(top.grammarName, n.nameLoc, fName, ty, vt, deps, [])]; top.boundNames <- [n.name]; top.translation = diff --git a/grammars/silver/compiler/refactor/ExplicitUndec.sv b/grammars/silver/compiler/refactor/ExplicitUndec.sv index 4258cb3ed..b324333f8 100644 --- a/grammars/silver/compiler/refactor/ExplicitUndec.sv +++ b/grammars/silver/compiler/refactor/ExplicitUndec.sv @@ -72,7 +72,7 @@ top::Expr ::= @q::QName } aspect production lexicalLocalReference -top::Expr ::= @q::QName _ _ +top::Expr ::= @q::QName _ _ _ { top.transforms <- if top.config.refactorExplicitUndec diff --git a/grammars/silver/compiler/translation/java/core/NamedSignature.sv b/grammars/silver/compiler/translation/java/core/NamedSignature.sv index 4f736222d..b676bf12d 100644 --- a/grammars/silver/compiler/translation/java/core/NamedSignature.sv +++ b/grammars/silver/compiler/translation/java/core/NamedSignature.sv @@ -348,14 +348,14 @@ fun refDecSiteTranslation String ::= env::Env flowEnv::FlowEnv lhsNtName::String -- Returns either left(translation as a Lazy object) or right(translation as an access from context). fun refDecSiteTranslationHelp Either ::= env::Env flowEnv::FlowEnv lhsNtName::String v::VertexType = case v of - | lhsVertexType_real() -> error("lhs can't be a ref decoration site") + | lhsVertexType() -> error("lhs can't be a ref decoration site") | rhsVertexType(sigName) -> error("child can't be a ref decoration site") | localVertexType(fName) -> case getValueDcl(fName, env) of | dcl :: _ -> right(s"context.localDecorated(${dcl.attrOccursIndex})") | [] -> error("Couldn't find decl for local " ++ fName) end - | transAttrVertexType(lhsVertexType_real(), transAttr) -> + | transAttrVertexType(lhsVertexType(), transAttr) -> case getOccursDcl(transAttr, lhsNtName, env) of | h :: _ -> right(s"context.translation(${h.attrGlobalOccursInitIndex}, ${h.attrGlobalOccursInitIndex}_inhs, ${h.attrGlobalOccursInitIndex}_dec_site)") -- If a translation attribute occurrence is defined in an optionally exported grammar, @@ -363,9 +363,10 @@ fun refDecSiteTranslationHelp Either ::= env::Env flowEnv::FlowEn | [] -> left(s"common.RTTIManager.getNonterminalton(\"${lhsNtName}\").getTransDecSite(\"${transAttr}\")") end | transAttrVertexType(_, transAttr) -> error("trans attr on non-lhs can't be a ref decoration site") - | forwardVertexType_real() -> right(s"context.forward()") + | forwardVertexType() -> right(s"context.forward()") | forwardParentVertexType() -> error("forward parent shouldn't be a ref decoration site") - | anonVertexType(_) -> error("dec site projection shouldn't happen with anon decorate") + | anonVertexType(_, _, _) -> error("dec site projection shouldn't happen with anon decorate") + | anonScrutineeVertexType(_, _, _) -> error("dec site projection shouldn't happen with anon scrutinee") | subtermVertexType(parent, prodName, sigName) -> -- prodName is either a production or dispatch signature name case refDecSiteTranslationHelp(env, flowEnv, lhsNtName, parent) of diff --git a/grammars/silver/core/IO.sv b/grammars/silver/core/IO.sv index d09f79f97..672e719c4 100644 --- a/grammars/silver/core/IO.sv +++ b/grammars/silver/core/IO.sv @@ -160,7 +160,8 @@ abstract production exit top::IO ::= val::Integer { top.stateOut = exitT(val, top.stateIn); - top.stateVal = error("stateOut should've been evaluated first?"); + -- This can happen via unsafeInterleaveIO + top.stateVal = error("Exit called lazily - code " ++ toString(val)); } abstract production mkdir diff --git a/grammars/silver/core/List.sv b/grammars/silver/core/List.sv index 25d00a7df..65ada3bcf 100644 --- a/grammars/silver/core/List.sv +++ b/grammars/silver/core/List.sv @@ -391,6 +391,14 @@ fun unzipWith [c] ::= f::(c ::= a b) l::[(a, b)] = if null(l) then [] else f(head(l).1, head(l).2) :: unzipWith(f, tail(l)); +fun zipFst [(a, b)] ::= x::a ys::[b] = + if null(ys) then [] + else (x, head(ys)) :: zipFst(x, tail(ys)); + +fun zipSnd [(a, b)] ::= xs::[a] y::b = + if null(xs) then [] + else (head(xs), y) :: zipSnd(tail(xs), y); + fun zip [(a, b)] ::= l1::[a] l2::[b] = if null(l1) || null(l2) then [] else (head(l1), head(l2)) :: zip(tail(l1), tail(l2)); diff --git a/grammars/silver/core/Pair.sv b/grammars/silver/core/Pair.sv index 83f4d9749..46c3dba0b 100644 --- a/grammars/silver/core/Pair.sv +++ b/grammars/silver/core/Pair.sv @@ -65,4 +65,9 @@ Pair<[a] [b]> ::= lst::[Pair] else (head(lst).fst :: recurse.fst, head(lst).snd :: recurse.snd); } +@{-- + - Compute the Cartesian product of two lists. + -} +global cartProd :: ([Pair] ::= [a] [b]) = lift2(pair(fst=_, snd=_), _, _); + diff --git a/grammars/silver/util/Project.sv b/grammars/silver/util/Project.sv index a1efbb95b..691672114 100644 --- a/grammars/silver/util/Project.sv +++ b/grammars/silver/util/Project.sv @@ -4,6 +4,7 @@ grammar silver:util; imports silver:util:cmdargs; imports silver:util:deque; imports silver:util:graph; +imports silver:util:idcache; imports silver:util:random; imports silver:util:subprocess; imports silver:util:treemap; diff --git a/grammars/silver/util/idcache/IdCache.sv b/grammars/silver/util/idcache/IdCache.sv new file mode 100644 index 000000000..77c1da05d --- /dev/null +++ b/grammars/silver/util/idcache/IdCache.sv @@ -0,0 +1,34 @@ +grammar silver:util:idcache; + +@@{- + - A utility for mapping comparable objects to unique integer ids. + -} + +type IdCache foreign = "java.util.TreeMap"; + +@{-- + - Returns a new, empty, id cache using Ord for comparison. + -} +fun empty Ord a => IdCache ::= = emptyWith(compare); + +@{-- + - Returns a new, empty, id cache using the specified comparator. + -} +function emptyWith +IdCache ::= comparator::(Integer ::= a a) +{ + return error("NYI"); +} foreign { + "java" : return "common.rawlib.RawIdCache.empty(%comparator%)"; +} + +@{-- + - Lookup a key from the id cache, generating a new id if not present. + -} +function lookup +Integer ::= key::a cache::IdCache +{ + return error("NYI"); +} foreign { + "java" : return "common.rawlib.RawIdCache.lookup(%key%, %cache%)"; +} diff --git a/make-compiler b/make-compiler index b212ceafc..aceb5f4d3 100755 --- a/make-compiler +++ b/make-compiler @@ -9,7 +9,7 @@ silver_version=`git describe --tags` echo "Build version $silver_version" export SILVER_HOME=$PWD -JVM_ARGS=(-Xss20M -Xmx6500M -jar ../jars/silver.compiler.composed.Default.jar --no-stdlib --include-jar ../jars/CopperCompiler.jar --include-jar ../jars/commonmark-0.17.1.jar --relative-jar "$@" --jar-impl-version "$silver_version") +JVM_ARGS=(-Xss20M -Xmx7500M -jar ../jars/silver.compiler.composed.Default.jar --no-stdlib --include-jar ../jars/CopperCompiler.jar --include-jar ../jars/commonmark-0.17.1.jar --relative-jar "$@" --jar-impl-version "$silver_version") export GRAMMAR_PATH="../grammars" export ANT_OPTS=-Xss10M diff --git a/runtime/java/src/common/rawlib/RawIdCache.java b/runtime/java/src/common/rawlib/RawIdCache.java new file mode 100644 index 000000000..b81d03b47 --- /dev/null +++ b/runtime/java/src/common/rawlib/RawIdCache.java @@ -0,0 +1,16 @@ +package common.rawlib; + +import java.util.TreeMap; + +import common.NodeFactory; +import common.javainterop.SilverComparator; + +public final class RawIdCache { + public static TreeMap empty(NodeFactory cmp) { + return new TreeMap(new SilverComparator(cmp)); + } + public static Integer lookup(Object k, TreeMap t) { + if(!t.containsKey(k)) t.put(k, t.size()); + return t.get(k); + } +} diff --git a/test/flow/Dispatch.sv b/test/flow/Dispatch.sv index 3cc6b18f8..0e275bd68 100644 --- a/test/flow/Dispatch.sv +++ b/test/flow/Dispatch.sv @@ -93,7 +93,7 @@ UDExpr ::= e::UDExpr } } -warnCode "Dispatching may require inherited attribute(s) flow:env2 on e, but these attribute(s) are supplied here after dispatching" { +warnCode "Potentially missing inherited override equation for flow:env2 on e; a cycle may exist via its sharing decoration site forward[flow:DispatchOp:e1]" { production dispatchCycle top::UDExpr ::= e::UDExpr { @@ -121,7 +121,7 @@ top::UDExpr ::= e::UDExpr top.errors2 = !null(e.env1); } -warnCode "Dispatching may require inherited attribute(s) flow:env2 on e, but these attribute(s) are supplied here after dispatching" { +warnCode "Potentially missing inherited override equation for flow:env2 on e; a cycle may exist via its sharing decoration site forward[flow:DispatchOp2:e]" { production dispatchCycle2 top::UDExpr ::= e::UDExpr { diff --git a/test/flow/FlowSpecs.sv b/test/flow/FlowSpecs.sv index d8c4accf5..a1cdc759e 100644 --- a/test/flow/FlowSpecs.sv +++ b/test/flow/FlowSpecs.sv @@ -12,6 +12,14 @@ wrongCode "Declaration of global missingRes with type Decorated flow:FSExpr2 wit global missingRes::Decorated FSExpr2 = decorate fse() with {}; } +warnCode "Forward equation exceeds flow type with dependencies on flow:env2" { +production fseForwardExceedsSpec +top::FSExpr ::= e::FSExpr +{ + forwards to if null(top.env2) then fse() else @e; +} +} + nonterminal FSExpr2 with env1, env2; wrongCode "circularity in flow specification for decorate on flow:FSExpr2" { diff --git a/test/flow/FwrdInh.sv b/test/flow/FwrdInh.sv index 9c03b4dd2..82dac6273 100644 --- a/test/flow/FwrdInh.sv +++ b/test/flow/FwrdInh.sv @@ -11,3 +11,29 @@ top::FIExpr ::= e::FIExpr forwards to ^e; } } + +production fie +top::FIExpr ::= +{ + top.errors1 = null(top.env1); +} + +nonterminal FIExtExpr with errors1, toFIE; +translation attribute toFIE::FIExpr; + +production fieExt +top::FIExtExpr ::= +{ + top.toFIE = fie(); + top.errors1 = false; +} + +warnCode "Access of inherited attribute env1 on forward.toFIE requires missing inherited attribute(s) flow:env1 to be supplied to translation attribute flow:toFIE of forward of production flow:fieExtFwrd" { +production fieExtFwrd +top::FIExtExpr ::= e::FIExtExpr +{ + top.toFIE = @e.toFIE; + top.errors1 = null(forward.toFIE.env1); + forwards to fieExt(); +} +} \ No newline at end of file diff --git a/test/flow/OccursContext.sv b/test/flow/OccursContext.sv index 14a9d18a3..7aaa9384d 100644 --- a/test/flow/OccursContext.sv +++ b/test/flow/OccursContext.sv @@ -19,7 +19,7 @@ Boolean ::= x::a y::a return x.isEqual; } -warnCode "Equation requires inherited attribute flow:env1 be supplied to child x of production flow:isEqualBad" { +warnCode "Access of synthesized attribute isEqual on x requires missing inherited attribute(s) flow:env1 to be supplied to child x of production flow:isEqualBad" { function isEqualBad attribute compareTo occurs on a, attribute isEqual {compareTo, env1} occurs on a => @@ -36,7 +36,7 @@ global isEqualGlobal :: (Boolean ::= a a) = \ x::a y::a -> decorate x with {compareTo = decorate y with {};}.isEqual; -warnCode "Decoration requires inherited attribute for flow:env1." { +warnCode "requires missing inherited attribute(s) silver:core:compareTo, flow:env1 to be supplied to anonymous decoration site" { global isEqualGlobalBad :: attribute compareTo occurs on a, attribute isEqual {compareTo, env1} occurs on a => @@ -71,7 +71,7 @@ class Equal1 a { isEqual1 :: (Boolean ::= a a); } -warnCode "Decoration requires inherited attribute for flow:env1." { +warnCode "requires missing inherited attribute(s) silver:core:compareTo, flow:env1 to be supplied to anonymous decoration site" { instance attribute compareTo occurs on a, attribute isEqual {compareTo, env1} occurs on a => Equal1 a { @@ -80,7 +80,7 @@ instance attribute compareTo occurs on a, } } -warnCode "Decoration requires inherited attribute for flow:env1." { +warnCode "requires missing inherited attribute(s) silver:core:compareTo, flow:env1 to be supplied to anonymous decoration site" { class attribute compareTo occurs on a, attribute isEqual {compareTo, env1} occurs on a => Equal2 a { diff --git a/test/flow/RefSiteProj.sv b/test/flow/RefSiteProj.sv index 446e2619f..85f48bdc9 100644 --- a/test/flow/RefSiteProj.sv +++ b/test/flow/RefSiteProj.sv @@ -1,5 +1,7 @@ grammar flow; +imports flow:ext; + nonterminal RSExpr with env1, env2, errors1, errors2; flowtype RSExpr = errors1 {env1}, errors2 {env1, env2}; @@ -12,6 +14,16 @@ top::RSExpr ::= e::RSExpr top.errors2 = false; } +production copy2 +top::RSExpr ::= e::RSExpr +{ + e.env1 = top.env1; + e.env2 = top.env2; + + top.errors1 = false; + top.errors2 = e.errors2; +} + production copy12 top::RSExpr ::= e::RSExpr { @@ -159,8 +171,7 @@ top::RSExpr ::= e::RSExpr } } -warnCode "may exceed a flow type with hidden transitive dependencies" { -production remoteExceedsOverride +production remoteExceedsOverrideOk top::RSExpr ::= e::RSExpr { e.env1 = top.env1; @@ -172,10 +183,21 @@ top::RSExpr ::= e::RSExpr top.errors1 = e.errors1; top.errors2 = e.errors2; } -} warnCode "equation errors1 exceeds flow type with dependencies on flow:env2" { -production uselessOverrideExceedsFT +production uselessOverrideStillExceedsFT +top::RSExpr ::= e::RSExpr +{ + e.env1 = top.env2; + local e1::RSExpr = @e; + e1.env1 = top.env1; -- Override equation has no effect on deps of e1.env1 + + top.errors1 = e1.errors1; + top.errors2 = false; +} +} + +production uselessOverrideNotHiddenTransDep top::RSExpr ::= e::RSExpr { e.env1 = top.env1; @@ -185,9 +207,8 @@ top::RSExpr ::= e::RSExpr top.errors1 = e1.errors1; top.errors2 = false; } -} -warnCode "may exceed a flow type with hidden transitive dependencies" { +warnCode "equation errors1 exceeds flow type with dependencies on flow:env2" { production uselessOverrideWithinFT top::RSExpr ::= e::RSExpr { @@ -200,7 +221,7 @@ top::RSExpr ::= e::RSExpr } } -warnCode "may exceed a flow type with hidden transitive dependencies" { +warnCode "the implicit copy equation for flow:errors1 (due to forwarding) would exceed the attribute's flow type with dependencies on flow:env2" { production fwrdDecSiteExceedsFT top::RSExpr ::= e::RSExpr { @@ -209,7 +230,7 @@ top::RSExpr ::= e::RSExpr } } -warnCode "may exceed a flow type with hidden transitive dependencies" { +warnCode "the implicit copy equation for flow:errors1 (due to forwarding) would exceed the attribute's flow type with dependencies on flow:env2" { production projExceedsFT top::RSExpr ::= e::RSExpr { @@ -219,7 +240,7 @@ top::RSExpr ::= e::RSExpr } } -warnCode "may exceed a flow type with hidden transitive dependencies" { +warnCode "the implicit copy equation for flow:errors1 (due to forwarding) would exceed the attribute's flow type with dependencies on flow:env2" { production condDecExceedsFT top::RSExpr ::= e::RSExpr { @@ -237,13 +258,13 @@ top::RSExpr ::= e::RSExpr if top.env1 == [] then copy12From2(@e) else base(); } -warnCode "may exceed a flow type with hidden transitive dependencies" { -production overrideNotInRefSet +warnCode "Access of synthesized attribute errors1 on e1 requires missing inherited attribute(s) flow:env1 to be supplied to local" { +production noReverseSharing top::RSExpr ::= e::RSExpr { e.env1 = top.env1; e.env2 = top.env2; - local e1::Expr = @e; + local e1::RSExpr = @e; -- No equation for e1.env1 e1.env2 = []; top.errors1 = e1.errors1; top.errors2 = e1.errors2; @@ -300,8 +321,7 @@ top::RSExpr ::= e::RSExpr top.errors2 = e.errors2; } -warnCode "may exceed a flow type with hidden transitive dependencies" { -production anonDecOverrideExceedsFT +production anonDecUselessOverrideOk top::RSExpr ::= e::RSExpr { e.env1 = []; @@ -310,7 +330,6 @@ top::RSExpr ::= e::RSExpr top.errors1 = e.errors1; top.errors2 = e.errors2; } -} production projChain top::RSExpr ::= e::RSExpr @@ -386,7 +405,7 @@ top::RSExpr ::= e::RSExpr end; } -warnCode "Equation requires inherited attribute flow:env1 be supplied to child e of production flow:condShareInLetBindingDep" { +warnCode "Access of synthesized attribute errors1 on e requires missing inherited attribute(s) flow:env1 to be supplied to child e of production flow:condShareInLetBindingDep" { production condShareInLetBindingDep top::RSExpr ::= e::RSExpr { @@ -420,4 +439,18 @@ top::RSExpr ::= e::RSExpr in fork(e1, e1) end; } -} \ No newline at end of file +} + +production forwardOuterDepsOk +top::RSExpr ::= e::RSExpr +{ + forwards to copy2(if null(top.env2) then base() else @e); +} + +warnCode "In production flow:forwardSubtreeEqTransDepExceedsFT, the implicit copy equation for flow:errors1 (due to forwarding) would exceed the attribute's flow type with dependencies on flow:env2" { +production forwardSubtreeEqTransDepExceedsFT +top::RSExpr ::= e::RSExpr +{ + forwards to copy12(if null(top.env2) then base() else @e); +} +} diff --git a/test/flow/References.sv b/test/flow/References.sv index 4c6c1a3ca..93ab19bb9 100644 --- a/test/flow/References.sv +++ b/test/flow/References.sv @@ -24,7 +24,7 @@ Decorated Expr ::= x::Expr return x; } -warnCode "Equation requires inherited attribute flow:env1 be supplied to child x of production flow:getRefEnv1Missing" { +warnCode "Taking a reference to x requires missing inherited attribute(s) flow:env1 to be supplied to child x of production flow:getRefEnv1Missing" { function getRefEnv1Missing Decorated Expr with {env1} ::= x::Expr { return x; } diff --git a/test/flow/ext/Dispatch.sv b/test/flow/ext/Dispatch.sv new file mode 100644 index 000000000..60080921f --- /dev/null +++ b/test/flow/ext/Dispatch.sv @@ -0,0 +1,23 @@ +grammar flow:ext; + +warnCode "Inherited override equation for flow:env2 on child e has excess dependencies" { +production extDispatchInhExceedsHost implements DispatchOp2 +top::UDExpr ::= e::UDExpr +{ + e.env2 = if e.errors1 then [] else top.env1; + + local prod::DispatchOp2 = doimpl1; + forwards to prod(@e); +} +} + +warnCode "Synthesized override equation for flow:errors1 has excess dependencies" { +production extDispatchSynExceedsHost implements DispatchOp2 +top::UDExpr ::= e::UDExpr +{ + top.errors1 = !null(e.env2); + + local prod::DispatchOp2 = doimpl1; + forwards to prod(@e); +} +} diff --git a/test/flow/ext/RefSiteProj.sv b/test/flow/ext/RefSiteProj.sv new file mode 100644 index 000000000..cf7a7c4f6 --- /dev/null +++ b/test/flow/ext/RefSiteProj.sv @@ -0,0 +1,83 @@ +grammar flow:ext; + +imports flow; + +warnCode "may exceed a flow type with hidden transitive dependencies" { +production remoteExceedsOverrideInExt +top::RSExpr ::= e::RSExpr +{ + e.env1 = top.env1; + + local e1::RSExpr = copy12(copy12From2(copy12(@e))); + e1.env1 = top.env1; + e1.env2 = top.env2; + + top.errors1 = e.errors1; + top.errors2 = e.errors2; +} +} + +warnCode "flow:env1 on child e may exceed a flow type with hidden transitive dependencies on flow:env1; on some reference to this tree, this attribute may be expected to depend only on flow:env2" { +production uselessOverrideHiddenTransDepInExt +top::RSExpr ::= e::RSExpr +{ + e.env1 = top.env1; -- Hidden transitive dependency + local e1::RSExpr = @e; + e1.env1 = top.env2; + + top.errors1 = e1.errors1; + top.errors2 = false; +} +} + +warnCode "may exceed a flow type with hidden transitive dependencies" { +production fwrdDecSiteExceedsFTInExt +top::RSExpr ::= e::RSExpr +{ + e.env1 = top.env2; + forwards to @e; +} +} + +warnCode "may exceed a flow type with hidden transitive dependencies" { +production projExceedsFTInExt +top::RSExpr ::= e::RSExpr +{ + local e1::RSExpr = copy12(@e); + e1.env1 = top.env2; + forwards to @e1; +} +} + +warnCode "may exceed a flow type with hidden transitive dependencies" { +production condDecExceedsFTInExt +top::RSExpr ::= e::RSExpr +{ + e.env1 = top.env2; + forwards to + if top.env1 == [] then copy12(@e) else base(); +} +} + +warnCode "may exceed a flow type with hidden transitive dependencies" { +production overrideHiddenTransitiveDepInExt +top::RSExpr ::= e::RSExpr +{ + e.env1 = top.env1; + e.env2 = top.env2; + local e1::RSExpr = @e; + e1.env2 = []; +} +} + +warnCode "may exceed a flow type with hidden transitive dependencies" { +production anonDecUselessOverrideExceedsFTInExt +top::RSExpr ::= e::RSExpr +{ + e.env1 = []; + e.env2 = top.env1 ++ top.env2; + local d::Decorated RSExpr with {env2} = decorate @e with {env2 = top.env2;}; + top.errors1 = e.errors1; + top.errors2 = e.errors2; +} +}