From c8e6d33320d7e5ec278f5b34252b0976472a895e Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Wed, 1 Apr 2020 16:19:54 -0500 Subject: [PATCH 01/78] Initial skeleton of strategy attribute implementation --- .../silver/extension/strategyattr/DclInfo.sv | 28 ++ .../silver/extension/strategyattr/Project.sv | 13 + .../silver/extension/strategyattr/Strategy.sv | 91 +++++++ .../extension/strategyattr/StrategyExpr.sv | 257 ++++++++++++++++++ .../extension/strategyattr/StrategyUtils.sv | 65 +++++ .../extension/strategyattr/Terminals.sv | 18 ++ .../strategyattr/convenience/Convenience.sv | 20 ++ grammars/silver/host/Project.sv | 1 + 8 files changed, 493 insertions(+) create mode 100644 grammars/silver/extension/strategyattr/DclInfo.sv create mode 100644 grammars/silver/extension/strategyattr/Project.sv create mode 100644 grammars/silver/extension/strategyattr/Strategy.sv create mode 100644 grammars/silver/extension/strategyattr/StrategyExpr.sv create mode 100644 grammars/silver/extension/strategyattr/StrategyUtils.sv create mode 100644 grammars/silver/extension/strategyattr/Terminals.sv create mode 100644 grammars/silver/extension/strategyattr/convenience/Convenience.sv diff --git a/grammars/silver/extension/strategyattr/DclInfo.sv b/grammars/silver/extension/strategyattr/DclInfo.sv new file mode 100644 index 000000000..de3c14963 --- /dev/null +++ b/grammars/silver/extension/strategyattr/DclInfo.sv @@ -0,0 +1,28 @@ +grammar silver:extension:strategyattr; + +synthesized attribute strategyExpr :: StrategyExpr occurs on DclInfo; + +aspect default production +top::DclInfo ::= +{ + top.strategyExpr = error("Internal compiler error: must be defined for all strategy attribute declarations"); +} + +abstract production strategyDcl +top::DclInfo ::= sg::String sl::Location fn::String tyVar::TyVar e::StrategyExpr +{ + top.sourceGrammar = sg; + top.sourceLocation = sl; + top.fullName = fn; + + top.typerep = nonterminalType("core:Maybe", [varType(tyVar)]); + top.dclBoundVars = [tyVar]; + top.isSynthesized = true; + + top.decoratedAccessHandler = synDecoratedAccessHandler(_, _, location=_); + top.undecoratedAccessHandler = accessBounceDecorate(synDecoratedAccessHandler(_, _, location=_), _, _, _); + top.attrDefDispatcher = synthesizedAttributeDef(_, _, _, location=_); -- Allow normal syn equations + top.attributionDispatcher = strategyAttributionDcl(_, _, _, _, location=_); + top.propagateDispatcher = propagateFunctor(_, location=_); + top.strategyExpr = e; +} diff --git a/grammars/silver/extension/strategyattr/Project.sv b/grammars/silver/extension/strategyattr/Project.sv new file mode 100644 index 000000000..94a6d1eb1 --- /dev/null +++ b/grammars/silver/extension/strategyattr/Project.sv @@ -0,0 +1,13 @@ +grammar silver:extension:strategyattr; + +imports silver:definition:core; +imports silver:definition:env; +imports silver:definition:type; +imports silver:definition:type:syntax; +imports silver:extension:autoattr; +imports silver:extension:patternmatching; +imports silver:extension:list; +--imports silver:extension:rewriting; +imports silver:modification:let_fix; + +exports silver:extension:strategyattr:convenience; diff --git a/grammars/silver/extension/strategyattr/Strategy.sv b/grammars/silver/extension/strategyattr/Strategy.sv new file mode 100644 index 000000000..47db57e2f --- /dev/null +++ b/grammars/silver/extension/strategyattr/Strategy.sv @@ -0,0 +1,91 @@ +grammar silver:extension:strategyattr; + +import silver:definition:flow:driver only ProductionGraph, FlowType, constructAnonymousGraph; +import silver:driver:util; + +concrete production strategyAttributeDcl +top::AGDcl ::= 'strategy' 'attribute' a::Name '=' e::StrategyExpr ';' +{ + top.unparse = "strategy attribute " ++ a.unparse ++ ";"; + + production attribute fName :: String; + fName = top.grammarName ++ ":" ++ a.name; + + -- Define these directly to avoid flow errors + propagate errors, moduleNames; + + top.errors <- + if length(getAttrDclAll(fName, top.env)) > 1 + then [err(a.location, "Attribute '" ++ fName ++ "' is already bound.")] + else []; + + -- Frame doesn't really matter, since we will re-check any expressions occuring in e when propagated. + -- Need all this to construct a bogus frame... + local myFlow :: EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).grammarFlowTypes; + local myProds :: EnvTree = head(searchEnvTree(top.grammarName, top.compiledGrammars)).productionFlowGraphs; + local myFlowGraph :: ProductionGraph = + constructAnonymousGraph(e.flowDefs, top.env, myProds, myFlow); + e.frame = globalExprContext(myFlowGraph); + + forwards to + defsAGDcl( + [attrDef(defaultEnvItem(strategyDcl(top.grammarName, a.location, fName, freshTyVar(), e)))], + location=top.location); +} + +abstract production strategyAttributionDcl +top::AGDcl ::= at::Decorated QName attl::BracketedOptTypeExprs nt::QName nttl::BracketedOptTypeExprs +{ + forwards to + defaultAttributionDcl( + at, + if length(attl.types) > 0 + then attl + else + botlSome( + '<', + typeListSingle( + nominalTypeExpr(nt.qNameType, nttl, location=top.location), + location=top.location), + '>', location=top.location), + nt, nttl, + location=top.location); +} + +{-- + - Propagate a strategy attribute on the enclosing production + - @param attr The name of the attribute to propagate + -} +abstract production propagateStrategy +top::ProductionStmt ::= attr::Decorated QName +{ + -- No explicit errors, for now. The only conceivable issue is the attribute not + -- occuring on the LHS but this should be caught by the forward errors. + + -- Generate the arguments for the constructor + local topName::QName = qName(top.location, top.frame.signature.outputElement.elementName); + local prodName::QName = qName(top.location, top.frame.fullName); + prodName.grammarName = top.grammarName; + prodName.config = top.config; + prodName.env = top.env; + + local inputs :: [Expr] = + map(makeArg(top.location, top.env, attr, _), top.frame.signature.inputElements); + local annotations :: [Pair] = + map(makeAnnoArg(top.location, topName, _), top.frame.signature.namedInputElements); + + -- Construct an attribute def and call with the generated arguments + forwards to + attributeDef( + concreteDefLHS(topName, location=top.location), + '.', + qNameAttrOccur(new(attr), location=top.location), + '=', + mkFullFunctionInvocation( + top.location, + baseExpr(prodName, location=top.location), + inputs, + annotations), + ';', + location=top.location); +} diff --git a/grammars/silver/extension/strategyattr/StrategyExpr.sv b/grammars/silver/extension/strategyattr/StrategyExpr.sv new file mode 100644 index 000000000..87362f1a9 --- /dev/null +++ b/grammars/silver/extension/strategyattr/StrategyExpr.sv @@ -0,0 +1,257 @@ +grammar silver:extension:strategyattr; + +inherited attribute attrName::String; -- Used to generate the names of lifted strategy attributes + +monoid attribute liftedAttrs::[Pair] with [], ++; +synthesized attribute isId::Boolean; +synthesized attribute isFail::Boolean; + +nonterminal StrategyExpr with + config, grammarName, env, location, unparse, errors, frame, compiledGrammars, flowEnv, flowDefs, -- Normal expression stuff + attrName, liftedAttrs, isId, isFail; + +propagate errors, flowDefs, liftedAttrs on StrategyExpr; + +abstract production nameStrategy +top::StrategyExpr ::= id::QName +{ + top.unparse = id.unparse; + + top.errors <- id.lookupAttribute.errors; + -- TODO: Type checking! +} + +-- Basic combinators +concrete production idStrategy +top::StrategyExpr ::= 'id' +{ + top.unparse = "id"; + top.isId = true; + top.isFail = false; +} + +concrete production failStrategy +top::StrategyExpr ::= 'fail' +{ + top.unparse = "fail"; + top.isId = false; + top.isFail = true; +} + +concrete production sequenceStrategy +top::StrategyExpr ::= s1::StrategyExpr '<*' s2::StrategyExpr +{ + top.unparse = "(${s1.pp} <* ${s2.pp})"; + top.isId = s1.isId && s2.isId; + top.isFail = s1.isFail || s2.isFail; +} + +concrete production choiceStrategy +top::StrategyExpr ::= s1::StrategyExpr '<+' s2::StrategyExpr +{ + top.unparse = "(${s1.pp} <+ ${s2.pp})"; + top.isId = s1.isId || (s1.isFail && s2.isId); + top.isFail = s1.isFail && s2.isFail; +} + +-- Traversals +concrete production allStrategy +top::StrategyExpr ::= 'all' '(' s::StrategyExpr ')' +{ + top.unparse = "all(${s.pp})"; + -- TODO: Can be more specific here + top.isId = s.isId; + top.isFail = s.isFail; +} + +concrete production someStrategy +top::StrategyExpr ::= 'some' '(' s::StrategyExpr ')' +{ + top.unparse = "some(${s.pp})"; + -- TODO: Can be more specific here + top.isId = s.isId; + top.isFail = s.isFail; +} + +concrete production oneStrategy +top::StrategyExpr ::= 'one' '(' s::StrategyExpr ')' +{ + top.unparse = "one(${s.pp})"; + -- TODO: Can be more specific here + top.isId = s.isId; + top.isFail = s.isFail; +} + + +-- Rules +concrete production ruleStrategy +top::StrategyExpr ::= 'rule' 'on' ty::TypeExpr 'of' Opt_Vbar_t ml::MRuleList 'end' +{ + top.unparse = "rule on " ++ ty.unparse ++ " of " ++ ml.unparse ++ " end"; + top.isId = false; -- Unusual, and no way of checking this without decorating RHSs + top.isFail = ml.isFail; + + -- Pattern matching error checking (mostly) happens on what caseExpr forwards to, + -- so we need to decorate one of those here. + local checkExpr::Expr = + caseExpr( + [hackExprType(ty.typerep, location=top.location)], + ml.matchRuleList, + errorExpr([], location=top.location), + ty.typerep, + location=top.location); + checkExpr.env = top.env; + checkExpr.flowEnv = top.flowEnv; + checkExpr.downSubst = emptySubst(); + checkExpr.finalSubst = checkExpr.upSubst; + checkExpr.grammarName = top.grammarName; + checkExpr.frame = top.frame; + checkExpr.config = top.config; + checkExpr.compiledGrammars = top.compiledGrammars; + + top.errors <- checkExpr.errors; + + top.flowDefs <- checkExpr.flowDefs; + + ml.matchRulePatternSize = 1; +} + +-- Hack dummy expr with a given type +abstract production hackExprType +top::Expr ::= t::Type +{ + top.typerep = t; + forwards to errorExpr([], location=top.location); +} + +attribute isFail occurs on MRuleList, MatchRule; + +aspect production mRuleList_one +top::MRuleList ::= m::MatchRule +{ + top.isFail = m.isFail; +} + +aspect production mRuleList_cons +top::MRuleList ::= h::MatchRule '|' t::MRuleList +{ + top.isFail = h.isFail && t.isFail; +} + +aspect production matchRule_c +top::MatchRule ::= pt::PatternList _ e::Expr +{ + top.isFail = false; -- TODO +} + +aspect production matchRuleWhen_c +top::MatchRule ::= pt::PatternList 'when' cond::Expr _ e::Expr +{ + top.isFail = false; -- TODO +} + +aspect production patternList_one +top::PatternList ::= p::Pattern +{ + +} +aspect production patternList_more +top::PatternList ::= p::Pattern ',' ps::PatternList +{ + +} + +aspect production patternList_nil +top::PatternList ::= +{ + +} + +aspect production namedPatternList_one +top::NamedPatternList ::= p::NamedPattern +{ + +} +aspect production namedPatternList_more +top::NamedPatternList ::= p::NamedPattern ',' ps::NamedPatternList +{ + +} + +aspect production namedPatternList_nil +top::NamedPatternList ::= +{ + +} + +aspect production namedPattern +top::NamedPattern ::= qn::QName '=' p::Pattern +{ + +} + +aspect production prodAppPattern_named +top::Pattern ::= prod::QName '(' ps::PatternList ',' nps::NamedPatternList ')' +{ + +} + +aspect production wildcPattern +top::Pattern ::= '_' +{ + +} + +aspect production varPattern +top::Pattern ::= v::Name +{ + +} + +aspect production errorPattern +top::Pattern ::= msg::[Message] +{ + +} + +aspect production intPattern +top::Pattern ::= num::Int_t +{ + +} + +aspect production fltPattern +top::Pattern ::= num::Float_t +{ + +} + +aspect production strPattern +top::Pattern ::= str::String_t +{ + +} + +aspect production truePattern +top::Pattern ::= 'true' +{ + +} + +aspect production falsePattern +top::Pattern ::= 'false' +{ + +} + +aspect production nilListPattern +top::Pattern ::= '[' ']' +{ + +} + +aspect production consListPattern +top::Pattern ::= hp::Pattern '::' tp::Pattern +{ + +} diff --git a/grammars/silver/extension/strategyattr/StrategyUtils.sv b/grammars/silver/extension/strategyattr/StrategyUtils.sv new file mode 100644 index 000000000..d148b374b --- /dev/null +++ b/grammars/silver/extension/strategyattr/StrategyUtils.sv @@ -0,0 +1,65 @@ +grammar silver:extension:strategyattr; + + +{- +-- Utilities +abstract production recStrategy +top::StrategyExpr ::= ctr::(StrategyExpr ::= StrategyExpr) +{ + forwards to ctr(top); +} + +abstract production try +top::StrategyExpr ::= s::StrategyExpr +{ + forwards to s <+ id(); +} + +abstract production repeat +top::StrategyExpr ::= s::StrategyExpr +{ + forwards to try(s <* repeat(s)); +} + +abstract production reduce +top::StrategyExpr ::= s::StrategyExpr +{ + forwards to repeat(rec(\ x::StrategyExpr -> some(x) <+ s)); +} + +abstract production bottomUp +top::StrategyExpr ::= s::StrategyExpr +{ + forwards to all(bottomUp(s)) <* s; +} + +abstract production topDown +top::StrategyExpr ::= s::StrategyExpr +{ + forwards to s <* all(topDown(s)); +} + +abstract production onceBottomUp +top::StrategyExpr ::= s::StrategyExpr +{ + forwards to one(onceBottomUp(s)) <+ s; +} + +abstract production onceTopDown +top::StrategyExpr ::= s::StrategyExpr +{ + forwards to s <+ one(onceTopDown(s)); +} + +abstract production innermost +top::StrategyExpr ::= s::StrategyExpr +{ + forwards to bottomUp(try(s <* innermost(s))); +} + +abstract production outermost +top::StrategyExpr ::= s::StrategyExpr +{ + forwards to topDown(try(s <* outermost(s))); +} +-} \ No newline at end of file diff --git a/grammars/silver/extension/strategyattr/Terminals.sv b/grammars/silver/extension/strategyattr/Terminals.sv new file mode 100644 index 000000000..ad6795a1f --- /dev/null +++ b/grammars/silver/extension/strategyattr/Terminals.sv @@ -0,0 +1,18 @@ +grammar silver:extension:strategyattr; + +terminal Strategy_kwd 'strategy' lexer classes {KEYWORD,RESERVED}; + +terminal StrategyId_t /[a-z][A-Za-z0-9\_]*/ lexer classes {IDENTIFIER}; + +terminal Sequence_t '<*' precedence = 12, association = left; -- Same as * +terminal Choice_t '<+' precedence = 11, association = left; -- Same as + + +lexer class STRATEGY_COMB dominates StrategyId_t; + +terminal Id_t 'id' lexer classes {KEYWORD}; +terminal Fail_t 'fail' lexer classes {KEYWORD}; +terminal All_t 'all' lexer classes {KEYWORD}; +terminal Some_t 'some' lexer classes {KEYWORD}; +terminal One_t 'one' lexer classes {KEYWORD}; +terminal Rule_t 'rule' lexer classes {KEYWORD}; +terminal Rec_t 'rec' lexer classes {KEYWORD}; diff --git a/grammars/silver/extension/strategyattr/convenience/Convenience.sv b/grammars/silver/extension/strategyattr/convenience/Convenience.sv new file mode 100644 index 000000000..cbc0cf6f1 --- /dev/null +++ b/grammars/silver/extension/strategyattr/convenience/Convenience.sv @@ -0,0 +1,20 @@ +grammar silver:extension:strategyattr:convenience; + +import silver:extension:strategyattr; +import silver:extension:convenience; +import silver:definition:core; +import silver:definition:concrete_syntax; +import silver:definition:type:syntax; +import silver:definition:type; +import silver:definition:env; + +concrete production strategyAttributeDclMultiple +top::AGDcl ::= 'strategy' 'attribute' a::Name '=' e::StrategyExpr 'occurs' 'on' qs::QNames ';' +{ + top.unparse = "strategy attribute " ++ a.name ++ " occurs on " ++ qs.unparse ++ ";"; + forwards to + appendAGDcl( + strategyAttributeDcl($1, $2, a, $4, e, $9, location=a.location), + makeOccursDclsHelp($1.location, qNameWithTL(qNameId(a, location=a.location), botlNone(location=top.location)), qs.qnames), + location=top.location); +} diff --git a/grammars/silver/host/Project.sv b/grammars/silver/host/Project.sv index 2656bb17a..2cc9ad779 100644 --- a/grammars/silver/host/Project.sv +++ b/grammars/silver/host/Project.sv @@ -41,6 +41,7 @@ exports silver:extension:patternmatching; exports silver:extension:treegen; exports silver:extension:doc; exports silver:extension:autoattr; +exports silver:extension:strategyattr; exports silver:extension:monad; exports silver:extension:reflection; exports silver:extension:rewriting; From 219c29012cfe5f7cdac7641ca1ba478ea057c91e Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Fri, 3 Apr 2020 17:01:28 -0500 Subject: [PATCH 02/78] More initial work with strategies --- .../silver/extension/patternmatching/Case.sv | 6 +- .../extension/patternmatching/PatternTypes.sv | 2 +- .../silver/extension/strategyattr/DclInfo.sv | 8 +- .../silver/extension/strategyattr/Strategy.sv | 31 +++- .../extension/strategyattr/StrategyExpr.sv | 159 +++++++++++++----- 5 files changed, 147 insertions(+), 59 deletions(-) diff --git a/grammars/silver/extension/patternmatching/Case.sv b/grammars/silver/extension/patternmatching/Case.sv index 9e55a3f15..bb0c26b44 100644 --- a/grammars/silver/extension/patternmatching/Case.sv +++ b/grammars/silver/extension/patternmatching/Case.sv @@ -16,7 +16,7 @@ terminal Opt_Vbar_t /\|?/ lexer classes {SPECOP}; -- optional Coq-style vbar. terminal When_kwd 'when' lexer classes {KEYWORD,RESERVED}; -- MR | ... -nonterminal MRuleList with location, config, unparse, env, errors, matchRuleList, matchRulePatternSize; +nonterminal MRuleList with location, config, unparse, env, frame, errors, matchRuleList, matchRulePatternSize; -- Turns MRuleList (of MatchRules) into [AbstractMatchRule] synthesized attribute matchRuleList :: [AbstractMatchRule]; @@ -24,7 +24,7 @@ synthesized attribute matchRuleList :: [AbstractMatchRule]; autocopy attribute matchRulePatternSize :: Integer; -- P -> E -nonterminal MatchRule with location, config, unparse, env, errors, matchRuleList, matchRulePatternSize; +nonterminal MatchRule with location, config, unparse, env, frame, errors, matchRuleList, matchRulePatternSize; nonterminal AbstractMatchRule with location, headPattern, isVarMatchRule, expandHeadPattern; -- The head pattern of a match rule @@ -35,7 +35,7 @@ synthesized attribute isVarMatchRule :: Boolean; synthesized attribute expandHeadPattern :: (AbstractMatchRule ::= [String]); -- P , ... -nonterminal PatternList with location, config, unparse, patternList, env, errors, patternVars, patternVarEnv; +nonterminal PatternList with location, config, unparse, patternList, env, frame, errors, patternVars, patternVarEnv; -- Turns PatternList into [Pattern] synthesized attribute patternList :: [Decorated Pattern]; diff --git a/grammars/silver/extension/patternmatching/PatternTypes.sv b/grammars/silver/extension/patternmatching/PatternTypes.sv index a6f663e2b..6bb0fe288 100644 --- a/grammars/silver/extension/patternmatching/PatternTypes.sv +++ b/grammars/silver/extension/patternmatching/PatternTypes.sv @@ -5,7 +5,7 @@ import silver:extension:list only LSqr_t, RSqr_t; {-- - The forms of syntactic patterns that are permissible in (nested) case expresssions. -} -nonterminal Pattern with location, config, unparse, env, errors, patternVars, patternVarEnv, patternIsVariable, patternVariableName, patternSubPatternList, patternNamedSubPatternList, patternSortKey; +nonterminal Pattern with location, config, unparse, env, frame, errors, patternVars, patternVarEnv, patternIsVariable, patternVariableName, patternSubPatternList, patternNamedSubPatternList, patternSortKey; {-- - The names of all var patterns in the pattern. diff --git a/grammars/silver/extension/strategyattr/DclInfo.sv b/grammars/silver/extension/strategyattr/DclInfo.sv index de3c14963..4f6217c1d 100644 --- a/grammars/silver/extension/strategyattr/DclInfo.sv +++ b/grammars/silver/extension/strategyattr/DclInfo.sv @@ -1,15 +1,17 @@ grammar silver:extension:strategyattr; synthesized attribute strategyExpr :: StrategyExpr occurs on DclInfo; +attribute liftedStrategies occurs on DclInfo; aspect default production top::DclInfo ::= { top.strategyExpr = error("Internal compiler error: must be defined for all strategy attribute declarations"); + top.liftedStrategies := error("Internal compiler error: must be defined for all strategy attribute declarations"); } abstract production strategyDcl -top::DclInfo ::= sg::String sl::Location fn::String tyVar::TyVar e::StrategyExpr +top::DclInfo ::= sg::String sl::Location fn::String tyVar::TyVar e::Decorated StrategyExpr { top.sourceGrammar = sg; top.sourceLocation = sl; @@ -24,5 +26,7 @@ top::DclInfo ::= sg::String sl::Location fn::String tyVar::TyVar e::StrategyExpr top.attrDefDispatcher = synthesizedAttributeDef(_, _, _, location=_); -- Allow normal syn equations top.attributionDispatcher = strategyAttributionDcl(_, _, _, _, location=_); top.propagateDispatcher = propagateFunctor(_, location=_); - top.strategyExpr = e; + + top.strategyExpr = new(e); + top.liftedStrategies := e.liftedStrategies; } diff --git a/grammars/silver/extension/strategyattr/Strategy.sv b/grammars/silver/extension/strategyattr/Strategy.sv index 47db57e2f..d8d808065 100644 --- a/grammars/silver/extension/strategyattr/Strategy.sv +++ b/grammars/silver/extension/strategyattr/Strategy.sv @@ -11,7 +11,7 @@ top::AGDcl ::= 'strategy' 'attribute' a::Name '=' e::StrategyExpr ';' production attribute fName :: String; fName = top.grammarName ++ ":" ++ a.name; - -- Define these directly to avoid flow errors + -- Define these directly to avoid circular dependencies propagate errors, moduleNames; top.errors <- @@ -27,6 +27,8 @@ top::AGDcl ::= 'strategy' 'attribute' a::Name '=' e::StrategyExpr ';' constructAnonymousGraph(e.flowDefs, top.env, myProds, myFlow); e.frame = globalExprContext(myFlowGraph); + e.genName = a.name; + forwards to defsAGDcl( [attrDef(defaultEnvItem(strategyDcl(top.grammarName, a.location, fName, freshTyVar(), e)))], @@ -36,20 +38,33 @@ top::AGDcl ::= 'strategy' 'attribute' a::Name '=' e::StrategyExpr ';' abstract production strategyAttributionDcl top::AGDcl ::= at::Decorated QName attl::BracketedOptTypeExprs nt::QName nttl::BracketedOptTypeExprs { + local localErrors::[Message] = + attl.errors ++ attl.errorsTyVars ++ nt.lookupType.errors ++ nttl.errors ++ nttl.errorsTyVars ++ + if length(attl.types) > 0 + then [err(attl.location, "Explicit type arguments are not allowed for strategy attributes")] + else []; + + top.errors := if !null(localErrors) then localErrors else forward.errors; + forwards to - defaultAttributionDcl( - at, - if length(attl.types) > 0 - then attl - else + foldr( + appendAGDcl(_, _, location=top.location), + defaultAttributionDcl( + at, botlSome( '<', typeListSingle( nominalTypeExpr(nt.qNameType, nttl, location=top.location), location=top.location), '>', location=top.location), - nt, nttl, - location=top.location); + nt, nttl, + location=top.location), + map( + \ s::Pair -> + attributionDcl( + 'attribute', qName(top.location, s.fst), attl, 'occurs', 'on', nt, nttl, ';', + location=top.location), + at.lookupAttribute.dcl.liftedStrategies)); } {-- diff --git a/grammars/silver/extension/strategyattr/StrategyExpr.sv b/grammars/silver/extension/strategyattr/StrategyExpr.sv index 87362f1a9..cefd00819 100644 --- a/grammars/silver/extension/strategyattr/StrategyExpr.sv +++ b/grammars/silver/extension/strategyattr/StrategyExpr.sv @@ -1,95 +1,141 @@ grammar silver:extension:strategyattr; -inherited attribute attrName::String; -- Used to generate the names of lifted strategy attributes - -monoid attribute liftedAttrs::[Pair] with [], ++; -synthesized attribute isId::Boolean; -synthesized attribute isFail::Boolean; +import silver:metatranslation; + +inherited attribute genName::String; -- Used to generate the names of lifted strategy attributes +monoid attribute liftedStrategies::[Pair] with [], ++; + +synthesized attribute translation::a; + +{- +strategy attribute optimize = + innermost( + rule on StrategyExpr of + | sequence(fail(), _) -> fail() + | sequence(_, fail()) -> fail() + | sequence(id(), s) -> s + | sequence(s, id()) -> s + | choice(fail(), s) -> s + | choice(s, fail()) -> s + | choice(id(), s) -> id() + | rewriteRule(...) when ....fails -> fail() + end); +-} nonterminal StrategyExpr with config, grammarName, env, location, unparse, errors, frame, compiledGrammars, flowEnv, flowDefs, -- Normal expression stuff - attrName, liftedAttrs, isId, isFail; + genName, liftedStrategies, + translation; + +flowtype StrategyExpr = + decorate {grammarName, env, genName}, -- NOT frame + unparse {}, errors {decorate, frame, config, compiledGrammars, flowEnv}, flowDefs {decorate, frame, config, compiledGrammars, flowEnv}, + liftedStrategies {decorate}, + translation {decorate, frame}; -propagate errors, flowDefs, liftedAttrs on StrategyExpr; +propagate errors, flowDefs, liftedStrategies on StrategyExpr; -abstract production nameStrategy +abstract production attrRef top::StrategyExpr ::= id::QName { top.unparse = id.unparse; top.errors <- id.lookupAttribute.errors; -- TODO: Type checking! + + top.translation = Silver_Expr { $name{top.frame.lhsNtName}.$QName{id} }; } -- Basic combinators -concrete production idStrategy +concrete production id top::StrategyExpr ::= 'id' { top.unparse = "id"; - top.isId = true; - top.isFail = false; + top.translation = Silver_Expr { core:just($name{top.frame.lhsNtName}) }; } -concrete production failStrategy +concrete production fail top::StrategyExpr ::= 'fail' { top.unparse = "fail"; - top.isId = false; - top.isFail = true; + top.translation = Silver_Expr { core:nothing() }; } -concrete production sequenceStrategy +concrete production sequence top::StrategyExpr ::= s1::StrategyExpr '<*' s2::StrategyExpr { - top.unparse = "(${s1.pp} <* ${s2.pp})"; - top.isId = s1.isId && s2.isId; - top.isFail = s1.isFail || s2.isFail; + top.unparse = s"(${s1.unparse} <* ${s2.unparse})"; + top.liftedStrategies <- [pair(s2.genName, s2)]; + s1.genName = top.genName; + s2.genName = top.genName ++ "_cont"; + + top.translation = + Silver_Expr { + -- TODO: This could be a monadic bind, but that isn't in core + case $Expr{s1.translation} of + | just(res) -> decorate res with {}.$name{s2.genName} -- TODO: Decorate with all inh attributes + | nothing() -> nothing() + end + }; } -concrete production choiceStrategy +concrete production choice top::StrategyExpr ::= s1::StrategyExpr '<+' s2::StrategyExpr { - top.unparse = "(${s1.pp} <+ ${s2.pp})"; - top.isId = s1.isId || (s1.isFail && s2.isId); - top.isFail = s1.isFail && s2.isFail; + top.unparse = s"(${s1.unparse} <+ ${s2.unparse})"; + + s1.genName = top.genName ++ "_left"; + s2.genName = top.genName ++ "_right"; + + top.translation = Silver_Expr { core:orElse($Expr{s1.translation}, $Expr{s2.translation}) }; } -- Traversals -concrete production allStrategy +concrete production allTraversal top::StrategyExpr ::= 'all' '(' s::StrategyExpr ')' { - top.unparse = "all(${s.pp})"; - -- TODO: Can be more specific here - top.isId = s.isId; - top.isFail = s.isFail; + top.unparse = s"all(${s.unparse})"; + + s.genName = top.genName ++ "_all"; + + } -concrete production someStrategy +concrete production someTraversal top::StrategyExpr ::= 'some' '(' s::StrategyExpr ')' { - top.unparse = "some(${s.pp})"; - -- TODO: Can be more specific here - top.isId = s.isId; - top.isFail = s.isFail; + top.unparse = s"some(${s.unparse})"; + + s.genName = top.genName ++ "_some"; + } -concrete production oneStrategy +concrete production oneTraversal top::StrategyExpr ::= 'one' '(' s::StrategyExpr ')' { - top.unparse = "one(${s.pp})"; - -- TODO: Can be more specific here - top.isId = s.isId; - top.isFail = s.isFail; + top.unparse = s"one(${s.unparse})"; + + s.genName = top.genName ++ "_one"; + + } +-- Recursive strategies +concrete production recStrategy +top::StrategyExpr ::= 'rec' n::Name '->' s::StrategyExpr +{ + top.unparse = s"rec ${n.name} -> (${s.unparse})"; + + s.genName = top.genName ++ "_" ++ n.name; + + +} -- Rules -concrete production ruleStrategy +concrete production rewriteRule top::StrategyExpr ::= 'rule' 'on' ty::TypeExpr 'of' Opt_Vbar_t ml::MRuleList 'end' { top.unparse = "rule on " ++ ty.unparse ++ " of " ++ ml.unparse ++ " end"; - top.isId = false; -- Unusual, and no way of checking this without decorating RHSs - top.isFail = ml.isFail; -- Pattern matching error checking (mostly) happens on what caseExpr forwards to, -- so we need to decorate one of those here. @@ -124,30 +170,53 @@ top::Expr ::= t::Type forwards to errorExpr([], location=top.location); } -attribute isFail occurs on MRuleList, MatchRule; +monoid attribute fails::Boolean with true, && occurs on MRuleList, MatchRule, PatternList, Pattern; +propagate fails on MRuleList, MatchRule; + +attribute translation occurs on MRuleList; aspect production mRuleList_one top::MRuleList ::= m::MatchRule { - top.isFail = m.isFail; + local defaultRule::MRuleList = + mRuleList_one( + matchRule_c( + foldr( + patternList_more(_, ',', _, location=top.location), + patternList_nil(location=top.location), + repeat(wildcPattern('_', location=top.location), length(top.frame.signature.inputElements))), + '->', + Silver_Expr { core:nothing() }, + location=top.location), + location=top.location); + top.translation = + if m.fails + then defaultRule + else mRuleList_cons(m.translation, '|', defaultRule, location=top.location); } aspect production mRuleList_cons top::MRuleList ::= h::MatchRule '|' t::MRuleList { - top.isFail = h.isFail && t.isFail; + top.translation = + if h.fails + then t.translation + else mRuleList_cons(h.translation, '|', t.translation, location=top.location); + } +attribute translation occurs on MatchRule; + aspect production matchRule_c top::MatchRule ::= pt::PatternList _ e::Expr { - top.isFail = false; -- TODO + } aspect production matchRuleWhen_c top::MatchRule ::= pt::PatternList 'when' cond::Expr _ e::Expr { - top.isFail = false; -- TODO + } aspect production patternList_one From b6185a6cc24cfb1d0b3a939cb0f2d134fe5bc912 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Fri, 3 Apr 2020 19:44:28 -0500 Subject: [PATCH 03/78] More progress --- .../silver/extension/strategyattr/DclInfo.sv | 2 +- .../silver/extension/strategyattr/Project.sv | 1 + .../silver/extension/strategyattr/Strategy.sv | 31 +------- .../extension/strategyattr/StrategyExpr.sv | 73 +++++++++++++------ 4 files changed, 57 insertions(+), 50 deletions(-) diff --git a/grammars/silver/extension/strategyattr/DclInfo.sv b/grammars/silver/extension/strategyattr/DclInfo.sv index 4f6217c1d..ca72ff380 100644 --- a/grammars/silver/extension/strategyattr/DclInfo.sv +++ b/grammars/silver/extension/strategyattr/DclInfo.sv @@ -25,7 +25,7 @@ top::DclInfo ::= sg::String sl::Location fn::String tyVar::TyVar e::Decorated St top.undecoratedAccessHandler = accessBounceDecorate(synDecoratedAccessHandler(_, _, location=_), _, _, _); top.attrDefDispatcher = synthesizedAttributeDef(_, _, _, location=_); -- Allow normal syn equations top.attributionDispatcher = strategyAttributionDcl(_, _, _, _, location=_); - top.propagateDispatcher = propagateFunctor(_, location=_); + top.propagateDispatcher = propagateStrategy(_, location=_); top.strategyExpr = new(e); top.liftedStrategies := e.liftedStrategies; diff --git a/grammars/silver/extension/strategyattr/Project.sv b/grammars/silver/extension/strategyattr/Project.sv index 94a6d1eb1..286d34a54 100644 --- a/grammars/silver/extension/strategyattr/Project.sv +++ b/grammars/silver/extension/strategyattr/Project.sv @@ -9,5 +9,6 @@ imports silver:extension:patternmatching; imports silver:extension:list; --imports silver:extension:rewriting; imports silver:modification:let_fix; +imports silver:modification:lambda_fn; exports silver:extension:strategyattr:convenience; diff --git a/grammars/silver/extension/strategyattr/Strategy.sv b/grammars/silver/extension/strategyattr/Strategy.sv index d8d808065..05baecb52 100644 --- a/grammars/silver/extension/strategyattr/Strategy.sv +++ b/grammars/silver/extension/strategyattr/Strategy.sv @@ -43,6 +43,7 @@ top::AGDcl ::= at::Decorated QName attl::BracketedOptTypeExprs nt::QName nttl::B if length(attl.types) > 0 then [err(attl.location, "Explicit type arguments are not allowed for strategy attributes")] else []; + -- TODO: Check that the type parameters of any rules of type nt match nttl top.errors := if !null(localErrors) then localErrors else forward.errors; @@ -74,33 +75,7 @@ top::AGDcl ::= at::Decorated QName attl::BracketedOptTypeExprs nt::QName nttl::B abstract production propagateStrategy top::ProductionStmt ::= attr::Decorated QName { - -- No explicit errors, for now. The only conceivable issue is the attribute not - -- occuring on the LHS but this should be caught by the forward errors. - - -- Generate the arguments for the constructor - local topName::QName = qName(top.location, top.frame.signature.outputElement.elementName); - local prodName::QName = qName(top.location, top.frame.fullName); - prodName.grammarName = top.grammarName; - prodName.config = top.config; - prodName.env = top.env; - - local inputs :: [Expr] = - map(makeArg(top.location, top.env, attr, _), top.frame.signature.inputElements); - local annotations :: [Pair] = - map(makeAnnoArg(top.location, topName, _), top.frame.signature.namedInputElements); - -- Construct an attribute def and call with the generated arguments - forwards to - attributeDef( - concreteDefLHS(topName, location=top.location), - '.', - qNameAttrOccur(new(attr), location=top.location), - '=', - mkFullFunctionInvocation( - top.location, - baseExpr(prodName, location=top.location), - inputs, - annotations), - ';', - location=top.location); + -- TODO: Don't generate code if attr decl contains errors + forwards to error("todo"); } diff --git a/grammars/silver/extension/strategyattr/StrategyExpr.sv b/grammars/silver/extension/strategyattr/StrategyExpr.sv index cefd00819..a3adaa08d 100644 --- a/grammars/silver/extension/strategyattr/StrategyExpr.sv +++ b/grammars/silver/extension/strategyattr/StrategyExpr.sv @@ -18,7 +18,7 @@ strategy attribute optimize = | choice(fail(), s) -> s | choice(s, fail()) -> s | choice(id(), s) -> id() - | rewriteRule(...) when ....fails -> fail() + | rewriteRule(...) when ....matchesFrame -> fail() end); -} @@ -122,7 +122,7 @@ top::StrategyExpr ::= 'one' '(' s::StrategyExpr ')' -- Recursive strategies concrete production recStrategy -top::StrategyExpr ::= 'rec' n::Name '->' s::StrategyExpr +top::StrategyExpr ::= 'rec' n::Name Arrow_t s::StrategyExpr { top.unparse = s"rec ${n.name} -> (${s.unparse})"; @@ -156,6 +156,10 @@ top::StrategyExpr ::= 'rule' 'on' ty::TypeExpr 'of' Opt_Vbar_t ml::MRuleList 'en checkExpr.compiledGrammars = top.compiledGrammars; top.errors <- checkExpr.errors; + top.errors <- + if !ty.typerep.isDecorable + then [wrn(ty.location, "Only rules on nonterminals can have an effect")] + else []; top.flowDefs <- checkExpr.flowDefs; @@ -170,8 +174,8 @@ top::Expr ::= t::Type forwards to errorExpr([], location=top.location); } -monoid attribute fails::Boolean with true, && occurs on MRuleList, MatchRule, PatternList, Pattern; -propagate fails on MRuleList, MatchRule; +monoid attribute matchesFrame::Boolean with false, || occurs on MRuleList, MatchRule, PatternList, Pattern; +propagate matchesFrame on MRuleList, MatchRule, PatternList; attribute translation occurs on MRuleList; @@ -181,27 +185,24 @@ top::MRuleList ::= m::MatchRule local defaultRule::MRuleList = mRuleList_one( matchRule_c( - foldr( - patternList_more(_, ',', _, location=top.location), - patternList_nil(location=top.location), - repeat(wildcPattern('_', location=top.location), length(top.frame.signature.inputElements))), - '->', + makeWildPatternList(top.frame, top.location), + terminal(Arrow_kwd, "->"), Silver_Expr { core:nothing() }, location=top.location), location=top.location); top.translation = - if m.fails - then defaultRule - else mRuleList_cons(m.translation, '|', defaultRule, location=top.location); + if m.matchesFrame + then mRuleList_cons(m.translation, '|', defaultRule, location=top.location) + else defaultRule; } aspect production mRuleList_cons top::MRuleList ::= h::MatchRule '|' t::MRuleList { top.translation = - if h.fails - then t.translation - else mRuleList_cons(h.translation, '|', t.translation, location=top.location); + if h.matchesFrame + then mRuleList_cons(h.translation, '|', t.translation, location=top.location) + else t.translation; } @@ -210,32 +211,42 @@ attribute translation occurs on MatchRule; aspect production matchRule_c top::MatchRule ::= pt::PatternList _ e::Expr { - + top.translation = + matchRule_c( + pt.translation, terminal(Arrow_kwd, "->"), Silver_Expr { core:just($Expr{e}) }, + location=top.location); } aspect production matchRuleWhen_c top::MatchRule ::= pt::PatternList 'when' cond::Expr _ e::Expr { - + top.translation = + matchRuleWhen_c( + pt.translation, 'when', cond, terminal(Arrow_kwd, "->"), Silver_Expr { core:just($Expr{e}) }, + location=top.location); } +attribute translation occurs on PatternList; + aspect production patternList_one top::PatternList ::= p::Pattern { - + top.translation = p.translation; } aspect production patternList_more top::PatternList ::= p::Pattern ',' ps::PatternList { - + top.translation = p.translation; } aspect production patternList_nil top::PatternList ::= { - + top.translation = error("Top-level pattern list shouldn't be empty"); } +monoid attribute letBindings::[AssignExpr] with [], ++ occurs on NamedPatternList, NamedPattern, Pattern; + aspect production namedPatternList_one top::NamedPatternList ::= p::NamedPattern { @@ -259,10 +270,20 @@ top::NamedPattern ::= qn::QName '=' p::Pattern } +attribute translation occurs on Pattern; + +aspect default production +top::Pattern ::= +{ + top.translation = makeWildPatternList(top.frame, top.location); + top.matchesFrame := true; +} + aspect production prodAppPattern_named top::Pattern ::= prod::QName '(' ps::PatternList ',' nps::NamedPatternList ')' { - + top.translation = ps; + top.matchesFrame := prod.lookupValue.fullName == top.frame.fullName; } aspect production wildcPattern @@ -324,3 +345,13 @@ top::Pattern ::= hp::Pattern '::' tp::Pattern { } + +function makeWildPatternList +PatternList ::= frame::BlockContext loc::Location +{ + return + foldr( + patternList_more(_, ',', _, location=loc), + patternList_nil(location=loc), + repeat(wildcPattern('_', location=loc), length(frame.signature.inputElements ++ frame.signature.namedInputElements))); +} From de4871cbdc9bf1c350835a085d9aeea1b819cf36 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Sat, 4 Apr 2020 17:33:12 -0500 Subject: [PATCH 04/78] Add antiquote production for QNameAttrOccur --- .../silver/extension/silverconstruction/Syntax.sv | 12 ++++++++++++ .../silver/extension/silverconstruction/Terminals.sv | 1 + .../extension/silverconstruction/Translation.sv | 1 + 3 files changed, 14 insertions(+) diff --git a/grammars/silver/extension/silverconstruction/Syntax.sv b/grammars/silver/extension/silverconstruction/Syntax.sv index 0af251a3a..f48559690 100644 --- a/grammars/silver/extension/silverconstruction/Syntax.sv +++ b/grammars/silver/extension/silverconstruction/Syntax.sv @@ -58,6 +58,18 @@ top::QName ::= '$QName' '{' e::Expr '}' location=top.location); } +concrete production antiquoteQNameAttrOccur +top::QNameAttrOccur ::= '$QNameAttrOccur' '{' e::Expr '}' +{ + top.unparse = s"$$QNameAttrOccur{${e.unparse}}"; + forwards to + qNameAttrOccur( + qNameError( + [err(top.location, "$QNameAttrOccur should not occur outside of Silver_Expr")], + location=top.location), + location=top.location); +} + concrete production antiquoteName top::Name ::= '$Name' '{' e::Expr '}' { diff --git a/grammars/silver/extension/silverconstruction/Terminals.sv b/grammars/silver/extension/silverconstruction/Terminals.sv index f43aaa15a..8a3420861 100644 --- a/grammars/silver/extension/silverconstruction/Terminals.sv +++ b/grammars/silver/extension/silverconstruction/Terminals.sv @@ -10,6 +10,7 @@ lexer class Escape font=font_escape; terminal EscapeExpr_t '$Expr' lexer classes {Escape}; terminal EscapeTypeExpr_t '$TypeExpr' lexer classes {Escape}; terminal EscapeQName_t '$QName' lexer classes {Escape}; +terminal EscapeQNameAttrOccur_t '$QNameAttrOccur' lexer classes {Escape}; terminal EscapeName_t '$Name' lexer classes {Escape}; terminal Escape_qName_t '$qName' lexer classes {Escape}; terminal Escape_name_t '$name' lexer classes {Escape}; diff --git a/grammars/silver/extension/silverconstruction/Translation.sv b/grammars/silver/extension/silverconstruction/Translation.sv index 8a16aac42..ccf06ff22 100644 --- a/grammars/silver/extension/silverconstruction/Translation.sv +++ b/grammars/silver/extension/silverconstruction/Translation.sv @@ -10,6 +10,7 @@ top::AST ::= prodName::String children::ASTs annotations::NamedASTs ["silver:extension:silverconstruction:antiquoteExpr", "silver:extension:silverconstruction:antiquoteTypeExpr", "silver:extension:silverconstruction:antiquoteQName", + "silver:extension:silverconstruction:antiquoteQNameAttrOccur", "silver:extension:silverconstruction:antiquoteName"]; -- "Indirect" antiquote productions From 40141a2e4cc520f9eec6125f38c8bc99cb9b302e Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Sun, 5 Apr 2020 20:42:31 -0500 Subject: [PATCH 05/78] More progress --- .../silver/extension/strategyattr/DclInfo.sv | 2 +- .../extension/strategyattr/StrategyExpr.sv | 335 ++++++++---------- .../extension/strategyattr/Terminals.sv | 27 +- 3 files changed, 172 insertions(+), 192 deletions(-) diff --git a/grammars/silver/extension/strategyattr/DclInfo.sv b/grammars/silver/extension/strategyattr/DclInfo.sv index ca72ff380..a08783a9a 100644 --- a/grammars/silver/extension/strategyattr/DclInfo.sv +++ b/grammars/silver/extension/strategyattr/DclInfo.sv @@ -7,7 +7,7 @@ aspect default production top::DclInfo ::= { top.strategyExpr = error("Internal compiler error: must be defined for all strategy attribute declarations"); - top.liftedStrategies := error("Internal compiler error: must be defined for all strategy attribute declarations"); + top.liftedStrategies := []; } abstract production strategyDcl diff --git a/grammars/silver/extension/strategyattr/StrategyExpr.sv b/grammars/silver/extension/strategyattr/StrategyExpr.sv index a3adaa08d..6f6d30d02 100644 --- a/grammars/silver/extension/strategyattr/StrategyExpr.sv +++ b/grammars/silver/extension/strategyattr/StrategyExpr.sv @@ -3,14 +3,17 @@ grammar silver:extension:strategyattr; import silver:metatranslation; inherited attribute genName::String; -- Used to generate the names of lifted strategy attributes +autocopy attribute recVars::[Pair]; monoid attribute liftedStrategies::[Pair] with [], ++; -synthesized attribute translation::a; +monoid attribute matchesFrame::Boolean with false, ||; + +functor attribute translation; {- strategy attribute optimize = innermost( - rule on StrategyExpr of + rule on top::StrategyExpr of | sequence(fail(), _) -> fail() | sequence(_, fail()) -> fail() | sequence(id(), s) -> s @@ -18,56 +21,61 @@ strategy attribute optimize = | choice(fail(), s) -> s | choice(s, fail()) -> s | choice(id(), s) -> id() - | rewriteRule(...) when ....matchesFrame -> fail() + | all, some, one... + | rec(n, s) when top.attrName.isJust -> replace n with top.attrName in s + | rewriteRule(...) when !... .matchesFrame -> fail() + | nameRef(n) when !n.matchesFrame -> fail() end); -} nonterminal StrategyExpr with config, grammarName, env, location, unparse, errors, frame, compiledGrammars, flowEnv, flowDefs, -- Normal expression stuff - genName, liftedStrategies, + genName, recVars, liftedStrategies, translation; flowtype StrategyExpr = - decorate {grammarName, env, genName}, -- NOT frame + decorate {grammarName, env, genName, recVars}, -- NOT frame unparse {}, errors {decorate, frame, config, compiledGrammars, flowEnv}, flowDefs {decorate, frame, config, compiledGrammars, flowEnv}, liftedStrategies {decorate}, - translation {decorate, frame}; - -propagate errors, flowDefs, liftedStrategies on StrategyExpr; + translation {decorate, frame, config}; -abstract production attrRef -top::StrategyExpr ::= id::QName -{ - top.unparse = id.unparse; - - top.errors <- id.lookupAttribute.errors; - -- TODO: Type checking! - - top.translation = Silver_Expr { $name{top.frame.lhsNtName}.$QName{id} }; -} +propagate errors on StrategyExpr excluding nameRef; +propagate flowDefs, liftedStrategies on StrategyExpr; -- Basic combinators -concrete production id +concrete production id_c top::StrategyExpr ::= 'id' +{ forwards to id(location=top.location); } +abstract production id +top::StrategyExpr ::= { top.unparse = "id"; top.translation = Silver_Expr { core:just($name{top.frame.lhsNtName}) }; } -concrete production fail +concrete production fail_c top::StrategyExpr ::= 'fail' +{ forwards to fail(location=top.location); } +abstract production fail +top::StrategyExpr ::= { top.unparse = "fail"; top.translation = Silver_Expr { core:nothing() }; } -concrete production sequence +concrete production sequence_c top::StrategyExpr ::= s1::StrategyExpr '<*' s2::StrategyExpr +{ + top.unparse = s"(${s1.unparse} <* ${s2.unparse})"; + forwards to sequence(top.genName, s1, s2, location=top.location); +} +abstract production sequence +top::StrategyExpr ::= genName::String s1::StrategyExpr s2::StrategyExpr { top.unparse = s"(${s1.unparse} <* ${s2.unparse})"; top.liftedStrategies <- [pair(s2.genName, s2)]; - s1.genName = top.genName; - s2.genName = top.genName ++ "_cont"; + s1.genName = genName; + s2.genName = genName ++ "_cont"; top.translation = Silver_Expr { @@ -79,61 +87,102 @@ top::StrategyExpr ::= s1::StrategyExpr '<*' s2::StrategyExpr }; } -concrete production choice +concrete production choice_c top::StrategyExpr ::= s1::StrategyExpr '<+' s2::StrategyExpr +{ + top.unparse = s"(${s1.unparse} <+ ${s2.unparse})"; + forwards to choice(top.genName, s1, s2, location=top.location); +} +abstract production choice +top::StrategyExpr ::= genName::String s1::StrategyExpr s2::StrategyExpr { top.unparse = s"(${s1.unparse} <+ ${s2.unparse})"; - s1.genName = top.genName ++ "_left"; - s2.genName = top.genName ++ "_right"; + s1.genName = genName ++ "_left"; + s2.genName = genName ++ "_right"; top.translation = Silver_Expr { core:orElse($Expr{s1.translation}, $Expr{s2.translation}) }; } -- Traversals -concrete production allTraversal +concrete production allTraversal_c top::StrategyExpr ::= 'all' '(' s::StrategyExpr ')' +{ + top.unparse = s"all(${s.unparse})"; + forwards to allTraversal(top.genName, s, location=top.location); +} +abstract production allTraversal +top::StrategyExpr ::= genName::String s::StrategyExpr { top.unparse = s"all(${s.unparse})"; - s.genName = top.genName ++ "_all"; - + s.genName = genName ++ "_all"; + top.translation = + caseExpr( + map( + \ e::NamedSignatureElement -> Silver_Expr { $name{e.elementName} }, + top.frame.signature.inputElements), + ml.matchRuleList, + Silver_Expr { core:nothing() }, + nonterminalType("core:Maybe", [top.frame.signature.outputElement.typerep]), + location=top.location); } -concrete production someTraversal +concrete production someTraversal_c top::StrategyExpr ::= 'some' '(' s::StrategyExpr ')' +{ + top.unparse = s"some(${s.unparse})"; + forwards to someTraversal(top.genName, s, location=top.location); +} +abstract production someTraversal +top::StrategyExpr ::= genName::String s::StrategyExpr { top.unparse = s"some(${s.unparse})"; - s.genName = top.genName ++ "_some"; + s.genName = genName ++ "_some"; } -concrete production oneTraversal +concrete production oneTraversal_c top::StrategyExpr ::= 'one' '(' s::StrategyExpr ')' +{ + top.unparse = s"one(${s.unparse})"; + forwards to oneTraversal(top.genName, s, location=top.location); +} +abstract production oneTraversal +top::StrategyExpr ::= genName::String s::StrategyExpr { top.unparse = s"one(${s.unparse})"; - s.genName = top.genName ++ "_one"; + s.genName = genName ++ "_one"; } -- Recursive strategies -concrete production recStrategy +concrete production rec_c top::StrategyExpr ::= 'rec' n::Name Arrow_t s::StrategyExpr +{ + top.unparse = s"rec ${n.name} -> (${s.unparse})"; + forwards to rec(top.genName, n, s, location=top.location); +} +abstract production rec +top::StrategyExpr ::= genName::String n::Name s::StrategyExpr { top.unparse = s"rec ${n.name} -> (${s.unparse})"; - s.genName = top.genName ++ "_" ++ n.name; + s.genName = genName ++ "_" ++ n.name; } -- Rules -concrete production rewriteRule +concrete production rewriteRule_c top::StrategyExpr ::= 'rule' 'on' ty::TypeExpr 'of' Opt_Vbar_t ml::MRuleList 'end' +{ forwards to rewriteRule(ty, ml, location=top.location); } +abstract production rewriteRule +top::StrategyExpr ::= ty::TypeExpr ml::MRuleList { top.unparse = "rule on " ++ ty.unparse ++ " of " ++ ml.unparse ++ " end"; @@ -164,6 +213,14 @@ top::StrategyExpr ::= 'rule' 'on' ty::TypeExpr 'of' Opt_Vbar_t ml::MRuleList 'en top.flowDefs <- checkExpr.flowDefs; ml.matchRulePatternSize = 1; + + top.translation = + caseExpr( + [Silver_Expr { $name{top.frame.signature.outputElement.elementName} }], + ml.matchRuleList, + Silver_Expr { core:nothing() }, + nonterminalType("core:Maybe", [ty.typerep]), + location=top.location); } -- Hack dummy expr with a given type @@ -174,46 +231,20 @@ top::Expr ::= t::Type forwards to errorExpr([], location=top.location); } -monoid attribute matchesFrame::Boolean with false, || occurs on MRuleList, MatchRule, PatternList, Pattern; +attribute matchesFrame occurs on MRuleList, MatchRule, PatternList, Pattern; propagate matchesFrame on MRuleList, MatchRule, PatternList; -attribute translation occurs on MRuleList; +attribute translation occurs on MRuleList; +propagate translation on MRuleList; -aspect production mRuleList_one -top::MRuleList ::= m::MatchRule -{ - local defaultRule::MRuleList = - mRuleList_one( - matchRule_c( - makeWildPatternList(top.frame, top.location), - terminal(Arrow_kwd, "->"), - Silver_Expr { core:nothing() }, - location=top.location), - location=top.location); - top.translation = - if m.matchesFrame - then mRuleList_cons(m.translation, '|', defaultRule, location=top.location) - else defaultRule; -} - -aspect production mRuleList_cons -top::MRuleList ::= h::MatchRule '|' t::MRuleList -{ - top.translation = - if h.matchesFrame - then mRuleList_cons(h.translation, '|', t.translation, location=top.location) - else t.translation; - -} - -attribute translation occurs on MatchRule; +attribute translation occurs on MatchRule; aspect production matchRule_c top::MatchRule ::= pt::PatternList _ e::Expr { top.translation = matchRule_c( - pt.translation, terminal(Arrow_kwd, "->"), Silver_Expr { core:just($Expr{e}) }, + pt, $2, Silver_Expr { core:just($Expr{e}) }, location=top.location); } @@ -222,136 +253,78 @@ top::MatchRule ::= pt::PatternList 'when' cond::Expr _ e::Expr { top.translation = matchRuleWhen_c( - pt.translation, 'when', cond, terminal(Arrow_kwd, "->"), Silver_Expr { core:just($Expr{e}) }, + pt, 'when', cond, $4, Silver_Expr { core:just($Expr{e}) }, location=top.location); } -attribute translation occurs on PatternList; - -aspect production patternList_one -top::PatternList ::= p::Pattern -{ - top.translation = p.translation; -} -aspect production patternList_more -top::PatternList ::= p::Pattern ',' ps::PatternList -{ - top.translation = p.translation; -} - -aspect production patternList_nil -top::PatternList ::= -{ - top.translation = error("Top-level pattern list shouldn't be empty"); -} - -monoid attribute letBindings::[AssignExpr] with [], ++ occurs on NamedPatternList, NamedPattern, Pattern; - -aspect production namedPatternList_one -top::NamedPatternList ::= p::NamedPattern -{ - -} -aspect production namedPatternList_more -top::NamedPatternList ::= p::NamedPattern ',' ps::NamedPatternList -{ - -} - -aspect production namedPatternList_nil -top::NamedPatternList ::= -{ - -} - -aspect production namedPattern -top::NamedPattern ::= qn::QName '=' p::Pattern -{ - -} - -attribute translation occurs on Pattern; - aspect default production top::Pattern ::= { - top.translation = makeWildPatternList(top.frame, top.location); top.matchesFrame := true; } aspect production prodAppPattern_named top::Pattern ::= prod::QName '(' ps::PatternList ',' nps::NamedPatternList ')' { - top.translation = ps; top.matchesFrame := prod.lookupValue.fullName == top.frame.fullName; -} - -aspect production wildcPattern -top::Pattern ::= '_' -{ - -} - -aspect production varPattern -top::Pattern ::= v::Name -{ - } -aspect production errorPattern -top::Pattern ::= msg::[Message] -{ - -} - -aspect production intPattern -top::Pattern ::= num::Int_t -{ - -} - -aspect production fltPattern -top::Pattern ::= num::Float_t -{ - -} - -aspect production strPattern -top::Pattern ::= str::String_t -{ - -} - -aspect production truePattern -top::Pattern ::= 'true' -{ - -} - -aspect production falsePattern -top::Pattern ::= 'false' +-- References to other attributes or rec variables +concrete production nameRef_c +top::StrategyExpr ::= id::StrategyQName +{ forwards to nameRef(qNameAttrOccur(id.ast, location=top.location), location=top.location); } +abstract production nameRef +top::StrategyExpr ::= id::QNameAttrOccur { + top.unparse = id.unparse; -} - -aspect production nilListPattern -top::Pattern ::= '[' ']' -{ + local recAttr::Maybe = lookupBy(stringEq, id.name, top.recVars); + local attrDcl::DclInfo = case id of qNameAttrOccur(a) -> a.lookupAttribute.dcl end; + attrDcl.givenNonterminalType = error("Not needed"); -- Ugh environment needs refactoring + top.errors := + if recAttr.isJust then [] + else + case id of qNameAttrOccur(a) -> a.lookupAttribute.errors end ++ + case attrDcl.typerep, attrDcl.dclBoundVars of + | nonterminalType("core:Maybe", [varType(a1)]), [a2] when tyVarEqual(a1, a2) -> [] + | varType(a1), [a2] when tyVarEqual(a1, a2) -> [] + | nonterminalType("core:Maybe", [nonterminalType(nt, _)]), _ -> + case getOccursDcl(attrDcl.fullName, nt, top.env) of + | [] -> [wrn(id.location, s"Attribute ${id.name} doesn't occur on its own nonterminal type ${nt}")] + | _ -> [] + end + | nonterminalType(nt, _), _ -> + case getOccursDcl(attrDcl.fullName, nt, top.env) of + | [] -> [wrn(id.location, s"Attribute ${id.name} doesn't occur on its own nonterminal type ${nt}")] + | _ -> [] + end + | errorType(), _ -> [] + | _, _ -> [err(id.location, "Attribute has invalid type for use in a strategy")] + end; + + id.attrFor = top.frame.signature.outputElement.typerep; -} - -aspect production consListPattern -top::Pattern ::= hp::Pattern '::' tp::Pattern -{ - -} - -function makeWildPatternList -PatternList ::= frame::BlockContext loc::Location -{ - return - foldr( - patternList_more(_, ',', _, location=loc), - patternList_nil(location=loc), - repeat(wildcPattern('_', location=loc), length(frame.signature.inputElements ++ frame.signature.namedInputElements))); + top.translation = + case recAttr, id.matchesFrame, id.typerep of + | just(a), _, _ -> + Silver_Expr { $name{top.frame.signature.outputElement.elementName}.$qName{a} } + | nothing(), true, nonterminalType("core:Maybe", _) -> + Silver_Expr { $name{top.frame.signature.outputElement.elementName}.$QNameAttrOccur{id} } + | nothing(), true, _ -> + Silver_Expr { core:just($name{top.frame.signature.outputElement.elementName}.$QNameAttrOccur{id}) } + | nothing(), false, _ -> + Silver_Expr { core:nothing() } + end; +} + +attribute matchesFrame occurs on QNameAttrOccur; + +aspect production qNameAttrOccur +top::QNameAttrOccur ::= at::QName +{ + top.matchesFrame := !top.found || + case top.typerep of + | nonterminalType("core:Maybe", [t]) -> !unify(top.attrFor, t).failure + | t -> !unify(top.attrFor, t).failure + end; } diff --git a/grammars/silver/extension/strategyattr/Terminals.sv b/grammars/silver/extension/strategyattr/Terminals.sv index ad6795a1f..ad4fb0bb4 100644 --- a/grammars/silver/extension/strategyattr/Terminals.sv +++ b/grammars/silver/extension/strategyattr/Terminals.sv @@ -2,17 +2,24 @@ grammar silver:extension:strategyattr; terminal Strategy_kwd 'strategy' lexer classes {KEYWORD,RESERVED}; -terminal StrategyId_t /[a-z][A-Za-z0-9\_]*/ lexer classes {IDENTIFIER}; - terminal Sequence_t '<*' precedence = 12, association = left; -- Same as * terminal Choice_t '<+' precedence = 11, association = left; -- Same as + -lexer class STRATEGY_COMB dominates StrategyId_t; +lexer class STRATEGY_COMB dominates StrategyName_t; + +terminal Id_t 'id' lexer classes {KEYWORD, STRATEGY_COMB}; +terminal Fail_t 'fail' lexer classes {KEYWORD, STRATEGY_COMB}; +terminal All_t 'all' lexer classes {KEYWORD, STRATEGY_COMB}; +terminal Some_t 'some' lexer classes {KEYWORD, STRATEGY_COMB}; +terminal One_t 'one' lexer classes {KEYWORD, STRATEGY_COMB}; +terminal Rule_t 'rule' lexer classes {KEYWORD, STRATEGY_COMB}; +terminal Rec_t 'rec' lexer classes {KEYWORD, STRATEGY_COMB}; + +terminal StrategyName_t /[a-z][A-Za-z0-9\_]*/ lexer classes {IDENTIFIER}; -terminal Id_t 'id' lexer classes {KEYWORD}; -terminal Fail_t 'fail' lexer classes {KEYWORD}; -terminal All_t 'all' lexer classes {KEYWORD}; -terminal Some_t 'some' lexer classes {KEYWORD}; -terminal One_t 'one' lexer classes {KEYWORD}; -terminal Rule_t 'rule' lexer classes {KEYWORD}; -terminal Rec_t 'rec' lexer classes {KEYWORD}; +nonterminal StrategyQName with location, ast; +concrete productions top::StrategyQName +| id::StrategyName_t +{ top.ast = qNameId(name(id.lexeme, id.location), location=top.location); } +| id::StrategyName_t ':' qn::StrategyQName +{ top.ast = qNameCons(name(id.lexeme, id.location), $2, qn.ast, location=top.location); } From e3bb15c949f96f2bf992e00131e2f486aa83fdbd Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Mon, 6 Apr 2020 16:22:13 -0500 Subject: [PATCH 06/78] Some refactoring to functor and monoid implementation --- grammars/silver/extension/autoattr/Functor.sv | 21 +++++++++---------- grammars/silver/extension/autoattr/Monoid.sv | 11 +++------- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/grammars/silver/extension/autoattr/Functor.sv b/grammars/silver/extension/autoattr/Functor.sv index adba5da28..c4042aade 100644 --- a/grammars/silver/extension/autoattr/Functor.sv +++ b/grammars/silver/extension/autoattr/Functor.sv @@ -22,6 +22,7 @@ top::AGDcl ::= 'functor' 'attribute' a::Name ';' abstract production functorAttributionDcl top::AGDcl ::= at::Decorated QName attl::BracketedOptTypeExprs nt::QName nttl::BracketedOptTypeExprs { + top.unparse = "attribute " ++ at.unparse ++ attl.unparse ++ " occurs on " ++ nt.unparse ++ nttl.unparse ++ ";"; forwards to defaultAttributionDcl( at, @@ -45,31 +46,29 @@ top::AGDcl ::= at::Decorated QName attl::BracketedOptTypeExprs nt::QName nttl::B abstract production propagateFunctor top::ProductionStmt ::= attr::Decorated QName { + top.unparse = s"propagate ${attr.unparse};"; + -- No explicit errors, for now. The only conceivable issue is the attribute not -- occuring on the LHS but this should be caught by the forward errors. -- Generate the arguments for the constructor - local topName::QName = qName(top.location, top.frame.signature.outputElement.elementName); - local prodName::QName = qName(top.location, top.frame.fullName); - prodName.grammarName = top.grammarName; - prodName.config = top.config; - prodName.env = top.env; - local inputs :: [Expr] = map(makeArg(top.location, top.env, attr, _), top.frame.signature.inputElements); local annotations :: [Pair] = - map(makeAnnoArg(top.location, topName, _), top.frame.signature.namedInputElements); + map( + makeAnnoArg(top.location, top.frame.signature.outputElement.elementName, _), + top.frame.signature.namedInputElements); -- Construct an attribute def and call with the generated arguments forwards to attributeDef( - concreteDefLHS(topName, location=top.location), + concreteDefLHS(qName(top.location, top.frame.signature.outputElement.elementName), location=top.location), '.', qNameAttrOccur(new(attr), location=top.location), '=', mkFullFunctionInvocation( top.location, - baseExpr(prodName, location=top.location), + baseExpr(qName(top.location, top.frame.fullName), location=top.location), inputs, annotations), ';', @@ -112,7 +111,7 @@ Expr ::= loc::Location env::Decorated Env attrName::Decorated QName input::Named - @return A list of AnnoExprs to be used to build the named arguments -} function makeAnnoArg -Pair ::= loc::Location baseName::QName input::NamedSignatureElement +Pair ::= loc::Location baseName::String input::NamedSignatureElement { -- TODO: This is a hacky way of getting the base name, not sure if correct -- trouble is the annotations are listed as fullnames, but have to be supplied as shortnames. weird. @@ -121,7 +120,7 @@ Pair ::= loc::Location baseName::QName input::NamedSignatureElement return pair(annoName, access( - baseExpr(baseName, location=loc), '.', + baseExpr(qName(loc, baseName), location=loc), '.', qNameAttrOccur(qName(loc, annoName), location=loc), location=loc)); } diff --git a/grammars/silver/extension/autoattr/Monoid.sv b/grammars/silver/extension/autoattr/Monoid.sv index 0d5a8a559..3ca28d880 100644 --- a/grammars/silver/extension/autoattr/Monoid.sv +++ b/grammars/silver/extension/autoattr/Monoid.sv @@ -84,6 +84,8 @@ top::Operation ::= abstract production propagateMonoid top::ProductionStmt ::= attr::Decorated QName { + top.unparse = s"propagate ${attr.unparse};"; + -- No explicit errors, for now. The only conceivable issue is the attribute not -- occuring on the LHS but this should be caught by the forward errors. @@ -94,13 +96,6 @@ top::ProductionStmt ::= attr::Decorated QName input.typerep.isDecorable && !null(getOccursDcl(attrFullName, input.typerep.typeName, top.env)), top.frame.signature.inputElements); - - local topName::QName = qName(top.location, top.frame.signature.outputElement.elementName); - local prodName::QName = qName(top.location, top.frame.fullName); - prodName.grammarName = top.grammarName; - prodName.config = top.config; - prodName.env = top.env; - local res :: Expr = if null(inputsWithAttr) then attr.lookupAttribute.dcl.emptyVal @@ -119,7 +114,7 @@ top::ProductionStmt ::= attr::Decorated QName -- Construct an attribute def and call with the generated arguments forwards to attrContainsBase( - concreteDefLHS(topName, location=top.location), + concreteDefLHS(qName(top.location, top.frame.signature.outputElement.elementName), location=top.location), '.', qNameAttrOccur(new(attr), location=top.location), ':=', res, ';', location=top.location); From cab401903fd8df39fb4875a563fd5bd8d755317f Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Mon, 6 Apr 2020 16:22:47 -0500 Subject: [PATCH 07/78] More work on strategy attributes, split StrategyExpr concrete syntax into seperate nonterminal --- .../extension/silverconstruction/Syntax.sv | 30 +- .../extension/silverconstruction/Terminals.sv | 2 + .../extension/strategyattr/ConcreteSyntax.sv | 80 +++++ .../silver/extension/strategyattr/Strategy.sv | 8 +- .../extension/strategyattr/StrategyExpr.sv | 318 +++++++++++------- .../extension/strategyattr/Terminals.sv | 7 - .../strategyattr/convenience/Convenience.sv | 4 +- 7 files changed, 307 insertions(+), 142 deletions(-) create mode 100644 grammars/silver/extension/strategyattr/ConcreteSyntax.sv diff --git a/grammars/silver/extension/silverconstruction/Syntax.sv b/grammars/silver/extension/silverconstruction/Syntax.sv index f48559690..24380904f 100644 --- a/grammars/silver/extension/silverconstruction/Syntax.sv +++ b/grammars/silver/extension/silverconstruction/Syntax.sv @@ -6,6 +6,7 @@ imports silver:definition:core; imports silver:definition:env; imports silver:definition:type:syntax; imports silver:extension:list; +imports silver:extension:patternmatching; concrete production quoteAGDcl top::Expr ::= 'Silver_AGDcl' '{' ast::AGDcl '}' @@ -28,13 +29,20 @@ top::Expr ::= 'Silver_Expr' '{' ast::Expr '}' forwards to translate(top.location, reflect(new(ast))); } +concrete production quotePattern +top::Expr ::= 'Silver_Pattern' '{' ast::Pattern '}' +{ + top.unparse = s"Silver_Pattern {${ast.unparse}}"; + forwards to translate(top.location, reflect(new(ast))); +} + concrete production antiquoteExpr top::Expr ::= '$Expr' '{' e::Expr '}' { top.unparse = s"$$Expr{${e.unparse}}"; forwards to errorExpr( - [err(top.location, "$Expr should not occur outside of Silver_Expr")], + [err(top.location, "$Expr should not occur outside of quoted Silver literal")], location=top.location); } @@ -44,7 +52,17 @@ top::TypeExpr ::= '$TypeExpr' '{' e::Expr '}' top.unparse = s"$$TypeExpr{${e.unparse}}"; forwards to errorTypeExpr( - [err(top.location, "$TypeExpr should not occur outside of Silver_Expr")], + [err(top.location, "$TypeExpr should not occur outside of quoted Silver literal")], + location=top.location); +} + +concrete production antiquotePattern +top::Pattern ::= '$Pattern' '{' e::Pattern '}' +{ + top.unparse = s"$$Pattern{${e.unparse}}"; + forwards to + errorPattern( + [err(top.location, "$Pattern should not occur outside of quoted Silver literal")], location=top.location); } @@ -54,7 +72,7 @@ top::QName ::= '$QName' '{' e::Expr '}' top.unparse = s"$$QName{${e.unparse}}"; forwards to qNameError( - [err(top.location, "$QName should not occur outside of Silver_Expr")], + [err(top.location, "$QName should not occur outside of quoted Silver literal")], location=top.location); } @@ -65,7 +83,7 @@ top::QNameAttrOccur ::= '$QNameAttrOccur' '{' e::Expr '}' forwards to qNameAttrOccur( qNameError( - [err(top.location, "$QNameAttrOccur should not occur outside of Silver_Expr")], + [err(top.location, "$QNameAttrOccur should not occur outside of quoted Silver literal")], location=top.location), location=top.location); } @@ -74,7 +92,7 @@ concrete production antiquoteName top::Name ::= '$Name' '{' e::Expr '}' { top.unparse = s"$$Name{${e.unparse}}"; - -- TODO: [err(top.location, "$Name should not occur outside of Silver_Expr")] + -- TODO: [err(top.location, "$Name should not occur outside of quoted Silver literal")] forwards to name("err", top.location); } @@ -92,6 +110,6 @@ concrete production antiquote_name top::Name ::= '$name' '{' e::Expr '}' { top.unparse = s"$$name{${e.unparse}}"; - -- TODO: [err(top.location, "$Name should not occur outside of Silver_Expr")] + -- TODO: [err(top.location, "$Name should not occur outside of quoted Silver literal")] forwards to name("err", top.location); } diff --git a/grammars/silver/extension/silverconstruction/Terminals.sv b/grammars/silver/extension/silverconstruction/Terminals.sv index 8a3420861..430b74162 100644 --- a/grammars/silver/extension/silverconstruction/Terminals.sv +++ b/grammars/silver/extension/silverconstruction/Terminals.sv @@ -1,6 +1,7 @@ grammar silver:extension:silverconstruction; marking terminal SilverExpr_t 'Silver_Expr' lexer classes {KEYWORD, RESERVED}; +marking terminal SilverPattern_t 'Silver_Pattern' lexer classes {KEYWORD, RESERVED}; marking terminal SilverAGDcl_t 'Silver_AGDcl' lexer classes {KEYWORD, RESERVED}; marking terminal SilverProductionStmt_t 'Silver_ProductionStmt' lexer classes {KEYWORD, RESERVED}; @@ -9,6 +10,7 @@ lexer class Escape font=font_escape; terminal EscapeExpr_t '$Expr' lexer classes {Escape}; terminal EscapeTypeExpr_t '$TypeExpr' lexer classes {Escape}; +terminal EscapePattern_t '$Pattern' lexer classes {Escape}; terminal EscapeQName_t '$QName' lexer classes {Escape}; terminal EscapeQNameAttrOccur_t '$QNameAttrOccur' lexer classes {Escape}; terminal EscapeName_t '$Name' lexer classes {Escape}; diff --git a/grammars/silver/extension/strategyattr/ConcreteSyntax.sv b/grammars/silver/extension/strategyattr/ConcreteSyntax.sv new file mode 100644 index 000000000..cb4dcd67f --- /dev/null +++ b/grammars/silver/extension/strategyattr/ConcreteSyntax.sv @@ -0,0 +1,80 @@ +grammar silver:extension:strategyattr; + +inherited attribute givenGenName::String; + +concrete production strategyAttributeDcl_c +top::AGDcl ::= 'strategy' 'attribute' a::Name '=' e::StrategyExpr_c ';' +{ + top.unparse = "strategy attribute " ++ a.unparse ++ "=" ++ e.unparse ++ ";"; + e.givenGenName = a.name; + forwards to strategyAttributeDcl(a, e.ast, location=top.location); +} + +nonterminal StrategyExpr_c with location, givenGenName, unparse, ast; + +concrete productions top::StrategyExpr_c +| 'id' +{ + top.unparse = "id"; + top.ast = id(genName=top.givenGenName, location=top.location); +} +| 'fail' +{ + top.unparse = "fail"; + top.ast = fail(genName=top.givenGenName, location=top.location); +} +| s1::StrategyExpr_c '<*' s2::StrategyExpr_c +{ + top.unparse = s"(${s1.unparse} <* ${s2.unparse})"; + top.ast = sequence(s1.ast, s2.ast, genName=top.givenGenName, location=top.location); + s1.givenGenName = top.givenGenName; + s2.givenGenName = top.givenGenName ++ "_cont"; +} +| s1::StrategyExpr_c '<+' s2::StrategyExpr_c +{ + top.unparse = s"(${s1.unparse} <+ ${s2.unparse})"; + top.ast = choice(s1.ast, s2.ast, genName=top.givenGenName, location=top.location); + s1.givenGenName = top.givenGenName ++ "_left"; + s2.givenGenName = top.givenGenName ++ "_right"; +} +| 'all' '(' s::StrategyExpr_c ')' +{ + top.unparse = s"all(${s.unparse})"; + top.ast = allTraversal(s.ast, genName=top.givenGenName, location=top.location); + s.givenGenName = top.givenGenName ++ "_item"; +} +| 'some' '(' s::StrategyExpr_c ')' +{ + top.unparse = s"some(${s.unparse})"; + top.ast = someTraversal(s.ast, genName=top.givenGenName, location=top.location); + s.givenGenName = top.givenGenName ++ "_item"; +} +| 'one' '(' s::StrategyExpr_c ')' +{ + top.unparse = s"one(${s.unparse})"; + top.ast = oneTraversal(s.ast, genName=top.givenGenName, location=top.location); + s.givenGenName = top.givenGenName ++ "_item"; +} +| 'rec' n::Name Arrow_t s::StrategyExpr_c +{ + top.unparse = s"rec ${n.name} -> (${s.unparse})"; + top.ast = rec(n, s.ast, genName=top.givenGenName, location=top.location); + s.givenGenName = top.givenGenName ++ "_" ++ n.name; +} +| 'rule' 'on' ty::TypeExpr 'of' Opt_Vbar_t ml::MRuleList 'end' +{ + top.unparse = "rule on " ++ ty.unparse ++ " of " ++ ml.unparse ++ " end"; + top.ast = rewriteRule(ty, ml, genName=top.givenGenName, location=top.location); +} +| id::StrategyQName +{ + top.unparse = id.ast.unparse; + top.ast = nameRef(id.ast, genName=top.givenGenName, location=top.location); +} + +nonterminal StrategyQName with location, ast; +concrete productions top::StrategyQName +| id::StrategyName_t +{ top.ast = qNameId(name(id.lexeme, id.location), location=top.location); } +| id::StrategyName_t ':' qn::StrategyQName +{ top.ast = qNameCons(name(id.lexeme, id.location), $2, qn.ast, location=top.location); } \ No newline at end of file diff --git a/grammars/silver/extension/strategyattr/Strategy.sv b/grammars/silver/extension/strategyattr/Strategy.sv index 05baecb52..4db049e2d 100644 --- a/grammars/silver/extension/strategyattr/Strategy.sv +++ b/grammars/silver/extension/strategyattr/Strategy.sv @@ -3,10 +3,10 @@ grammar silver:extension:strategyattr; import silver:definition:flow:driver only ProductionGraph, FlowType, constructAnonymousGraph; import silver:driver:util; -concrete production strategyAttributeDcl -top::AGDcl ::= 'strategy' 'attribute' a::Name '=' e::StrategyExpr ';' +abstract production strategyAttributeDcl +top::AGDcl ::= a::Name e::StrategyExpr { - top.unparse = "strategy attribute " ++ a.unparse ++ ";"; + top.unparse = "strategy attribute " ++ a.unparse ++ "=" ++ e.unparse ++ ";"; production attribute fName :: String; fName = top.grammarName ++ ":" ++ a.name; @@ -27,7 +27,7 @@ top::AGDcl ::= 'strategy' 'attribute' a::Name '=' e::StrategyExpr ';' constructAnonymousGraph(e.flowDefs, top.env, myProds, myFlow); e.frame = globalExprContext(myFlowGraph); - e.genName = a.name; + e.recVars = []; forwards to defsAGDcl( diff --git a/grammars/silver/extension/strategyattr/StrategyExpr.sv b/grammars/silver/extension/strategyattr/StrategyExpr.sv index 6f6d30d02..df1c1a3be 100644 --- a/grammars/silver/extension/strategyattr/StrategyExpr.sv +++ b/grammars/silver/extension/strategyattr/StrategyExpr.sv @@ -2,13 +2,16 @@ grammar silver:extension:strategyattr; import silver:metatranslation; -inherited attribute genName::String; -- Used to generate the names of lifted strategy attributes +annotation genName::String; -- Used to generate the names of lifted strategy attributes + autocopy attribute recVars::[Pair]; monoid attribute liftedStrategies::[Pair] with [], ++; +synthesized attribute attrRefName::Maybe; monoid attribute matchesFrame::Boolean with false, ||; functor attribute translation; +synthesized attribute directRefTranslation::Maybe<(Expr ::= NamedSignatureElement Location)>; {- strategy attribute optimize = @@ -21,10 +24,15 @@ strategy attribute optimize = | choice(fail(), s) -> s | choice(s, fail()) -> s | choice(id(), s) -> id() - | all, some, one... + | choice(functorRef(n), s) -> functorRef(n) + | all(id()) -> id() + | some(fail()) -> fail() + | one(fail()) -> fail() | rec(n, s) when top.attrName.isJust -> replace n with top.attrName in s | rewriteRule(...) when !... .matchesFrame -> fail() - | nameRef(n) when !n.matchesFrame -> fail() + | recVarRef(n) when !n.matchesFrame -> fail() + | strategyRef(n) when !n.matchesFrame -> fail() + | functorRef(n) when !n.matchesFrame -> fail() end); -} @@ -34,18 +42,15 @@ nonterminal StrategyExpr with translation; flowtype StrategyExpr = - decorate {grammarName, env, genName, recVars}, -- NOT frame - unparse {}, errors {decorate, frame, config, compiledGrammars, flowEnv}, flowDefs {decorate, frame, config, compiledGrammars, flowEnv}, + decorate {grammarName, env, config, recVars}, -- NOT frame + unparse {}, errors {decorate, frame, compiledGrammars, flowEnv}, flowDefs {decorate, frame, compiledGrammars, flowEnv}, liftedStrategies {decorate}, - translation {decorate, frame, config}; + translation {decorate, frame}; -propagate errors on StrategyExpr excluding nameRef; +propagate errors on StrategyExpr excluding strategyRef, functorRef; propagate flowDefs, liftedStrategies on StrategyExpr; -- Basic combinators -concrete production id_c -top::StrategyExpr ::= 'id' -{ forwards to id(location=top.location); } abstract production id top::StrategyExpr ::= { @@ -53,9 +58,6 @@ top::StrategyExpr ::= top.translation = Silver_Expr { core:just($name{top.frame.lhsNtName}) }; } -concrete production fail_c -top::StrategyExpr ::= 'fail' -{ forwards to fail(location=top.location); } abstract production fail top::StrategyExpr ::= { @@ -63,124 +65,154 @@ top::StrategyExpr ::= top.translation = Silver_Expr { core:nothing() }; } -concrete production sequence_c -top::StrategyExpr ::= s1::StrategyExpr '<*' s2::StrategyExpr -{ - top.unparse = s"(${s1.unparse} <* ${s2.unparse})"; - forwards to sequence(top.genName, s1, s2, location=top.location); -} abstract production sequence -top::StrategyExpr ::= genName::String s1::StrategyExpr s2::StrategyExpr +top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr { top.unparse = s"(${s1.unparse} <* ${s2.unparse})"; - top.liftedStrategies <- [pair(s2.genName, s2)]; - s1.genName = genName; - s2.genName = genName ++ "_cont"; + top.liftedStrategies <- + case s2 of + | recVarRef(_) -> [] + | strategyRef(_) -> [] + | functorRef(_) -> [] + | _ -> [pair(s2.genName, s2)] + end; + local s2Name::String = + case s2 of + | recVarRef(n) -> s2.genName ++ "_" ++ n.name + | strategyRef(n) -> n.name + | functorRef(n) -> n.name + | _ -> s2.genName + end; top.translation = - Silver_Expr { - -- TODO: This could be a monadic bind, but that isn't in core - case $Expr{s1.translation} of - | just(res) -> decorate res with {}.$name{s2.genName} -- TODO: Decorate with all inh attributes - | nothing() -> nothing() - end - }; + case s2 of + | functorRef(_) -> + Silver_Expr { + -- TODO: This could be a monadic bind, but bindMaybe isn't in core + case $Expr{s1.translation} of + | just(res) -> core:just(decorate res with {}.$name{s2Name}) -- TODO: Decorate with all inh attributes + | nothing() -> nothing() + end + } + | _ -> + Silver_Expr { + -- TODO: This could be a monadic bind, but bindMaybe isn't in core + case $Expr{s1.translation} of + | just(res) -> decorate res with {}.$name{s2Name} -- TODO: Decorate with all inh attributes + | nothing() -> nothing() + end + } + end; } -concrete production choice_c -top::StrategyExpr ::= s1::StrategyExpr '<+' s2::StrategyExpr -{ - top.unparse = s"(${s1.unparse} <+ ${s2.unparse})"; - forwards to choice(top.genName, s1, s2, location=top.location); -} abstract production choice -top::StrategyExpr ::= genName::String s1::StrategyExpr s2::StrategyExpr +top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr { top.unparse = s"(${s1.unparse} <+ ${s2.unparse})"; - s1.genName = genName ++ "_left"; - s2.genName = genName ++ "_right"; - top.translation = Silver_Expr { core:orElse($Expr{s1.translation}, $Expr{s2.translation}) }; } -- Traversals -concrete production allTraversal_c -top::StrategyExpr ::= 'all' '(' s::StrategyExpr ')' -{ - top.unparse = s"all(${s.unparse})"; - forwards to allTraversal(top.genName, s, location=top.location); -} abstract production allTraversal -top::StrategyExpr ::= genName::String s::StrategyExpr +top::StrategyExpr ::= s::StrategyExpr { top.unparse = s"all(${s.unparse})"; + top.liftedStrategies <- + case s of + | recVarRef(_) -> [] + | strategyRef(_) -> [] + | functorRef(_) -> [] + | _ -> [pair(s.genName, s)] + end; - s.genName = genName ++ "_all"; - + local sName::String = + case s of + | recVarRef(n) -> s.genName ++ "_" ++ n.name + | strategyRef(n) -> n.name + | functorRef(n) -> n.name + | _ -> s.genName + end; top.translation = - caseExpr( - map( - \ e::NamedSignatureElement -> Silver_Expr { $name{e.elementName} }, - top.frame.signature.inputElements), - ml.matchRuleList, - Silver_Expr { core:nothing() }, - nonterminalType("core:Maybe", [top.frame.signature.outputElement.typerep]), - location=top.location); + case s of + | functorRef(qNameAttrOccur(attr)) -> + Silver_Expr { + core:just( + $Expr{ + -- From the functor attribute extension + mkFullFunctionInvocation( + top.location, + baseExpr(qName(top.location, top.frame.fullName), location=top.location), + map(makeArg(top.location, top.env, attr, _), top.frame.signature.inputElements), + map( + makeAnnoArg(top.location, top.frame.signature.outputElement.elementName, _), + top.frame.signature.namedInputElements))}) + } + | _ -> + caseExpr( + map( + \ n::String -> Silver_Expr { $name{n}.$name{sName} }, + top.frame.signature.inputNames), + [matchRule( + map( + \ n::String -> + decorate + varPattern(name(n ++ "_" ++ sName, top.location), location=top.location) + with { config = top.config; env = top.env; frame = top.frame; patternVarEnv = []; }, + top.frame.signature.inputNames), + nothing(), + mkStrFunctionInvocation( + top.location, top.frame.fullName, + map( + \ n::String -> Silver_Expr { $name{n ++ "_" ++ sName} }, + top.frame.signature.inputNames)), + location=top.location)], + Silver_Expr { core:nothing() }, + nonterminalType("core:Maybe", [top.frame.signature.outputElement.typerep]), + location=top.location) + end; } -concrete production someTraversal_c -top::StrategyExpr ::= 'some' '(' s::StrategyExpr ')' -{ - top.unparse = s"some(${s.unparse})"; - forwards to someTraversal(top.genName, s, location=top.location); -} abstract production someTraversal -top::StrategyExpr ::= genName::String s::StrategyExpr +top::StrategyExpr ::= s::StrategyExpr { top.unparse = s"some(${s.unparse})"; + top.liftedStrategies <- + case s of + | nameRef(_) -> [] + | _ -> [pair(s.genName, s)] + end; - s.genName = genName ++ "_some"; - -} - -concrete production oneTraversal_c -top::StrategyExpr ::= 'one' '(' s::StrategyExpr ')' -{ - top.unparse = s"one(${s.unparse})"; - forwards to oneTraversal(top.genName, s, location=top.location); + local sName::String = + case s of + | nameRef(n) -> n.name + | _ -> s.genName + end; + top.translation = + mkStrFunctionInvocation( + top.location, top.frame.fullName, + map( + \ n::String -> + Silver_Expr { core:fromMaybe($name{n}, $name{n}.$name{sName}) }, + top.frame.signature.inputNames)); } abstract production oneTraversal -top::StrategyExpr ::= genName::String s::StrategyExpr +top::StrategyExpr ::= s::StrategyExpr { top.unparse = s"one(${s.unparse})"; - s.genName = genName ++ "_one"; - - } -- Recursive strategies -concrete production rec_c -top::StrategyExpr ::= 'rec' n::Name Arrow_t s::StrategyExpr -{ - top.unparse = s"rec ${n.name} -> (${s.unparse})"; - forwards to rec(top.genName, n, s, location=top.location); -} abstract production rec -top::StrategyExpr ::= genName::String n::Name s::StrategyExpr +top::StrategyExpr ::= n::Name s::StrategyExpr { top.unparse = s"rec ${n.name} -> (${s.unparse})"; - s.genName = genName ++ "_" ++ n.name; - } -- Rules -concrete production rewriteRule_c -top::StrategyExpr ::= 'rule' 'on' ty::TypeExpr 'of' Opt_Vbar_t ml::MRuleList 'end' -{ forwards to rewriteRule(ty, ml, location=top.location); } abstract production rewriteRule top::StrategyExpr ::= ty::TypeExpr ml::MRuleList { @@ -270,51 +302,91 @@ top::Pattern ::= prod::QName '(' ps::PatternList ',' nps::NamedPatternList ')' } -- References to other attributes or rec variables -concrete production nameRef_c -top::StrategyExpr ::= id::StrategyQName -{ forwards to nameRef(qNameAttrOccur(id.ast, location=top.location), location=top.location); } abstract production nameRef +top::StrategyExpr ::= id::QName +{ + top.unparse = id.unparse; + + local attrDcl::DclInfo = id.lookupAttribute.dcl; + attrDcl.givenNonterminalType = error("Not actually needed"); -- Ugh environment needs refactoring + forwards to + if lookupBy(stringEq, id.name, top.recVars).isJust + then recVarRef(id, genName=top.genName, location=top.location) + else if !null(id.lookupAttribute.errors) + then errorRef(id.lookupAttribute.errors, id, genName=top.genName, location=top.location) + else case decorate id.lookupAttribute.dcl with { givenNonterminalType = error("Not actually needed"); }.typerep of -- Ugh environment needs refactoring + | nonterminalType("core:Maybe", _) -> strategyRef(qNameAttrOccur(id, location=top.location), genName=top.genName, location=top.location) + | _ -> functorRef(qNameAttrOccur(id, location=top.location), genName=top.genName, location=top.location) + end; +} +abstract production errorRef +top::StrategyExpr ::= msg::[Message] id::Decorated QName +{ + top.unparse = id.unparse; + + top.errors <- msg; + top.translation = Silver_Expr { core:nothing() }; +} +abstract production recVarRef +top::StrategyExpr ::= id::Decorated QName +{ + top.unparse = id.unparse; + + local recAttr::String = lookupBy(stringEq, id.name, top.recVars).fromJust; + + top.translation = Silver_Expr { $name{top.frame.signature.outputElement.elementName}.$qName{recAttr} }; +} +abstract production strategyRef top::StrategyExpr ::= id::QNameAttrOccur { top.unparse = id.unparse; - local recAttr::Maybe = lookupBy(stringEq, id.name, top.recVars); local attrDcl::DclInfo = case id of qNameAttrOccur(a) -> a.lookupAttribute.dcl end; - attrDcl.givenNonterminalType = error("Not needed"); -- Ugh environment needs refactoring + attrDcl.givenNonterminalType = error("Not actually needed"); -- Ugh environment needs refactoring top.errors := - if recAttr.isJust then [] - else - case id of qNameAttrOccur(a) -> a.lookupAttribute.errors end ++ - case attrDcl.typerep, attrDcl.dclBoundVars of - | nonterminalType("core:Maybe", [varType(a1)]), [a2] when tyVarEqual(a1, a2) -> [] - | varType(a1), [a2] when tyVarEqual(a1, a2) -> [] - | nonterminalType("core:Maybe", [nonterminalType(nt, _)]), _ -> - case getOccursDcl(attrDcl.fullName, nt, top.env) of - | [] -> [wrn(id.location, s"Attribute ${id.name} doesn't occur on its own nonterminal type ${nt}")] - | _ -> [] - end - | nonterminalType(nt, _), _ -> - case getOccursDcl(attrDcl.fullName, nt, top.env) of - | [] -> [wrn(id.location, s"Attribute ${id.name} doesn't occur on its own nonterminal type ${nt}")] - | _ -> [] - end - | errorType(), _ -> [] - | _, _ -> [err(id.location, "Attribute has invalid type for use in a strategy")] - end; + case attrDcl.typerep, attrDcl.dclBoundVars of + | nonterminalType("core:Maybe", [varType(a1)]), [a2] when tyVarEqual(a1, a2) -> [] + | nonterminalType("core:Maybe", [nonterminalType(nt, _)]), _ -> + case getOccursDcl(attrDcl.fullName, nt, top.env) of + | [] -> [wrn(id.location, s"Attribute ${id.name} cannot be used as a strategy, because it doesn't occur on its own nonterminal type ${nt}")] + | _ -> [] + end + | errorType(), _ -> [] + | _, _ -> [err(id.location, s"Attribute ${id.name} cannot be used as a strategy")] + end; id.attrFor = top.frame.signature.outputElement.typerep; top.translation = - case recAttr, id.matchesFrame, id.typerep of - | just(a), _, _ -> - Silver_Expr { $name{top.frame.signature.outputElement.elementName}.$qName{a} } - | nothing(), true, nonterminalType("core:Maybe", _) -> - Silver_Expr { $name{top.frame.signature.outputElement.elementName}.$QNameAttrOccur{id} } - | nothing(), true, _ -> - Silver_Expr { core:just($name{top.frame.signature.outputElement.elementName}.$QNameAttrOccur{id}) } - | nothing(), false, _ -> - Silver_Expr { core:nothing() } + if id.matchesFrame + then Silver_Expr { $name{top.frame.signature.outputElement.elementName}.$QNameAttrOccur{id} } + else Silver_Expr { core:nothing() }; +} +abstract production functorRef +top::StrategyExpr ::= id::QNameAttrOccur +{ + top.unparse = id.unparse; + + local attrDcl::DclInfo = case id of qNameAttrOccur(a) -> a.lookupAttribute.dcl end; + attrDcl.givenNonterminalType = error("Not actually needed"); -- Ugh environment needs refactoring + top.errors := + case attrDcl.typerep, attrDcl.dclBoundVars of + | varType(a1), [a2] when tyVarEqual(a1, a2) -> [] + | nonterminalType(nt, _), _ -> + case getOccursDcl(attrDcl.fullName, nt, top.env) of + | [] -> [wrn(id.location, s"Attribute ${id.name} cannot be used as a functor, because it doesn't occur on its own nonterminal type ${nt}")] + | _ -> [] + end + | errorType(), _ -> [] + | _, _ -> [err(id.location, s"Attribute ${id.name} cannot be used as a functor")] end; + + id.attrFor = top.frame.signature.outputElement.typerep; + + top.translation = + if id.matchesFrame + then Silver_Expr { core:just($name{top.frame.signature.outputElement.elementName}.$QNameAttrOccur{id}) } + else Silver_Expr { core:nothing() }; } attribute matchesFrame occurs on QNameAttrOccur; @@ -322,7 +394,7 @@ attribute matchesFrame occurs on QNameAttrOccur; aspect production qNameAttrOccur top::QNameAttrOccur ::= at::QName { - top.matchesFrame := !top.found || + top.matchesFrame := top.found && case top.typerep of | nonterminalType("core:Maybe", [t]) -> !unify(top.attrFor, t).failure | t -> !unify(top.attrFor, t).failure diff --git a/grammars/silver/extension/strategyattr/Terminals.sv b/grammars/silver/extension/strategyattr/Terminals.sv index ad4fb0bb4..72bb9725a 100644 --- a/grammars/silver/extension/strategyattr/Terminals.sv +++ b/grammars/silver/extension/strategyattr/Terminals.sv @@ -16,10 +16,3 @@ terminal Rule_t 'rule' lexer classes {KEYWORD, STRATEGY_COMB}; terminal Rec_t 'rec' lexer classes {KEYWORD, STRATEGY_COMB}; terminal StrategyName_t /[a-z][A-Za-z0-9\_]*/ lexer classes {IDENTIFIER}; - -nonterminal StrategyQName with location, ast; -concrete productions top::StrategyQName -| id::StrategyName_t -{ top.ast = qNameId(name(id.lexeme, id.location), location=top.location); } -| id::StrategyName_t ':' qn::StrategyQName -{ top.ast = qNameCons(name(id.lexeme, id.location), $2, qn.ast, location=top.location); } diff --git a/grammars/silver/extension/strategyattr/convenience/Convenience.sv b/grammars/silver/extension/strategyattr/convenience/Convenience.sv index cbc0cf6f1..b91106b0e 100644 --- a/grammars/silver/extension/strategyattr/convenience/Convenience.sv +++ b/grammars/silver/extension/strategyattr/convenience/Convenience.sv @@ -9,12 +9,12 @@ import silver:definition:type; import silver:definition:env; concrete production strategyAttributeDclMultiple -top::AGDcl ::= 'strategy' 'attribute' a::Name '=' e::StrategyExpr 'occurs' 'on' qs::QNames ';' +top::AGDcl ::= 'strategy' 'attribute' a::Name '=' e::StrategyExpr_c 'occurs' 'on' qs::QNames ';' { top.unparse = "strategy attribute " ++ a.name ++ " occurs on " ++ qs.unparse ++ ";"; forwards to appendAGDcl( - strategyAttributeDcl($1, $2, a, $4, e, $9, location=a.location), + strategyAttributeDcl_c($1, $2, a, $4, e, $9, location=a.location), makeOccursDclsHelp($1.location, qNameWithTL(qNameId(a, location=a.location), botlNone(location=top.location)), qs.qnames), location=top.location); } From 25dc931eed167c76ddc8eda742135b13c7f96f13 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Mon, 6 Apr 2020 20:08:45 -0500 Subject: [PATCH 08/78] Add range function to core --- grammars/core/List.sv | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/grammars/core/List.sv b/grammars/core/List.sv index 6fd95ccc4..327d028fc 100644 --- a/grammars/core/List.sv +++ b/grammars/core/List.sv @@ -277,6 +277,12 @@ function repeat else v :: repeat(v, times-1); } +function range +[Integer] ::= lower::Integer upper::Integer +{ + return if lower >= upper then [] else lower :: range(lower + 1, upper); +} + function zipWith [c] ::= f::(c ::= a b) l1::[a] l2::[b] { From c0e53ac509670be13cad6ea214cf38ea4c75e209 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Mon, 6 Apr 2020 20:09:08 -0500 Subject: [PATCH 09/78] Fully implement all, some, one --- .../extension/strategyattr/StrategyExpr.sv | 287 +++++++++++++----- 1 file changed, 204 insertions(+), 83 deletions(-) diff --git a/grammars/silver/extension/strategyattr/StrategyExpr.sv b/grammars/silver/extension/strategyattr/StrategyExpr.sv index df1c1a3be..8f7180c3a 100644 --- a/grammars/silver/extension/strategyattr/StrategyExpr.sv +++ b/grammars/silver/extension/strategyattr/StrategyExpr.sv @@ -11,7 +11,6 @@ synthesized attribute attrRefName::Maybe; monoid attribute matchesFrame::Boolean with false, ||; functor attribute translation; -synthesized attribute directRefTranslation::Maybe<(Expr ::= NamedSignatureElement Location)>; {- strategy attribute optimize = @@ -29,6 +28,11 @@ strategy attribute optimize = | some(fail()) -> fail() | one(fail()) -> fail() | rec(n, s) when top.attrName.isJust -> replace n with top.attrName in s + + -- These don't apply inside traversals/sequence continuations! + | all(s) when !attrMatchesChild(top.env, fromMaybe(s.genName, s.attrRefName), top.frame) -> id() + | some(s) when !attrMatchesChild(top.env, fromMaybe(s.genName, s.attrRefName), top.frame) -> fail() + | one(s) when !attrMatchesChild(top.env, fromMaybe(s.genName, s.attrRefName), top.frame) -> fail() | rewriteRule(...) when !... .matchesFrame -> fail() | recVarRef(n) when !n.matchesFrame -> fail() | strategyRef(n) when !n.matchesFrame -> fail() @@ -38,18 +42,24 @@ strategy attribute optimize = nonterminal StrategyExpr with config, grammarName, env, location, unparse, errors, frame, compiledGrammars, flowEnv, flowDefs, -- Normal expression stuff - genName, recVars, liftedStrategies, + genName, recVars, liftedStrategies, attrRefName, translation; flowtype StrategyExpr = decorate {grammarName, env, config, recVars}, -- NOT frame unparse {}, errors {decorate, frame, compiledGrammars, flowEnv}, flowDefs {decorate, frame, compiledGrammars, flowEnv}, - liftedStrategies {decorate}, + liftedStrategies {decorate}, attrRefName {decorate}, translation {decorate, frame}; propagate errors on StrategyExpr excluding strategyRef, functorRef; propagate flowDefs, liftedStrategies on StrategyExpr; +aspect default production +top::StrategyExpr ::= +{ + top.attrRefName = nothing(); +} + -- Basic combinators abstract production id top::StrategyExpr ::= @@ -71,30 +81,34 @@ top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr top.unparse = s"(${s1.unparse} <* ${s2.unparse})"; top.liftedStrategies <- case s2 of - | recVarRef(_) -> [] - | strategyRef(_) -> [] | functorRef(_) -> [] + | _ when s2.attrRefName.isJust -> [] | _ -> [pair(s2.genName, s2)] end; - local s2Name::String = - case s2 of - | recVarRef(n) -> s2.genName ++ "_" ++ n.name - | strategyRef(n) -> n.name - | functorRef(n) -> n.name - | _ -> s2.genName - end; + local s2Name::String = fromMaybe(s2.genName, s2.attrRefName); top.translation = - case s2 of - | functorRef(_) -> + case s1, s2 of + | functorRef(attr1), functorRef(attr2) -> + Silver_Expr { + core:just( + decorate $name{top.frame.signature.outputElement.elementName}.$QNameAttrOccur{attr1} + with {}.$QNameAttrOccur{attr2}) -- TODO: Decorate with all inh attributes + } + | functorRef(attr1), _ -> + Silver_Expr { + decorate $name{top.frame.signature.outputElement.elementName}.$QNameAttrOccur{attr1} + with {}.$name{s2Name} + } + | _, functorRef(attr2) -> Silver_Expr { -- TODO: This could be a monadic bind, but bindMaybe isn't in core case $Expr{s1.translation} of - | just(res) -> core:just(decorate res with {}.$name{s2Name}) -- TODO: Decorate with all inh attributes + | just(res) -> decorate res with {}.$QNameAttrOccur{attr2} -- TODO: Decorate with all inh attributes | nothing() -> nothing() end } - | _ -> + | _, _ -> Silver_Expr { -- TODO: This could be a monadic bind, but bindMaybe isn't in core case $Expr{s1.translation} of @@ -119,58 +133,56 @@ top::StrategyExpr ::= s::StrategyExpr { top.unparse = s"all(${s.unparse})"; top.liftedStrategies <- - case s of - | recVarRef(_) -> [] - | strategyRef(_) -> [] - | functorRef(_) -> [] - | _ -> [pair(s.genName, s)] - end; + if s.attrRefName.isJust + then [] + else [pair(s.genName, s)]; - local sName::String = - case s of - | recVarRef(n) -> s.genName ++ "_" ++ n.name - | strategyRef(n) -> n.name - | functorRef(n) -> n.name - | _ -> s.genName - end; + local sName::String = fromMaybe(s.genName, s.attrRefName); + local childAccesses::[Pair] = + map( + \ e::NamedSignatureElement -> + pair(e.elementName, attrMatchesFrame(top.env, sName, e.typerep)), + top.frame.signature.inputElements); top.translation = - case s of - | functorRef(qNameAttrOccur(attr)) -> - Silver_Expr { - core:just( - $Expr{ - -- From the functor attribute extension - mkFullFunctionInvocation( - top.location, - baseExpr(qName(top.location, top.frame.fullName), location=top.location), - map(makeArg(top.location, top.env, attr, _), top.frame.signature.inputElements), - map( - makeAnnoArg(top.location, top.frame.signature.outputElement.elementName, _), - top.frame.signature.namedInputElements))}) - } - | _ -> - caseExpr( - map( - \ n::String -> Silver_Expr { $name{n}.$name{sName} }, - top.frame.signature.inputNames), - [matchRule( - map( - \ n::String -> - decorate - varPattern(name(n ++ "_" ++ sName, top.location), location=top.location) - with { config = top.config; env = top.env; frame = top.frame; patternVarEnv = []; }, - top.frame.signature.inputNames), - nothing(), - mkStrFunctionInvocation( - top.location, top.frame.fullName, - map( - \ n::String -> Silver_Expr { $name{n ++ "_" ++ sName} }, - top.frame.signature.inputNames)), - location=top.location)], - Silver_Expr { core:nothing() }, - nonterminalType("core:Maybe", [top.frame.signature.outputElement.typerep]), - location=top.location) - end; + {- case a.s, c.s of + | just(a_s), just(c_s) -> just(prod(a_s, b, c_s)) + | _, _ -> nothing() + end -} + caseExpr( + flatMap( + \ a::Pair -> + if a.snd then [Silver_Expr { $name{a.fst}.$name{sName} }] else [], + childAccesses), + [matchRule( + flatMap( + \ a::Pair -> + if a.snd + then + [decorate Silver_Pattern { $name{a.fst ++ "_" ++ sName} } + with { config = top.config; env = top.env; frame = top.frame; patternVarEnv = []; }] + else [], + childAccesses), + nothing(), + Silver_Expr { + core:just( + $Expr{ + mkFullFunctionInvocation( + top.location, + baseExpr(qName(top.location, top.frame.fullName), location=top.location), + map( + \ a::Pair -> + if a.snd + then Silver_Expr { $name{a.fst ++ "_" ++ sName} } + else Silver_Expr { $name{a.fst} }, + childAccesses), + map( + makeAnnoArg(top.location, top.frame.signature.outputElement.elementName, _), + top.frame.signature.namedInputElements))}) + }, + location=top.location)], + Silver_Expr { core:nothing() }, + nonterminalType("core:Maybe", [top.frame.signature.outputElement.typerep]), + location=top.location); } abstract production someTraversal @@ -178,29 +190,111 @@ top::StrategyExpr ::= s::StrategyExpr { top.unparse = s"some(${s.unparse})"; top.liftedStrategies <- - case s of - | nameRef(_) -> [] - | _ -> [pair(s.genName, s)] - end; + if s.attrRefName.isJust + then [] + else [pair(s.genName, s)]; - local sName::String = - case s of - | nameRef(n) -> n.name - | _ -> s.genName - end; + local sName::String = fromMaybe(s.genName, s.attrRefName); + local childAccesses::[Pair] = + map( + \ e::NamedSignatureElement -> + pair( + e.elementName, + decorate qNameAttrOccur(qName(top.location, sName), location=top.location) + with { config = top.config; grammarName = top.grammarName; env = top.env; attrFor = e.typerep; }.matchesFrame), + top.frame.signature.inputElements); top.translation = - mkStrFunctionInvocation( - top.location, top.frame.fullName, - map( - \ n::String -> - Silver_Expr { core:fromMaybe($name{n}, $name{n}.$name{sName}) }, - top.frame.signature.inputNames)); + {- if a.s.isJust || c.s.isJust + then just(prod(fromMaybe(a, a.s), b, fromMaybe(c, c.s))) + else nothing() -} + Silver_Expr { + if $Expr{ + foldr( + or(_, '||', _, location=top.location), + falseConst('false', location=top.location), + map( + \ a::String -> Silver_Expr { $name{a}.$name{sName}.isJust }, + map(fst, filter(snd, childAccesses))))} + then + core:just( + $Expr{ + mkFullFunctionInvocation( + top.location, + baseExpr(qName(top.location, top.frame.fullName), location=top.location), + map( + \ a::Pair -> + if a.snd + then Silver_Expr { core:fromMaybe($name{a.fst}, $name{a.fst}.$name{sName}) } + else Silver_Expr { $name{a.fst} }, + childAccesses), + map( + makeAnnoArg(top.location, top.frame.signature.outputElement.elementName, _), + top.frame.signature.namedInputElements))}) + else core:nothing() + }; } abstract production oneTraversal top::StrategyExpr ::= s::StrategyExpr { top.unparse = s"one(${s.unparse})"; + top.liftedStrategies <- + if s.attrRefName.isJust + then [] + else [pair(s.genName, s)]; + + local sName::String = fromMaybe(s.genName, s.attrRefName); + local childAccesses::[Pair] = + map( + \ e::NamedSignatureElement -> + pair(e.elementName, attrMatchesFrame(top.env, sName, e.typerep)), + top.frame.signature.inputElements); + local matchingChildren::[String] = map(fst, filter(snd, childAccesses)); + top.translation = + {- case a.s, c.s of + | just(a_s), _ -> just(prod(a_s, b, c)) + | _, just(c_s) -> just(prod(a, b, c_s)) + | _, _ -> nothing() + end -} + caseExpr( + map( + \ a::String -> Silver_Expr { $name{a}.$name{sName} }, + matchingChildren), + map( + \ i::Integer -> + let childI::String = head(drop(i, matchingChildren)) + in let childIndex::Integer = positionOf(stringEq, childI, map(fst, childAccesses)) + in + matchRule( + map( + \ p::Pattern -> decorate p with { config = top.config; env = top.env; frame = top.frame; patternVarEnv = []; }, + repeat(wildcPattern('_', location=top.location), i) ++ + Silver_Pattern { $name{childI ++ "_" ++ sName} } :: + repeat(wildcPattern('_', location=top.location), length(matchingChildren) - (i + 1))), + nothing(), + Silver_Expr { + core:just( + $Expr{ + mkFullFunctionInvocation( + top.location, + baseExpr(qName(top.location, top.frame.fullName), location=top.location), + map( + \ a::Pair -> Silver_Expr { $name{a.fst} }, + take(childIndex, childAccesses)) ++ + Silver_Expr { $name{childI ++ "_" ++ sName} } :: + map( + \ a::Pair -> Silver_Expr { $name{a.fst} }, + drop(childIndex + 1, childAccesses)), + map( + makeAnnoArg(top.location, top.frame.signature.outputElement.elementName, _), + top.frame.signature.namedInputElements))}) + }, + location=top.location) + end end, + range(0, length(matchingChildren))), + Silver_Expr { core:nothing() }, + nonterminalType("core:Maybe", [top.frame.signature.outputElement.typerep]), + location=top.location); } -- Recursive strategies @@ -307,6 +401,8 @@ top::StrategyExpr ::= id::QName { top.unparse = id.unparse; + top.attrRefName = just(id.name); + local attrDcl::DclInfo = id.lookupAttribute.dcl; attrDcl.givenNonterminalType = error("Not actually needed"); -- Ugh environment needs refactoring forwards to @@ -324,6 +420,8 @@ top::StrategyExpr ::= msg::[Message] id::Decorated QName { top.unparse = id.unparse; + top.attrRefName = just(id.name); + top.errors <- msg; top.translation = Silver_Expr { core:nothing() }; } @@ -332,9 +430,9 @@ top::StrategyExpr ::= id::Decorated QName { top.unparse = id.unparse; - local recAttr::String = lookupBy(stringEq, id.name, top.recVars).fromJust; + top.attrRefName = lookupBy(stringEq, id.name, top.recVars); - top.translation = Silver_Expr { $name{top.frame.signature.outputElement.elementName}.$qName{recAttr} }; + top.translation = Silver_Expr { $name{top.frame.signature.outputElement.elementName}.$qName{top.attrRefName.fromJust} }; } abstract production strategyRef top::StrategyExpr ::= id::QNameAttrOccur @@ -355,6 +453,8 @@ top::StrategyExpr ::= id::QNameAttrOccur | _, _ -> [err(id.location, s"Attribute ${id.name} cannot be used as a strategy")] end; + top.attrRefName = just(id.name); + id.attrFor = top.frame.signature.outputElement.typerep; top.translation = @@ -381,6 +481,8 @@ top::StrategyExpr ::= id::QNameAttrOccur | _, _ -> [err(id.location, s"Attribute ${id.name} cannot be used as a functor")] end; + top.attrRefName = nothing(); + id.attrFor = top.frame.signature.outputElement.typerep; top.translation = @@ -400,3 +502,22 @@ top::QNameAttrOccur ::= at::QName | t -> !unify(top.attrFor, t).failure end; } + +function attrMatchesFrame +Boolean ::= env::Decorated Env attrName::String attrFor::Type +{ + return + decorate qNameAttrOccur(qName(loc("", -1, -1, -1, -1, -1, -1), attrName), location=loc("", -1, -1, -1, -1, -1, -1)) + with { env = env; attrFor = attrFor; }.matchesFrame; +} + +function attrMatchesChild +Boolean ::= env::Decorated Env attrName::String frame::BlockContext +{ + return + any( + map( + \ e::NamedSignatureElement -> attrMatchesFrame(env, attrName, e.typerep), + frame.signature.inputElements)); +} + From cc629c79f1d96015897191909df3c1e0a47ca429 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Tue, 7 Apr 2020 17:24:50 -0500 Subject: [PATCH 10/78] Add pp on caseExpr, workaround for no match rules --- grammars/silver/extension/patternmatching/Case.sv | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/grammars/silver/extension/patternmatching/Case.sv b/grammars/silver/extension/patternmatching/Case.sv index bb0c26b44..21ed9da3c 100644 --- a/grammars/silver/extension/patternmatching/Case.sv +++ b/grammars/silver/extension/patternmatching/Case.sv @@ -25,7 +25,7 @@ autocopy attribute matchRulePatternSize :: Integer; -- P -> E nonterminal MatchRule with location, config, unparse, env, frame, errors, matchRuleList, matchRulePatternSize; -nonterminal AbstractMatchRule with location, headPattern, isVarMatchRule, expandHeadPattern; +nonterminal AbstractMatchRule with location, unparse, headPattern, isVarMatchRule, expandHeadPattern; -- The head pattern of a match rule synthesized attribute headPattern :: Decorated Pattern; @@ -75,13 +75,18 @@ top::Expr ::= 'case' es::Exprs 'of' Opt_Vbar_t ml::MRuleList 'end' abstract production caseExpr top::Expr ::= es::[Expr] ml::[AbstractMatchRule] failExpr::Expr retType::Type { - top.unparse = error("Internal error: pretty of intermediate data structure"); + top.unparse = + "(case " ++ implode(", ", map((.unparse), es)) ++ " of " ++ + implode(" | ", map((.unparse), ml)) ++ " | _ -> " ++ failExpr.unparse ++ + " end :: " ++ prettyType(retType) ++ ")"; -- 4 cases: no patterns left, all constructors, all variables, or mixed con/var. -- errors cases: more patterns no scrutinees, more scrutinees no patterns, no scrutinees multiple rules forwards to case ml of | matchRule([], c, e) :: _ -> buildMatchWhenConditionals(ml, failExpr) -- valid or error case + -- No match rules, only possible through abstract syntax + | [] -> Silver_Expr { let res :: $TypeExpr{typerepTypeExpr(retType, location=top.location)} = $Expr{failExpr} in res end } | _ -> if null(es) then failExpr -- error case else if null(varRules) then allConCase else if null(prodRules) then allVarCase @@ -203,6 +208,10 @@ top::MatchRule ::= pt::PatternList 'when' cond::Expr '->' e::Expr abstract production matchRule top::AbstractMatchRule ::= pl::[Decorated Pattern] cond::Maybe e::Expr { + top.unparse = + implode(", ", map((.unparse), pl)) ++ + (if cond.isJust then " when " ++ cond.fromJust.unparse else "") ++ + " -> " ++ e.unparse; top.headPattern = head(pl); -- If pl is null, and we're consulted, then we're missing patterns, pretend they're _ top.isVarMatchRule = null(pl) || head(pl).patternIsVariable; From c987590f1e93769d7f70d50629577612f1b8aad8 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Tue, 7 Apr 2020 17:25:36 -0500 Subject: [PATCH 11/78] Initial working implementation of strategy attributes, elimPlusZero example --- grammars/silver/extension/autoattr/Functor.sv | 2 +- .../extension/strategyattr/ConcreteSyntax.sv | 15 +- .../silver/extension/strategyattr/DclInfo.sv | 19 +- .../silver/extension/strategyattr/Strategy.sv | 58 ++++-- .../extension/strategyattr/StrategyExpr.sv | 172 +++++++++++++----- test/silver_features/Strategy.sv | 48 +++++ 6 files changed, 251 insertions(+), 63 deletions(-) create mode 100644 test/silver_features/Strategy.sv diff --git a/grammars/silver/extension/autoattr/Functor.sv b/grammars/silver/extension/autoattr/Functor.sv index c4042aade..2b0a9a02c 100644 --- a/grammars/silver/extension/autoattr/Functor.sv +++ b/grammars/silver/extension/autoattr/Functor.sv @@ -60,7 +60,7 @@ top::ProductionStmt ::= attr::Decorated QName top.frame.signature.namedInputElements); -- Construct an attribute def and call with the generated arguments - forwards to + forwards to attributeDef( concreteDefLHS(qName(top.location, top.frame.signature.outputElement.elementName), location=top.location), '.', diff --git a/grammars/silver/extension/strategyattr/ConcreteSyntax.sv b/grammars/silver/extension/strategyattr/ConcreteSyntax.sv index cb4dcd67f..e516c46db 100644 --- a/grammars/silver/extension/strategyattr/ConcreteSyntax.sv +++ b/grammars/silver/extension/strategyattr/ConcreteSyntax.sv @@ -7,7 +7,7 @@ top::AGDcl ::= 'strategy' 'attribute' a::Name '=' e::StrategyExpr_c ';' { top.unparse = "strategy attribute " ++ a.unparse ++ "=" ++ e.unparse ++ ";"; e.givenGenName = a.name; - forwards to strategyAttributeDcl(a, e.ast, location=top.location); + forwards to strategyAttributeDcl(a, [], e.ast, location=top.location); } nonterminal StrategyExpr_c with location, givenGenName, unparse, ast; @@ -61,16 +61,27 @@ concrete productions top::StrategyExpr_c top.ast = rec(n, s.ast, genName=top.givenGenName, location=top.location); s.givenGenName = top.givenGenName ++ "_" ++ n.name; } +| 'rule' 'on' id::Name '::' ty::TypeExpr 'of' Opt_Vbar_t ml::MRuleList 'end' +{ + top.unparse = "rule on " ++ id.unparse ++ "::" ++ ty.unparse ++ " of " ++ ml.unparse ++ " end"; + top.ast = rewriteRule(id, ty, ml, genName=top.givenGenName, location=top.location); +} | 'rule' 'on' ty::TypeExpr 'of' Opt_Vbar_t ml::MRuleList 'end' { top.unparse = "rule on " ++ ty.unparse ++ " of " ++ ml.unparse ++ " end"; - top.ast = rewriteRule(ty, ml, genName=top.givenGenName, location=top.location); + top.ast = rewriteRule(name("top", top.location), ty, ml, genName=top.givenGenName, location=top.location); } | id::StrategyQName { top.unparse = id.ast.unparse; top.ast = nameRef(id.ast, genName=top.givenGenName, location=top.location); } +| '(' s::StrategyExpr_c ')' +{ + top.unparse = s"(${s.unparse})"; + top.ast = s.ast; + s.givenGenName = top.givenGenName; +} nonterminal StrategyQName with location, ast; concrete productions top::StrategyQName diff --git a/grammars/silver/extension/strategyattr/DclInfo.sv b/grammars/silver/extension/strategyattr/DclInfo.sv index a08783a9a..589349f14 100644 --- a/grammars/silver/extension/strategyattr/DclInfo.sv +++ b/grammars/silver/extension/strategyattr/DclInfo.sv @@ -1,17 +1,24 @@ grammar silver:extension:strategyattr; +synthesized attribute containsErrors::Boolean occurs on DclInfo; +synthesized attribute liftedStrategyNames::[String] occurs on DclInfo; +synthesized attribute givenRecVarEnv::[Pair] occurs on DclInfo; synthesized attribute strategyExpr :: StrategyExpr occurs on DclInfo; -attribute liftedStrategies occurs on DclInfo; aspect default production top::DclInfo ::= { + top.containsErrors = false; + top.liftedStrategyNames = []; + top.givenRecVarEnv = []; top.strategyExpr = error("Internal compiler error: must be defined for all strategy attribute declarations"); - top.liftedStrategies := []; } abstract production strategyDcl -top::DclInfo ::= sg::String sl::Location fn::String tyVar::TyVar e::Decorated StrategyExpr +top::DclInfo ::= + sg::String sl::Location fn::String tyVar::TyVar + containsErrors::Boolean liftedStrategyNames::[String] givenRecVarEnv::[Pair] + e::StrategyExpr { top.sourceGrammar = sg; top.sourceLocation = sl; @@ -27,6 +34,8 @@ top::DclInfo ::= sg::String sl::Location fn::String tyVar::TyVar e::Decorated St top.attributionDispatcher = strategyAttributionDcl(_, _, _, _, location=_); top.propagateDispatcher = propagateStrategy(_, location=_); - top.strategyExpr = new(e); - top.liftedStrategies := e.liftedStrategies; + top.containsErrors = containsErrors; + top.liftedStrategyNames = liftedStrategyNames; + top.givenRecVarEnv = givenRecVarEnv; + top.strategyExpr = e; } diff --git a/grammars/silver/extension/strategyattr/Strategy.sv b/grammars/silver/extension/strategyattr/Strategy.sv index 4db049e2d..be98ee896 100644 --- a/grammars/silver/extension/strategyattr/Strategy.sv +++ b/grammars/silver/extension/strategyattr/Strategy.sv @@ -4,7 +4,7 @@ import silver:definition:flow:driver only ProductionGraph, FlowType, constructAn import silver:driver:util; abstract production strategyAttributeDcl -top::AGDcl ::= a::Name e::StrategyExpr +top::AGDcl ::= a::Name recVarEnv::[Pair] e::StrategyExpr { top.unparse = "strategy attribute " ++ a.unparse ++ "=" ++ e.unparse ++ ";"; @@ -27,12 +27,23 @@ top::AGDcl ::= a::Name e::StrategyExpr constructAnonymousGraph(e.flowDefs, top.env, myProds, myFlow); e.frame = globalExprContext(myFlowGraph); - e.recVars = []; + e.recVarEnv = recVarEnv; + e.outerAttr = just(a.name); forwards to - defsAGDcl( - [attrDef(defaultEnvItem(strategyDcl(top.grammarName, a.location, fName, freshTyVar(), e)))], - location=top.location); + foldr( + appendAGDcl(_, _, location=top.location), + defsAGDcl( + [attrDef( + defaultEnvItem( + strategyDcl( + top.grammarName, a.location, fName, freshTyVar(), + !null(e.errors), map(fst, e.liftedStrategies), recVarEnv, e)))], + location=top.location), + map( + \ d::Pair -> + strategyAttributeDcl(name(d.fst, top.location), d.snd.recVarEnv, new(d.snd), location=top.location), + e.liftedStrategies)); } abstract production strategyAttributionDcl @@ -61,11 +72,11 @@ top::AGDcl ::= at::Decorated QName attl::BracketedOptTypeExprs nt::QName nttl::B nt, nttl, location=top.location), map( - \ s::Pair -> + \ n::String -> attributionDcl( - 'attribute', qName(top.location, s.fst), attl, 'occurs', 'on', nt, nttl, ';', + 'attribute', qName(top.location, n), attl, 'occurs', 'on', nt, nttl, ';', location=top.location), - at.lookupAttribute.dcl.liftedStrategies)); + at.lookupAttribute.dcl.liftedStrategyNames)); } {-- @@ -75,7 +86,32 @@ top::AGDcl ::= at::Decorated QName attl::BracketedOptTypeExprs nt::QName nttl::B abstract production propagateStrategy top::ProductionStmt ::= attr::Decorated QName { - - -- TODO: Don't generate code if attr decl contains errors - forwards to error("todo"); + top.unparse = s"propagate ${attr.unparse}"; + + production e::StrategyExpr = attr.lookupAttribute.dcl.strategyExpr; + e.grammarName = top.grammarName; + e.config = top.config; + e.frame = top.frame; + e.env = top.env; + e.recVarEnv = attr.lookupAttribute.dcl.givenRecVarEnv; + e.outerAttr = just(attr.lookupAttribute.fullName); + + forwards to + if attr.lookupAttribute.dcl.containsErrors + then errorProductionStmt([], location=top.location) + else --unsafeTrace( + foldr( + productionStmtAppend(_, _, location=top.location), + attributeDef( + concreteDefLHS(qName(top.location, top.frame.signature.outputElement.elementName), location=top.location), + '.', + qNameAttrOccur(new(attr), location=top.location), + '=', + e.translation, + ';', + location=top.location), + map( + \ n::String -> propagateOneAttr(qName(top.location, n), location=top.location), + attr.lookupAttribute.dcl.liftedStrategyNames));--, + --print(attr.name ++ " on " ++ top.frame.fullName ++ ": " ++ e.translation.unparse ++ "\n\n", unsafeIO())); } diff --git a/grammars/silver/extension/strategyattr/StrategyExpr.sv b/grammars/silver/extension/strategyattr/StrategyExpr.sv index 8f7180c3a..ebf41a7d7 100644 --- a/grammars/silver/extension/strategyattr/StrategyExpr.sv +++ b/grammars/silver/extension/strategyattr/StrategyExpr.sv @@ -4,13 +4,15 @@ import silver:metatranslation; annotation genName::String; -- Used to generate the names of lifted strategy attributes -autocopy attribute recVars::[Pair]; -monoid attribute liftedStrategies::[Pair] with [], ++; +autocopy attribute recVarEnv::[Pair]; +inherited attribute outerAttr::Maybe; +monoid attribute liftedStrategies::[Pair] with [], ++; synthesized attribute attrRefName::Maybe; +monoid attribute freeRecVars::[String] with [], ++; monoid attribute matchesFrame::Boolean with false, ||; -functor attribute translation; +synthesized attribute translation::a; {- strategy attribute optimize = @@ -27,7 +29,7 @@ strategy attribute optimize = | all(id()) -> id() | some(fail()) -> fail() | one(fail()) -> fail() - | rec(n, s) when top.attrName.isJust -> replace n with top.attrName in s + | rec(n, s) when !containsBy(stringEq, s.freeRecVars, n.name) -> s -- These don't apply inside traversals/sequence continuations! | all(s) when !attrMatchesChild(top.env, fromMaybe(s.genName, s.attrRefName), top.frame) -> id() @@ -42,17 +44,18 @@ strategy attribute optimize = nonterminal StrategyExpr with config, grammarName, env, location, unparse, errors, frame, compiledGrammars, flowEnv, flowDefs, -- Normal expression stuff - genName, recVars, liftedStrategies, attrRefName, + genName, recVarEnv, outerAttr, liftedStrategies, attrRefName, freeRecVars, translation; flowtype StrategyExpr = - decorate {grammarName, env, config, recVars}, -- NOT frame - unparse {}, errors {decorate, frame, compiledGrammars, flowEnv}, flowDefs {decorate, frame, compiledGrammars, flowEnv}, + decorate {grammarName, config, recVarEnv, outerAttr}, -- NOT frame or env + unparse {}, errors {decorate, frame, env, compiledGrammars, flowEnv}, flowDefs {decorate, frame, env, compiledGrammars, flowEnv}, liftedStrategies {decorate}, attrRefName {decorate}, - translation {decorate, frame}; + translation {decorate, frame, env}, freeRecVars {decorate, env}; propagate errors on StrategyExpr excluding strategyRef, functorRef; -propagate flowDefs, liftedStrategies on StrategyExpr; +propagate flowDefs on StrategyExpr; +propagate freeRecVars on StrategyExpr excluding rec; aspect default production top::StrategyExpr ::= @@ -65,13 +68,15 @@ abstract production id top::StrategyExpr ::= { top.unparse = "id"; - top.translation = Silver_Expr { core:just($name{top.frame.lhsNtName}) }; + propagate liftedStrategies; + top.translation = Silver_Expr { core:just($name{top.frame.signature.outputElement.elementName}) }; } abstract production fail top::StrategyExpr ::= { top.unparse = "fail"; + propagate liftedStrategies; top.translation = Silver_Expr { core:nothing() }; } @@ -79,12 +84,14 @@ abstract production sequence top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr { top.unparse = s"(${s1.unparse} <* ${s2.unparse})"; - top.liftedStrategies <- - case s2 of - | functorRef(_) -> [] - | _ when s2.attrRefName.isJust -> [] - | _ -> [pair(s2.genName, s2)] - end; + top.liftedStrategies := + s1.liftedStrategies ++ + if s2.attrRefName.isJust + then [] + else [pair(s2.genName, s2)]; + + s1.outerAttr = nothing(); + s2.outerAttr = nothing(); local s2Name::String = fromMaybe(s2.genName, s2.attrRefName); top.translation = @@ -123,6 +130,10 @@ abstract production choice top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr { top.unparse = s"(${s1.unparse} <+ ${s2.unparse})"; + propagate liftedStrategies; + + s1.outerAttr = nothing(); + s2.outerAttr = nothing(); top.translation = Silver_Expr { core:orElse($Expr{s1.translation}, $Expr{s2.translation}) }; } @@ -132,11 +143,21 @@ abstract production allTraversal top::StrategyExpr ::= s::StrategyExpr { top.unparse = s"all(${s.unparse})"; - top.liftedStrategies <- + + top.errors <- + case s of + -- TBH this doesn't seem very useful anyway + | functorRef(_) -> [err(s.location, "Functor attributes as arguments to generic traversals are not yet supported")] + | _ -> [] + end; + + top.liftedStrategies := if s.attrRefName.isJust then [] else [pair(s.genName, s)]; + s.outerAttr = nothing(); + local sName::String = fromMaybe(s.genName, s.attrRefName); local childAccesses::[Pair] = map( @@ -158,7 +179,7 @@ top::StrategyExpr ::= s::StrategyExpr \ a::Pair -> if a.snd then - [decorate Silver_Pattern { $name{a.fst ++ "_" ++ sName} } + [decorate Silver_Pattern { core:just($name{a.fst ++ "_" ++ sName}) } with { config = top.config; env = top.env; frame = top.frame; patternVarEnv = []; }] else [], childAccesses), @@ -189,19 +210,26 @@ abstract production someTraversal top::StrategyExpr ::= s::StrategyExpr { top.unparse = s"some(${s.unparse})"; - top.liftedStrategies <- + + top.errors <- + case s of + -- TBH this doesn't seem very useful anyway + | functorRef(_) -> [err(s.location, "Functor attributes as arguments to generic traversals are not yet supported")] + | _ -> [] + end; + + top.liftedStrategies := if s.attrRefName.isJust then [] else [pair(s.genName, s)]; + s.outerAttr = nothing(); + local sName::String = fromMaybe(s.genName, s.attrRefName); local childAccesses::[Pair] = map( \ e::NamedSignatureElement -> - pair( - e.elementName, - decorate qNameAttrOccur(qName(top.location, sName), location=top.location) - with { config = top.config; grammarName = top.grammarName; env = top.env; attrFor = e.typerep; }.matchesFrame), + pair(e.elementName, attrMatchesFrame(top.env, sName, e.typerep)), top.frame.signature.inputElements); top.translation = {- if a.s.isJust || c.s.isJust @@ -238,11 +266,20 @@ top::StrategyExpr ::= s::StrategyExpr { top.unparse = s"one(${s.unparse})"; - top.liftedStrategies <- + top.errors <- + case s of + -- TBH this doesn't seem very useful anyway + | functorRef(_) -> [err(s.location, "Functor attributes as arguments to generic traversals are not yet supported")] + | _ -> [] + end; + + top.liftedStrategies := if s.attrRefName.isJust then [] else [pair(s.genName, s)]; + s.outerAttr = nothing(); + local sName::String = fromMaybe(s.genName, s.attrRefName); local childAccesses::[Pair] = map( @@ -269,7 +306,7 @@ top::StrategyExpr ::= s::StrategyExpr map( \ p::Pattern -> decorate p with { config = top.config; env = top.env; frame = top.frame; patternVarEnv = []; }, repeat(wildcPattern('_', location=top.location), i) ++ - Silver_Pattern { $name{childI ++ "_" ++ sName} } :: + Silver_Pattern { core:just($name{childI ++ "_" ++ sName}) } :: repeat(wildcPattern('_', location=top.location), length(matchingChildren) - (i + 1))), nothing(), Silver_Expr { @@ -303,23 +340,36 @@ top::StrategyExpr ::= n::Name s::StrategyExpr { top.unparse = s"rec ${n.name} -> (${s.unparse})"; + top.liftedStrategies := if top.outerAttr.isJust then [] else [pair(s.genName, s)]; + top.freeRecVars := removeBy(stringEq, n.name, s.freeRecVars); + + s.recVarEnv = pair(n.name, fromMaybe(s.genName, top.outerAttr)) :: top.recVarEnv; + s.outerAttr = top.outerAttr; + top.translation = + if top.outerAttr.isJust + then s.translation + else Silver_Expr { $name{top.frame.signature.outputElement.elementName}.$name{s.genName} }; } -- Rules abstract production rewriteRule -top::StrategyExpr ::= ty::TypeExpr ml::MRuleList +top::StrategyExpr ::= id::Name ty::TypeExpr ml::MRuleList { - top.unparse = "rule on " ++ ty.unparse ++ " of " ++ ml.unparse ++ " end"; + top.unparse = "rule on " ++ id.name ++ "::" ++ ty.unparse ++ " of " ++ ml.unparse ++ " end"; + propagate liftedStrategies; -- Pattern matching error checking (mostly) happens on what caseExpr forwards to, -- so we need to decorate one of those here. local checkExpr::Expr = - caseExpr( - [hackExprType(ty.typerep, location=top.location)], - ml.matchRuleList, - errorExpr([], location=top.location), - ty.typerep, + letp( + assignExpr(id, '::', ty, '=', errorExpr([], location=top.location), location=top.location), + caseExpr( + [hackExprType(ty.typerep, location=top.location)], + ml.matchRuleList, + errorExpr([], location=top.location), + ty.typerep, + location=top.location), location=top.location); checkExpr.env = top.env; checkExpr.flowEnv = top.flowEnv; @@ -340,13 +390,23 @@ top::StrategyExpr ::= ty::TypeExpr ml::MRuleList ml.matchRulePatternSize = 1; - top.translation = + local res::Expr = caseExpr( [Silver_Expr { $name{top.frame.signature.outputElement.elementName} }], - ml.matchRuleList, + ml.translation, Silver_Expr { core:nothing() }, nonterminalType("core:Maybe", [ty.typerep]), location=top.location); + top.translation = + if unify(ty.typerep, top.frame.signature.outputElement.typerep).failure + then Silver_Expr { core:nothing() } + else if top.frame.signature.outputElement.elementName == id.name + then res + else Silver_Expr { + let $Name{id}::$TypeExpr{ty} = $name{top.frame.signature.outputElement.elementName} + in $Expr{res} + end + }; } -- Hack dummy expr with a given type @@ -360,17 +420,34 @@ top::Expr ::= t::Type attribute matchesFrame occurs on MRuleList, MatchRule, PatternList, Pattern; propagate matchesFrame on MRuleList, MatchRule, PatternList; -attribute translation occurs on MRuleList; -propagate translation on MRuleList; +attribute translation<[AbstractMatchRule]> occurs on MRuleList; + +aspect production mRuleList_one +top::MRuleList ::= m::MatchRule +{ + top.translation = + if m.matchesFrame + then [m.translation] + else []; +} + +aspect production mRuleList_cons +top::MRuleList ::= h::MatchRule '|' t::MRuleList +{ + top.translation = + if h.matchesFrame + then h.translation :: t.translation + else t.translation; +} -attribute translation occurs on MatchRule; +attribute translation occurs on MatchRule; aspect production matchRule_c top::MatchRule ::= pt::PatternList _ e::Expr { top.translation = - matchRule_c( - pt, $2, Silver_Expr { core:just($Expr{e}) }, + matchRule( + pt.patternList, nothing(), Silver_Expr { core:just($Expr{e}) }, location=top.location); } @@ -378,8 +455,8 @@ aspect production matchRuleWhen_c top::MatchRule ::= pt::PatternList 'when' cond::Expr _ e::Expr { top.translation = - matchRuleWhen_c( - pt, 'when', cond, $4, Silver_Expr { core:just($Expr{e}) }, + matchRule( + pt.patternList, just(cond), Silver_Expr { core:just($Expr{e}) }, location=top.location); } @@ -401,12 +478,14 @@ top::StrategyExpr ::= id::QName { top.unparse = id.unparse; + -- Forwarding depends on env here, these must be computed without env + propagate liftedStrategies; top.attrRefName = just(id.name); local attrDcl::DclInfo = id.lookupAttribute.dcl; attrDcl.givenNonterminalType = error("Not actually needed"); -- Ugh environment needs refactoring forwards to - if lookupBy(stringEq, id.name, top.recVars).isJust + if lookupBy(stringEq, id.name, top.recVarEnv).isJust then recVarRef(id, genName=top.genName, location=top.location) else if !null(id.lookupAttribute.errors) then errorRef(id.lookupAttribute.errors, id, genName=top.genName, location=top.location) @@ -420,6 +499,7 @@ top::StrategyExpr ::= msg::[Message] id::Decorated QName { top.unparse = id.unparse; + propagate liftedStrategies; top.attrRefName = just(id.name); top.errors <- msg; @@ -430,7 +510,9 @@ top::StrategyExpr ::= id::Decorated QName { top.unparse = id.unparse; - top.attrRefName = lookupBy(stringEq, id.name, top.recVars); + propagate liftedStrategies; + top.attrRefName = lookupBy(stringEq, id.name, top.recVarEnv); + top.freeRecVars <- [id.name]; top.translation = Silver_Expr { $name{top.frame.signature.outputElement.elementName}.$qName{top.attrRefName.fromJust} }; } @@ -453,6 +535,7 @@ top::StrategyExpr ::= id::QNameAttrOccur | _, _ -> [err(id.location, s"Attribute ${id.name} cannot be used as a strategy")] end; + propagate liftedStrategies; top.attrRefName = just(id.name); id.attrFor = top.frame.signature.outputElement.typerep; @@ -481,7 +564,8 @@ top::StrategyExpr ::= id::QNameAttrOccur | _, _ -> [err(id.location, s"Attribute ${id.name} cannot be used as a functor")] end; - top.attrRefName = nothing(); + propagate liftedStrategies; + top.attrRefName = just(id.name); id.attrFor = top.frame.signature.outputElement.typerep; diff --git a/test/silver_features/Strategy.sv b/test/silver_features/Strategy.sv new file mode 100644 index 000000000..d788426ee --- /dev/null +++ b/test/silver_features/Strategy.sv @@ -0,0 +1,48 @@ +grammar silver_features; + +strategy attribute elimPlusZero = + all(elimPlusZero) <* + (rule on SExpr of addSExpr(e, constSExpr(0)) -> e end <+ id); + +nonterminal SExpr with elimPlusZero; + +abstract production addSExpr +top::SExpr ::= e1::SExpr e2::SExpr +{ + propagate elimPlusZero; +} +abstract production constSExpr +top::SExpr ::= i::Integer +{ + propagate elimPlusZero; +} +abstract production idSExpr +top::SExpr ::= id::String +{ + propagate elimPlusZero; +} + +nonterminal SStmt with elimPlusZero; +abstract production seqSStmt +top::SStmt ::= s1::SStmt s2::SStmt +{ + propagate elimPlusZero; +} +abstract production assignSStmt +top::SStmt ::= n::String e::SExpr +{ + propagate elimPlusZero; +} + +equalityTest( + hackUnparse(addSExpr(constSExpr(42), constSExpr(0)).elimPlusZero), + "core:just(silver_features:constSExpr(42))", + String, silver_tests); + +equalityTest( + hackUnparse( + seqSStmt( + assignSStmt("a", addSExpr(constSExpr(42), constSExpr(0))), + assignSStmt("b", addSExpr(addSExpr(idSExpr("a"), constSExpr(0)), constSExpr(0)))).elimPlusZero), + "core:just(silver_features:seqSStmt(silver_features:assignSStmt(\"a\", silver_features:constSExpr(42)), silver_features:assignSStmt(\"b\", silver_features:idSExpr(\"a\"))))", + String, silver_tests); From df6ee59befb0a8a1eb67c71fb83e5290d12c8432 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Tue, 7 Apr 2020 19:34:41 -0500 Subject: [PATCH 12/78] Escape -> Antiquote --- .../extension/silverconstruction/Terminals.sv | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/grammars/silver/extension/silverconstruction/Terminals.sv b/grammars/silver/extension/silverconstruction/Terminals.sv index 430b74162..6a0ab974d 100644 --- a/grammars/silver/extension/silverconstruction/Terminals.sv +++ b/grammars/silver/extension/silverconstruction/Terminals.sv @@ -6,13 +6,13 @@ marking terminal SilverAGDcl_t 'Silver_AGDcl' lexer classes {K marking terminal SilverProductionStmt_t 'Silver_ProductionStmt' lexer classes {KEYWORD, RESERVED}; temp_imp_ide_font font_escape color(160, 32, 240) bold italic; -lexer class Escape font=font_escape; +lexer class Antiquote font=font_escape; -terminal EscapeExpr_t '$Expr' lexer classes {Escape}; -terminal EscapeTypeExpr_t '$TypeExpr' lexer classes {Escape}; -terminal EscapePattern_t '$Pattern' lexer classes {Escape}; -terminal EscapeQName_t '$QName' lexer classes {Escape}; -terminal EscapeQNameAttrOccur_t '$QNameAttrOccur' lexer classes {Escape}; -terminal EscapeName_t '$Name' lexer classes {Escape}; -terminal Escape_qName_t '$qName' lexer classes {Escape}; -terminal Escape_name_t '$name' lexer classes {Escape}; +terminal AntiquoteExpr_t '$Expr' lexer classes {Antiquote}; +terminal AntiquoteTypeExpr_t '$TypeExpr' lexer classes {Antiquote}; +terminal AntiquotePattern_t '$Pattern' lexer classes {Antiquote}; +terminal AntiquoteQName_t '$QName' lexer classes {Antiquote}; +terminal AntiquoteQNameAttrOccur_t '$QNameAttrOccur' lexer classes {Antiquote}; +terminal AntiquoteName_t '$Name' lexer classes {Antiquote}; +terminal Antiquote_qName_t '$qName' lexer classes {Antiquote}; +terminal Antiquote_name_t '$name' lexer classes {Antiquote}; From 441e1f8176e421c4722ea2039b3e60ca53257788 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Tue, 7 Apr 2020 20:21:39 -0500 Subject: [PATCH 13/78] Implement quotation/antiquotation for StrategyExpr --- .../extension/strategyattr/Construction.sv | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 grammars/silver/extension/strategyattr/Construction.sv diff --git a/grammars/silver/extension/strategyattr/Construction.sv b/grammars/silver/extension/strategyattr/Construction.sv new file mode 100644 index 000000000..c1ff23c4d --- /dev/null +++ b/grammars/silver/extension/strategyattr/Construction.sv @@ -0,0 +1,36 @@ +grammar silver:extension:strategyattr; + +import silver:reflect; +import silver:metatranslation; + +terminal SilverStrategyExpr_t 'Silver_StrategyExpr' lexer classes {KEYWORD, RESERVED}; +terminal AntiquoteStrategyExpr_t '$StrategyExpr' lexer classes {Antiquote, Strategy}; + +concrete production quoteStrategyExpr +top::Expr ::= 'Silver_StrategyExpr' genName::Name '{' cst::StrategyExpr_c '}' +{ + top.unparse = s"Silver_StrategyExpr {${cst.unparse}}"; + cst.givenGenName = genName.name ++ "_" ++ toString(genInt()); + forwards to translate(top.location, reflect(cst.ast)); +} + +concrete production antiquoteStrategyExpr_c +top::StrategyExpr_c ::= '$StrategyExpr' '{' e::Expr '}' +{ + top.unparse = s"$$StrategyExpr{${e.unparse}}"; + top.ast = antiquoteStrategyExpr(e, genName=top.givenGenName, location=top.location); +} + +abstract production antiquoteStrategyExpr +top::StrategyExpr ::= e::Expr +{ + top.unparse = s"$$StrategyExpr{${e.unparse}}"; + forwards to error("no forward"); +} + +aspect production nonterminalAST +top::AST ::= prodName::String children::ASTs annotations::NamedASTs +{ + directAntiquoteProductions <- + ["silver:extension:strategyattr:antiquoteStrategyExpr"]; +} From 187365bbfdd6c38dd498486baeba08a8ff0997ac Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Tue, 7 Apr 2020 20:23:40 -0500 Subject: [PATCH 14/78] Implement try strategy utility --- .../extension/strategyattr/ConcreteSyntax.sv | 8 +++++++- .../silver/extension/strategyattr/Project.sv | 1 + .../extension/strategyattr/StrategyUtils.sv | 15 +++++--------- .../extension/strategyattr/Terminals.sv | 20 ++++++++++--------- test/silver_features/Strategy.sv | 2 +- 5 files changed, 25 insertions(+), 21 deletions(-) diff --git a/grammars/silver/extension/strategyattr/ConcreteSyntax.sv b/grammars/silver/extension/strategyattr/ConcreteSyntax.sv index e516c46db..35ccff942 100644 --- a/grammars/silver/extension/strategyattr/ConcreteSyntax.sv +++ b/grammars/silver/extension/strategyattr/ConcreteSyntax.sv @@ -10,7 +10,7 @@ top::AGDcl ::= 'strategy' 'attribute' a::Name '=' e::StrategyExpr_c ';' forwards to strategyAttributeDcl(a, [], e.ast, location=top.location); } -nonterminal StrategyExpr_c with location, givenGenName, unparse, ast; +closed nonterminal StrategyExpr_c with location, givenGenName, unparse, ast; concrete productions top::StrategyExpr_c | 'id' @@ -82,6 +82,12 @@ concrete productions top::StrategyExpr_c top.ast = s.ast; s.givenGenName = top.givenGenName; } +| 'try' '(' s::StrategyExpr_c ')' +{ + top.unparse = s"try(${s.unparse})"; + top.ast = try(s.ast, genName=top.givenGenName, location=top.location); + s.givenGenName = top.givenGenName ++ "_try"; +} nonterminal StrategyQName with location, ast; concrete productions top::StrategyQName diff --git a/grammars/silver/extension/strategyattr/Project.sv b/grammars/silver/extension/strategyattr/Project.sv index 286d34a54..a783a32e3 100644 --- a/grammars/silver/extension/strategyattr/Project.sv +++ b/grammars/silver/extension/strategyattr/Project.sv @@ -8,6 +8,7 @@ imports silver:extension:autoattr; imports silver:extension:patternmatching; imports silver:extension:list; --imports silver:extension:rewriting; +imports silver:extension:silverconstruction; imports silver:modification:let_fix; imports silver:modification:lambda_fn; diff --git a/grammars/silver/extension/strategyattr/StrategyUtils.sv b/grammars/silver/extension/strategyattr/StrategyUtils.sv index d148b374b..48e524796 100644 --- a/grammars/silver/extension/strategyattr/StrategyUtils.sv +++ b/grammars/silver/extension/strategyattr/StrategyUtils.sv @@ -1,20 +1,15 @@ grammar silver:extension:strategyattr; - -{- -- Utilities -abstract production recStrategy -top::StrategyExpr ::= ctr::(StrategyExpr ::= StrategyExpr) -{ - forwards to ctr(top); -} - abstract production try top::StrategyExpr ::= s::StrategyExpr { - forwards to s <+ id(); + forwards to + Silver_StrategyExpr try { + $StrategyExpr{s} <+ id + }; } - +{- abstract production repeat top::StrategyExpr ::= s::StrategyExpr { diff --git a/grammars/silver/extension/strategyattr/Terminals.sv b/grammars/silver/extension/strategyattr/Terminals.sv index 72bb9725a..7f1ef1f78 100644 --- a/grammars/silver/extension/strategyattr/Terminals.sv +++ b/grammars/silver/extension/strategyattr/Terminals.sv @@ -1,18 +1,20 @@ grammar silver:extension:strategyattr; -terminal Strategy_kwd 'strategy' lexer classes {KEYWORD,RESERVED}; +terminal Strategy_kwd 'strategy' lexer classes {KEYWORD, RESERVED}; terminal Sequence_t '<*' precedence = 12, association = left; -- Same as * terminal Choice_t '<+' precedence = 11, association = left; -- Same as + -lexer class STRATEGY_COMB dominates StrategyName_t; +lexer class Strategy dominates StrategyName_t; -terminal Id_t 'id' lexer classes {KEYWORD, STRATEGY_COMB}; -terminal Fail_t 'fail' lexer classes {KEYWORD, STRATEGY_COMB}; -terminal All_t 'all' lexer classes {KEYWORD, STRATEGY_COMB}; -terminal Some_t 'some' lexer classes {KEYWORD, STRATEGY_COMB}; -terminal One_t 'one' lexer classes {KEYWORD, STRATEGY_COMB}; -terminal Rule_t 'rule' lexer classes {KEYWORD, STRATEGY_COMB}; -terminal Rec_t 'rec' lexer classes {KEYWORD, STRATEGY_COMB}; +terminal Id_t 'id' lexer classes {KEYWORD, Strategy}; +terminal Fail_t 'fail' lexer classes {KEYWORD, Strategy}; +terminal All_t 'all' lexer classes {KEYWORD, Strategy}; +terminal Some_t 'some' lexer classes {KEYWORD, Strategy}; +terminal One_t 'one' lexer classes {KEYWORD, Strategy}; +terminal Rule_t 'rule' lexer classes {KEYWORD, Strategy}; +terminal Rec_t 'rec' lexer classes {KEYWORD, Strategy}; + +terminal Try_t 'try' lexer classes {KEYWORD, Strategy}; terminal StrategyName_t /[a-z][A-Za-z0-9\_]*/ lexer classes {IDENTIFIER}; diff --git a/test/silver_features/Strategy.sv b/test/silver_features/Strategy.sv index d788426ee..4d5f94bd9 100644 --- a/test/silver_features/Strategy.sv +++ b/test/silver_features/Strategy.sv @@ -2,7 +2,7 @@ grammar silver_features; strategy attribute elimPlusZero = all(elimPlusZero) <* - (rule on SExpr of addSExpr(e, constSExpr(0)) -> e end <+ id); + try(rule on SExpr of addSExpr(e, constSExpr(0)) -> e end); nonterminal SExpr with elimPlusZero; From a759e3a251ddc1be6c7f05caafdd7a4d4615d781 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Wed, 8 Apr 2020 12:27:24 -0500 Subject: [PATCH 15/78] More utilities --- .../extension/strategyattr/ConcreteSyntax.sv | 30 ++++++++++++++++ .../extension/strategyattr/StrategyUtils.sv | 35 +++++++++++++------ .../extension/strategyattr/Terminals.sv | 7 +++- 3 files changed, 61 insertions(+), 11 deletions(-) diff --git a/grammars/silver/extension/strategyattr/ConcreteSyntax.sv b/grammars/silver/extension/strategyattr/ConcreteSyntax.sv index 35ccff942..5d17895af 100644 --- a/grammars/silver/extension/strategyattr/ConcreteSyntax.sv +++ b/grammars/silver/extension/strategyattr/ConcreteSyntax.sv @@ -88,6 +88,36 @@ concrete productions top::StrategyExpr_c top.ast = try(s.ast, genName=top.givenGenName, location=top.location); s.givenGenName = top.givenGenName ++ "_try"; } +| 'repeat' '(' s::StrategyExpr_c ')' +{ + top.unparse = s"repeat(${s.unparse})"; + top.ast = repeatS(s.ast, genName=top.givenGenName, location=top.location); + s.givenGenName = top.givenGenName ++ "_repeat"; +} +| 'bottomUp' '(' s::StrategyExpr_c ')' +{ + top.unparse = s"bottomUp(${s.unparse})"; + top.ast = bottomUp(s.ast, genName=top.givenGenName, location=top.location); + s.givenGenName = top.givenGenName ++ "_bottomUp"; +} +| 'topDown' '(' s::StrategyExpr_c ')' +{ + top.unparse = s"topDown(${s.unparse})"; + top.ast = topDown(s.ast, genName=top.givenGenName, location=top.location); + s.givenGenName = top.givenGenName ++ "_topDown"; +} +| 'onceBottomUp' '(' s::StrategyExpr_c ')' +{ + top.unparse = s"onceBottomUp(${s.unparse})"; + top.ast = onceBottomUp(s.ast, genName=top.givenGenName, location=top.location); + s.givenGenName = top.givenGenName ++ "_onceBottomUp"; +} +| 'onceTopDown' '(' s::StrategyExpr_c ')' +{ + top.unparse = s"onceTopDown(${s.unparse})"; + top.ast = onceTopDown(s.ast, genName=top.givenGenName, location=top.location); + s.givenGenName = top.givenGenName ++ "_onceTopDown"; +} nonterminal StrategyQName with location, ast; concrete productions top::StrategyQName diff --git a/grammars/silver/extension/strategyattr/StrategyUtils.sv b/grammars/silver/extension/strategyattr/StrategyUtils.sv index 48e524796..83788e89f 100644 --- a/grammars/silver/extension/strategyattr/StrategyUtils.sv +++ b/grammars/silver/extension/strategyattr/StrategyUtils.sv @@ -9,43 +9,58 @@ top::StrategyExpr ::= s::StrategyExpr $StrategyExpr{s} <+ id }; } -{- -abstract production repeat + +abstract production repeatS top::StrategyExpr ::= s::StrategyExpr { - forwards to try(s <* repeat(s)); + forwards to + Silver_StrategyExpr repeat { + rec res -> try($StrategyExpr{s} <* res) + }; } - +{- abstract production reduce top::StrategyExpr ::= s::StrategyExpr { forwards to repeat(rec(\ x::StrategyExpr -> some(x) <+ s)); } - +-} abstract production bottomUp top::StrategyExpr ::= s::StrategyExpr { - forwards to all(bottomUp(s)) <* s; + forwards to + Silver_StrategyExpr bottomUp { + rec res -> all(res) <* $StrategyExpr{s} + }; } abstract production topDown top::StrategyExpr ::= s::StrategyExpr { - forwards to s <* all(topDown(s)); + forwards to + Silver_StrategyExpr topDown { + rec res -> $StrategyExpr{s} <* all(res) + }; } abstract production onceBottomUp top::StrategyExpr ::= s::StrategyExpr { - forwards to one(onceBottomUp(s)) <+ s; + forwards to + Silver_StrategyExpr onceBottomUp { + rec res -> one(res) <+ $StrategyExpr{s} + }; } abstract production onceTopDown top::StrategyExpr ::= s::StrategyExpr { - forwards to s <+ one(onceTopDown(s)); + forwards to + Silver_StrategyExpr onceTopDown { + rec res -> $StrategyExpr{s} <+ one(res) + }; } - +{- abstract production innermost top::StrategyExpr ::= s::StrategyExpr { diff --git a/grammars/silver/extension/strategyattr/Terminals.sv b/grammars/silver/extension/strategyattr/Terminals.sv index 7f1ef1f78..7bd91576b 100644 --- a/grammars/silver/extension/strategyattr/Terminals.sv +++ b/grammars/silver/extension/strategyattr/Terminals.sv @@ -15,6 +15,11 @@ terminal One_t 'one' lexer classes {KEYWORD, Strategy}; terminal Rule_t 'rule' lexer classes {KEYWORD, Strategy}; terminal Rec_t 'rec' lexer classes {KEYWORD, Strategy}; -terminal Try_t 'try' lexer classes {KEYWORD, Strategy}; +terminal Try_t 'try' lexer classes {KEYWORD, Strategy}; +terminal Repeat_t 'repeat' lexer classes {KEYWORD, Strategy}; +terminal BottomUp_t 'bottomUp' lexer classes {KEYWORD, Strategy}; +terminal TopDown_t 'topDown' lexer classes {KEYWORD, Strategy}; +terminal OnceBottomUp_t 'onceBottomUp' lexer classes {KEYWORD, Strategy}; +terminal OnceTopDown_t 'onceTopDown' lexer classes {KEYWORD, Strategy}; terminal StrategyName_t /[a-z][A-Za-z0-9\_]*/ lexer classes {IDENTIFIER}; From ef3c05a7328556742d5880379bedd4c5b14e5206 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Wed, 8 Apr 2020 12:46:04 -0500 Subject: [PATCH 16/78] reduce, innermost, outermost utilities --- .../extension/strategyattr/ConcreteSyntax.sv | 18 +++++++++++++++ .../extension/strategyattr/StrategyUtils.sv | 22 +++++++++++++------ .../extension/strategyattr/Terminals.sv | 3 +++ 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/grammars/silver/extension/strategyattr/ConcreteSyntax.sv b/grammars/silver/extension/strategyattr/ConcreteSyntax.sv index 5d17895af..e78720a30 100644 --- a/grammars/silver/extension/strategyattr/ConcreteSyntax.sv +++ b/grammars/silver/extension/strategyattr/ConcreteSyntax.sv @@ -94,6 +94,12 @@ concrete productions top::StrategyExpr_c top.ast = repeatS(s.ast, genName=top.givenGenName, location=top.location); s.givenGenName = top.givenGenName ++ "_repeat"; } +| 'reduce' '(' s::StrategyExpr_c ')' +{ + top.unparse = s"reduce(${s.unparse})"; + top.ast = reduce(s.ast, genName=top.givenGenName, location=top.location); + s.givenGenName = top.givenGenName ++ "_reduce"; +} | 'bottomUp' '(' s::StrategyExpr_c ')' { top.unparse = s"bottomUp(${s.unparse})"; @@ -118,6 +124,18 @@ concrete productions top::StrategyExpr_c top.ast = onceTopDown(s.ast, genName=top.givenGenName, location=top.location); s.givenGenName = top.givenGenName ++ "_onceTopDown"; } +| 'innermost' '(' s::StrategyExpr_c ')' +{ + top.unparse = s"innermost(${s.unparse})"; + top.ast = innermost(s.ast, genName=top.givenGenName, location=top.location); + s.givenGenName = top.givenGenName ++ "_innermost"; +} +| 'outermost' '(' s::StrategyExpr_c ')' +{ + top.unparse = s"outermost(${s.unparse})"; + top.ast = outermost(s.ast, genName=top.givenGenName, location=top.location); + s.givenGenName = top.givenGenName ++ "_outermost"; +} nonterminal StrategyQName with location, ast; concrete productions top::StrategyQName diff --git a/grammars/silver/extension/strategyattr/StrategyUtils.sv b/grammars/silver/extension/strategyattr/StrategyUtils.sv index 83788e89f..b28637374 100644 --- a/grammars/silver/extension/strategyattr/StrategyUtils.sv +++ b/grammars/silver/extension/strategyattr/StrategyUtils.sv @@ -18,13 +18,16 @@ top::StrategyExpr ::= s::StrategyExpr rec res -> try($StrategyExpr{s} <* res) }; } -{- + abstract production reduce top::StrategyExpr ::= s::StrategyExpr { - forwards to repeat(rec(\ x::StrategyExpr -> some(x) <+ s)); + forwards to + Silver_StrategyExpr reduce { + repeat(rec res -> some(res) <+ $StrategyExpr{s}) + }; } --} + abstract production bottomUp top::StrategyExpr ::= s::StrategyExpr { @@ -60,16 +63,21 @@ top::StrategyExpr ::= s::StrategyExpr rec res -> $StrategyExpr{s} <+ one(res) }; } -{- + abstract production innermost top::StrategyExpr ::= s::StrategyExpr { - forwards to bottomUp(try(s <* innermost(s))); + forwards to + Silver_StrategyExpr innermost { + rec res -> bottomUp(try($StrategyExpr{s} <* res)) + }; } abstract production outermost top::StrategyExpr ::= s::StrategyExpr { - forwards to topDown(try(s <* outermost(s))); + forwards to + Silver_StrategyExpr outermost { + rec res -> topDown(try($StrategyExpr{s} <* res)) + }; } --} \ No newline at end of file diff --git a/grammars/silver/extension/strategyattr/Terminals.sv b/grammars/silver/extension/strategyattr/Terminals.sv index 7bd91576b..e23185462 100644 --- a/grammars/silver/extension/strategyattr/Terminals.sv +++ b/grammars/silver/extension/strategyattr/Terminals.sv @@ -17,9 +17,12 @@ terminal Rec_t 'rec' lexer classes {KEYWORD, Strategy}; terminal Try_t 'try' lexer classes {KEYWORD, Strategy}; terminal Repeat_t 'repeat' lexer classes {KEYWORD, Strategy}; +terminal Reduce_t 'reduce' lexer classes {KEYWORD, Strategy}; terminal BottomUp_t 'bottomUp' lexer classes {KEYWORD, Strategy}; terminal TopDown_t 'topDown' lexer classes {KEYWORD, Strategy}; terminal OnceBottomUp_t 'onceBottomUp' lexer classes {KEYWORD, Strategy}; terminal OnceTopDown_t 'onceTopDown' lexer classes {KEYWORD, Strategy}; +terminal Innermost_t 'innermost' lexer classes {KEYWORD, Strategy}; +terminal Outermost_t 'outermost' lexer classes {KEYWORD, Strategy}; terminal StrategyName_t /[a-z][A-Za-z0-9\_]*/ lexer classes {IDENTIFIER}; From a7a5e173bffe85cb92ec86df632b72b5ead7911f Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Wed, 8 Apr 2020 15:32:24 -0500 Subject: [PATCH 17/78] Better generated strategy names --- .../extension/strategyattr/ConcreteSyntax.sv | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/grammars/silver/extension/strategyattr/ConcreteSyntax.sv b/grammars/silver/extension/strategyattr/ConcreteSyntax.sv index e78720a30..17ddb7662 100644 --- a/grammars/silver/extension/strategyattr/ConcreteSyntax.sv +++ b/grammars/silver/extension/strategyattr/ConcreteSyntax.sv @@ -41,19 +41,19 @@ concrete productions top::StrategyExpr_c { top.unparse = s"all(${s.unparse})"; top.ast = allTraversal(s.ast, genName=top.givenGenName, location=top.location); - s.givenGenName = top.givenGenName ++ "_item"; + s.givenGenName = top.givenGenName ++ "_all_arg"; } | 'some' '(' s::StrategyExpr_c ')' { top.unparse = s"some(${s.unparse})"; top.ast = someTraversal(s.ast, genName=top.givenGenName, location=top.location); - s.givenGenName = top.givenGenName ++ "_item"; + s.givenGenName = top.givenGenName ++ "_some_arg"; } | 'one' '(' s::StrategyExpr_c ')' { top.unparse = s"one(${s.unparse})"; top.ast = oneTraversal(s.ast, genName=top.givenGenName, location=top.location); - s.givenGenName = top.givenGenName ++ "_item"; + s.givenGenName = top.givenGenName ++ "_one_arg"; } | 'rec' n::Name Arrow_t s::StrategyExpr_c { @@ -86,55 +86,55 @@ concrete productions top::StrategyExpr_c { top.unparse = s"try(${s.unparse})"; top.ast = try(s.ast, genName=top.givenGenName, location=top.location); - s.givenGenName = top.givenGenName ++ "_try"; + s.givenGenName = top.givenGenName ++ "_try_arg"; } | 'repeat' '(' s::StrategyExpr_c ')' { top.unparse = s"repeat(${s.unparse})"; top.ast = repeatS(s.ast, genName=top.givenGenName, location=top.location); - s.givenGenName = top.givenGenName ++ "_repeat"; + s.givenGenName = top.givenGenName ++ "_repeat_arg"; } | 'reduce' '(' s::StrategyExpr_c ')' { top.unparse = s"reduce(${s.unparse})"; top.ast = reduce(s.ast, genName=top.givenGenName, location=top.location); - s.givenGenName = top.givenGenName ++ "_reduce"; + s.givenGenName = top.givenGenName ++ "_reduce_arg"; } | 'bottomUp' '(' s::StrategyExpr_c ')' { top.unparse = s"bottomUp(${s.unparse})"; top.ast = bottomUp(s.ast, genName=top.givenGenName, location=top.location); - s.givenGenName = top.givenGenName ++ "_bottomUp"; + s.givenGenName = top.givenGenName ++ "_bottomUp_arg"; } | 'topDown' '(' s::StrategyExpr_c ')' { top.unparse = s"topDown(${s.unparse})"; top.ast = topDown(s.ast, genName=top.givenGenName, location=top.location); - s.givenGenName = top.givenGenName ++ "_topDown"; + s.givenGenName = top.givenGenName ++ "_topDown_arg"; } | 'onceBottomUp' '(' s::StrategyExpr_c ')' { top.unparse = s"onceBottomUp(${s.unparse})"; top.ast = onceBottomUp(s.ast, genName=top.givenGenName, location=top.location); - s.givenGenName = top.givenGenName ++ "_onceBottomUp"; + s.givenGenName = top.givenGenName ++ "_onceBottomUp_arg"; } | 'onceTopDown' '(' s::StrategyExpr_c ')' { top.unparse = s"onceTopDown(${s.unparse})"; top.ast = onceTopDown(s.ast, genName=top.givenGenName, location=top.location); - s.givenGenName = top.givenGenName ++ "_onceTopDown"; + s.givenGenName = top.givenGenName ++ "_onceTopDown_arg"; } | 'innermost' '(' s::StrategyExpr_c ')' { top.unparse = s"innermost(${s.unparse})"; top.ast = innermost(s.ast, genName=top.givenGenName, location=top.location); - s.givenGenName = top.givenGenName ++ "_innermost"; + s.givenGenName = top.givenGenName ++ "_innermost_arg"; } | 'outermost' '(' s::StrategyExpr_c ')' { top.unparse = s"outermost(${s.unparse})"; top.ast = outermost(s.ast, genName=top.givenGenName, location=top.location); - s.givenGenName = top.givenGenName ++ "_outermost"; + s.givenGenName = top.givenGenName ++ "_outermost_arg"; } nonterminal StrategyQName with location, ast; From 0487fcf89e297e6c915b5411797d830fe75d78df Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Wed, 8 Apr 2020 15:34:20 -0500 Subject: [PATCH 18/78] Bug fixes, use mondic bind in sequence translation, test for bottomUp --- .../silver/extension/strategyattr/Strategy.sv | 18 +++-- .../extension/strategyattr/StrategyExpr.sv | 68 +++++++++++-------- test/silver_features/Strategy.sv | 10 ++- 3 files changed, 60 insertions(+), 36 deletions(-) diff --git a/grammars/silver/extension/strategyattr/Strategy.sv b/grammars/silver/extension/strategyattr/Strategy.sv index be98ee896..e941d602f 100644 --- a/grammars/silver/extension/strategyattr/Strategy.sv +++ b/grammars/silver/extension/strategyattr/Strategy.sv @@ -11,13 +11,18 @@ top::AGDcl ::= a::Name recVarEnv::[Pair] e::StrategyExpr production attribute fName :: String; fName = top.grammarName ++ ":" ++ a.name; - -- Define these directly to avoid circular dependencies + -- Define these directly to avoid circular dependencies, + -- since the forward contributes to the env. propagate errors, moduleNames; top.errors <- if length(getAttrDclAll(fName, top.env)) > 1 then [err(a.location, "Attribute '" ++ fName ++ "' is already bound.")] else []; + top.errors <- + if null(getValueDcl("core:monad:bindMaybe", top.env)) + then [err(top.location, "Strategy attributes require import of core:monad")] + else []; -- Frame doesn't really matter, since we will re-check any expressions occuring in e when propagated. -- Need all this to construct a bogus frame... @@ -30,7 +35,7 @@ top::AGDcl ::= a::Name recVarEnv::[Pair] e::StrategyExpr e.recVarEnv = recVarEnv; e.outerAttr = just(a.name); - forwards to + forwards to-- unsafeTrace( foldr( appendAGDcl(_, _, location=top.location), defsAGDcl( @@ -38,12 +43,13 @@ top::AGDcl ::= a::Name recVarEnv::[Pair] e::StrategyExpr defaultEnvItem( strategyDcl( top.grammarName, a.location, fName, freshTyVar(), - !null(e.errors), map(fst, e.liftedStrategies), recVarEnv, e)))], + !null(top.errors), map(fst, e.liftedStrategies), recVarEnv, e)))], location=top.location), map( \ d::Pair -> strategyAttributeDcl(name(d.fst, top.location), d.snd.recVarEnv, new(d.snd), location=top.location), - e.liftedStrategies)); + e.liftedStrategies));--, + --print(a.name ++ " = " ++ e.unparse ++ "; lifted " ++ implode(", ", map(fst, e.liftedStrategies)) ++ "\n\n", unsafeIO())); } abstract production strategyAttributionDcl @@ -99,7 +105,7 @@ top::ProductionStmt ::= attr::Decorated QName forwards to if attr.lookupAttribute.dcl.containsErrors then errorProductionStmt([], location=top.location) - else --unsafeTrace( + else-- unsafeTrace( foldr( productionStmtAppend(_, _, location=top.location), attributeDef( @@ -113,5 +119,5 @@ top::ProductionStmt ::= attr::Decorated QName map( \ n::String -> propagateOneAttr(qName(top.location, n), location=top.location), attr.lookupAttribute.dcl.liftedStrategyNames));--, - --print(attr.name ++ " on " ++ top.frame.fullName ++ ": " ++ e.translation.unparse ++ "\n\n", unsafeIO())); + --print(attr.name ++ " on " ++ top.frame.fullName ++ " = " ++ e.translation.unparse ++ ";\n\n", unsafeIO())); } diff --git a/grammars/silver/extension/strategyattr/StrategyExpr.sv b/grammars/silver/extension/strategyattr/StrategyExpr.sv index ebf41a7d7..dee0f2c4e 100644 --- a/grammars/silver/extension/strategyattr/StrategyExpr.sv +++ b/grammars/silver/extension/strategyattr/StrategyExpr.sv @@ -109,19 +109,17 @@ top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr } | _, functorRef(attr2) -> Silver_Expr { - -- TODO: This could be a monadic bind, but bindMaybe isn't in core - case $Expr{s1.translation} of - | just(res) -> decorate res with {}.$QNameAttrOccur{attr2} -- TODO: Decorate with all inh attributes - | nothing() -> nothing() - end + core:monad:bindMaybe( + $Expr{s1.translation}, + \ res::$TypeExpr{typerepTypeExpr(top.frame.signature.outputElement.typerep, location=top.location)} -> + decorate res with {}.$QNameAttrOccur{attr2}) -- TODO: Decorate with all inh attributes } | _, _ -> Silver_Expr { - -- TODO: This could be a monadic bind, but bindMaybe isn't in core - case $Expr{s1.translation} of - | just(res) -> decorate res with {}.$name{s2Name} -- TODO: Decorate with all inh attributes - | nothing() -> nothing() - end + core:monad:bindMaybe( + $Expr{s1.translation}, + \ res::$TypeExpr{typerepTypeExpr(top.frame.signature.outputElement.typerep, location=top.location)} -> + decorate res with {}.$name{s2Name}) -- TODO: Decorate with all inh attributes } end; } @@ -159,16 +157,19 @@ top::StrategyExpr ::= s::StrategyExpr s.outerAttr = nothing(); local sName::String = fromMaybe(s.genName, s.attrRefName); + local sBaseName::String = last(explode(":", sName)); local childAccesses::[Pair] = map( \ e::NamedSignatureElement -> pair(e.elementName, attrMatchesFrame(top.env, sName, e.typerep)), top.frame.signature.inputElements); top.translation = - {- case a.s, c.s of - | just(a_s), just(c_s) -> just(prod(a_s, b, c_s)) - | _, _ -> nothing() - end -} + {- Translation of prod::(Foo ::= a::Foo b::Integer c::Bar): + case a.s, c.s of + | just(a_s), just(c_s) -> just(prod(a_s, b, c_s)) + | _, _ -> nothing() + end + Could also be implemented as chained monadic binds. Maybe more efficient this way? -} caseExpr( flatMap( \ a::Pair -> @@ -179,7 +180,7 @@ top::StrategyExpr ::= s::StrategyExpr \ a::Pair -> if a.snd then - [decorate Silver_Pattern { core:just($name{a.fst ++ "_" ++ sName}) } + [decorate Silver_Pattern { core:just($name{a.fst ++ "_" ++ sBaseName}) } with { config = top.config; env = top.env; frame = top.frame; patternVarEnv = []; }] else [], childAccesses), @@ -193,7 +194,7 @@ top::StrategyExpr ::= s::StrategyExpr map( \ a::Pair -> if a.snd - then Silver_Expr { $name{a.fst ++ "_" ++ sName} } + then Silver_Expr { $name{a.fst ++ "_" ++ sBaseName} } else Silver_Expr { $name{a.fst} }, childAccesses), map( @@ -232,9 +233,11 @@ top::StrategyExpr ::= s::StrategyExpr pair(e.elementName, attrMatchesFrame(top.env, sName, e.typerep)), top.frame.signature.inputElements); top.translation = - {- if a.s.isJust || c.s.isJust - then just(prod(fromMaybe(a, a.s), b, fromMaybe(c, c.s))) - else nothing() -} + {- Translation of prod::(Foo ::= a::Foo b::Integer c::Bar): + if a.s.isJust || c.s.isJust + then just(prod(fromMaybe(a, a.s), b, fromMaybe(c, c.s))) + else nothing() + Not sure of a clean way to do this with monads -} Silver_Expr { if $Expr{ foldr( @@ -281,6 +284,7 @@ top::StrategyExpr ::= s::StrategyExpr s.outerAttr = nothing(); local sName::String = fromMaybe(s.genName, s.attrRefName); + local sBaseName::String = last(explode(":", sName)); local childAccesses::[Pair] = map( \ e::NamedSignatureElement -> @@ -288,11 +292,16 @@ top::StrategyExpr ::= s::StrategyExpr top.frame.signature.inputElements); local matchingChildren::[String] = map(fst, filter(snd, childAccesses)); top.translation = - {- case a.s, c.s of - | just(a_s), _ -> just(prod(a_s, b, c)) - | _, just(c_s) -> just(prod(a, b, c_s)) - | _, _ -> nothing() - end -} + {- Translation of prod::(Foo ::= a::Foo b::Integer c::Bar): + case a.s, c.s of + | just(a_s), _ -> just(prod(a_s, b, c)) + | _, just(c_s) -> just(prod(a, b, c_s)) + | _, _ -> nothing() + end + Could also be implemented as + orElse( + bindMaybe(a.s, \ a_s::Foo -> returnMaybe(prod(a_s, b, c))), + bindMaybe(c.s, \ c_s::Bar -> returnMaybe(prod(a, b, c_s))) -} caseExpr( map( \ a::String -> Silver_Expr { $name{a}.$name{sName} }, @@ -306,7 +315,7 @@ top::StrategyExpr ::= s::StrategyExpr map( \ p::Pattern -> decorate p with { config = top.config; env = top.env; frame = top.frame; patternVarEnv = []; }, repeat(wildcPattern('_', location=top.location), i) ++ - Silver_Pattern { core:just($name{childI ++ "_" ++ sName}) } :: + Silver_Pattern { core:just($name{childI ++ "_" ++ sBaseName}) } :: repeat(wildcPattern('_', location=top.location), length(matchingChildren) - (i + 1))), nothing(), Silver_Expr { @@ -318,7 +327,7 @@ top::StrategyExpr ::= s::StrategyExpr map( \ a::Pair -> Silver_Expr { $name{a.fst} }, take(childIndex, childAccesses)) ++ - Silver_Expr { $name{childI ++ "_" ++ sName} } :: + Silver_Expr { $name{childI ++ "_" ++ sBaseName} } :: map( \ a::Pair -> Silver_Expr { $name{a.fst} }, drop(childIndex + 1, childAccesses)), @@ -340,7 +349,10 @@ top::StrategyExpr ::= n::Name s::StrategyExpr { top.unparse = s"rec ${n.name} -> (${s.unparse})"; - top.liftedStrategies := if top.outerAttr.isJust then [] else [pair(s.genName, s)]; + top.liftedStrategies := + if top.outerAttr.isJust + then s.liftedStrategies + else [pair(s.genName, s)]; top.freeRecVars := removeBy(stringEq, n.name, s.freeRecVars); s.recVarEnv = pair(n.name, fromMaybe(s.genName, top.outerAttr)) :: top.recVarEnv; @@ -480,7 +492,7 @@ top::StrategyExpr ::= id::QName -- Forwarding depends on env here, these must be computed without env propagate liftedStrategies; - top.attrRefName = just(id.name); + top.attrRefName = just(fromMaybe(id.name, lookupBy(stringEq, id.name, top.recVarEnv))); local attrDcl::DclInfo = id.lookupAttribute.dcl; attrDcl.givenNonterminalType = error("Not actually needed"); -- Ugh environment needs refactoring diff --git a/test/silver_features/Strategy.sv b/test/silver_features/Strategy.sv index 4d5f94bd9..2d793a71b 100644 --- a/test/silver_features/Strategy.sv +++ b/test/silver_features/Strategy.sv @@ -1,8 +1,9 @@ grammar silver_features; +import core:monad; + strategy attribute elimPlusZero = - all(elimPlusZero) <* - try(rule on SExpr of addSExpr(e, constSExpr(0)) -> e end); + bottomUp(try(rule on SExpr of addSExpr(e, constSExpr(0)) -> e end)); nonterminal SExpr with elimPlusZero; @@ -39,6 +40,11 @@ equalityTest( "core:just(silver_features:constSExpr(42))", String, silver_tests); +equalityTest( + hackUnparse(addSExpr(addSExpr(constSExpr(42), constSExpr(0)), constSExpr(0)).elimPlusZero), + "core:just(silver_features:constSExpr(42))", + String, silver_tests); + equalityTest( hackUnparse( seqSStmt( From 32798c406dc04216aaf5a7948ea4b3a4e4d75a3e Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Wed, 8 Apr 2020 17:31:38 -0500 Subject: [PATCH 19/78] More bug fixes --- .../extension/strategyattr/StrategyExpr.sv | 77 ++++++++++--------- 1 file changed, 42 insertions(+), 35 deletions(-) diff --git a/grammars/silver/extension/strategyattr/StrategyExpr.sv b/grammars/silver/extension/strategyattr/StrategyExpr.sv index dee0f2c4e..71542dbd4 100644 --- a/grammars/silver/extension/strategyattr/StrategyExpr.sv +++ b/grammars/silver/extension/strategyattr/StrategyExpr.sv @@ -8,12 +8,10 @@ autocopy attribute recVarEnv::[Pair]; inherited attribute outerAttr::Maybe; monoid attribute liftedStrategies::[Pair] with [], ++; synthesized attribute attrRefName::Maybe; -monoid attribute freeRecVars::[String] with [], ++; - monoid attribute matchesFrame::Boolean with false, ||; +monoid attribute freeRecVars::[String] with [], ++; synthesized attribute translation::a; - {- strategy attribute optimize = innermost( @@ -25,7 +23,7 @@ strategy attribute optimize = | choice(fail(), s) -> s | choice(s, fail()) -> s | choice(id(), s) -> id() - | choice(functorRef(n), s) -> functorRef(n) + | choice(functorRef(n, genName=g, location=l), s) -> functorRef(n, genName=g, location=l) | all(id()) -> id() | some(fail()) -> fail() | one(fail()) -> fail() @@ -35,23 +33,26 @@ strategy attribute optimize = | all(s) when !attrMatchesChild(top.env, fromMaybe(s.genName, s.attrRefName), top.frame) -> id() | some(s) when !attrMatchesChild(top.env, fromMaybe(s.genName, s.attrRefName), top.frame) -> fail() | one(s) when !attrMatchesChild(top.env, fromMaybe(s.genName, s.attrRefName), top.frame) -> fail() - | rewriteRule(...) when !... .matchesFrame -> fail() - | recVarRef(n) when !n.matchesFrame -> fail() + | rewriteRule(_, _, ml) when !ml.matchesFrame -> fail() | strategyRef(n) when !n.matchesFrame -> fail() | functorRef(n) when !n.matchesFrame -> fail() + | strategyRef(n) when n.matchesFrame && !n.attrDcl.isRecursive && null(n.attrDcl.givenRecVarEnv) -> n.attrDcl.strategyExpr + end <+ + rule on MRuleList of + | mRuleList_cons(h, _, t) when !h.matchesFrame -> t end); -} nonterminal StrategyExpr with config, grammarName, env, location, unparse, errors, frame, compiledGrammars, flowEnv, flowDefs, -- Normal expression stuff - genName, recVarEnv, outerAttr, liftedStrategies, attrRefName, freeRecVars, - translation; + genName, recVarEnv, outerAttr, liftedStrategies, attrRefName, + translation, matchesFrame, freeRecVars; flowtype StrategyExpr = decorate {grammarName, config, recVarEnv, outerAttr}, -- NOT frame or env unparse {}, errors {decorate, frame, env, compiledGrammars, flowEnv}, flowDefs {decorate, frame, env, compiledGrammars, flowEnv}, liftedStrategies {decorate}, attrRefName {decorate}, - translation {decorate, frame, env}, freeRecVars {decorate, env}; + translation {decorate, frame, env}, matchesFrame {decorate, frame, env}, freeRecVars {decorate, env}; propagate errors on StrategyExpr excluding strategyRef, functorRef; propagate flowDefs on StrategyExpr; @@ -61,6 +62,7 @@ aspect default production top::StrategyExpr ::= { top.attrRefName = nothing(); + top.matchesFrame := true; } -- Basic combinators @@ -95,33 +97,36 @@ top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr local s2Name::String = fromMaybe(s2.genName, s2.attrRefName); top.translation = - case s1, s2 of - | functorRef(attr1), functorRef(attr2) -> - Silver_Expr { - core:just( + if !s1.matchesFrame || !s2.matchesFrame + then Silver_Expr { core:nothing() } + else + case s1, s2 of + | functorRef(attr1), functorRef(attr2) -> + Silver_Expr { + core:just( + decorate $name{top.frame.signature.outputElement.elementName}.$QNameAttrOccur{attr1} + with {}.$QNameAttrOccur{attr2}) -- TODO: Decorate with all inh attributes + } + | functorRef(attr1), _ -> + Silver_Expr { decorate $name{top.frame.signature.outputElement.elementName}.$QNameAttrOccur{attr1} - with {}.$QNameAttrOccur{attr2}) -- TODO: Decorate with all inh attributes - } - | functorRef(attr1), _ -> - Silver_Expr { - decorate $name{top.frame.signature.outputElement.elementName}.$QNameAttrOccur{attr1} - with {}.$name{s2Name} - } - | _, functorRef(attr2) -> - Silver_Expr { - core:monad:bindMaybe( - $Expr{s1.translation}, - \ res::$TypeExpr{typerepTypeExpr(top.frame.signature.outputElement.typerep, location=top.location)} -> - decorate res with {}.$QNameAttrOccur{attr2}) -- TODO: Decorate with all inh attributes - } - | _, _ -> - Silver_Expr { - core:monad:bindMaybe( - $Expr{s1.translation}, - \ res::$TypeExpr{typerepTypeExpr(top.frame.signature.outputElement.typerep, location=top.location)} -> - decorate res with {}.$name{s2Name}) -- TODO: Decorate with all inh attributes - } - end; + with {}.$name{s2Name} + } + | _, functorRef(attr2) -> + Silver_Expr { + core:monad:bindMaybe( + $Expr{s1.translation}, + \ res::$TypeExpr{typerepTypeExpr(top.frame.signature.outputElement.typerep, location=top.location)} -> + decorate res with {}.$QNameAttrOccur{attr2}) -- TODO: Decorate with all inh attributes + } + | _, _ -> + Silver_Expr { + core:monad:bindMaybe( + $Expr{s1.translation}, + \ res::$TypeExpr{typerepTypeExpr(top.frame.signature.outputElement.typerep, location=top.location)} -> + decorate res with {}.$name{s2Name}) -- TODO: Decorate with all inh attributes + } + end; } abstract production choice @@ -549,6 +554,7 @@ top::StrategyExpr ::= id::QNameAttrOccur propagate liftedStrategies; top.attrRefName = just(id.name); + top.matchesFrame := id.matchesFrame; id.attrFor = top.frame.signature.outputElement.typerep; @@ -578,6 +584,7 @@ top::StrategyExpr ::= id::QNameAttrOccur propagate liftedStrategies; top.attrRefName = just(id.name); + top.matchesFrame := id.matchesFrame; id.attrFor = top.frame.signature.outputElement.typerep; From af1c6a61068041d3184cd61a56e00cfd74dce8ad Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Wed, 8 Apr 2020 18:06:15 -0500 Subject: [PATCH 20/78] Add quotation/antiquotation for ExprInhs --- .../silver/extension/silverconstruction/Syntax.sv | 15 +++++++++++++++ .../extension/silverconstruction/Terminals.sv | 2 ++ .../extension/silverconstruction/Translation.sv | 1 + 3 files changed, 18 insertions(+) diff --git a/grammars/silver/extension/silverconstruction/Syntax.sv b/grammars/silver/extension/silverconstruction/Syntax.sv index 24380904f..929270130 100644 --- a/grammars/silver/extension/silverconstruction/Syntax.sv +++ b/grammars/silver/extension/silverconstruction/Syntax.sv @@ -29,6 +29,13 @@ top::Expr ::= 'Silver_Expr' '{' ast::Expr '}' forwards to translate(top.location, reflect(new(ast))); } +concrete production quoteExprInh +top::Expr ::= 'Silver_ExprInh' '{' ast::ExprInh '}' +{ + top.unparse = s"Silver_ExprInh {${ast.unparse}}"; + forwards to translate(top.location, reflect(new(ast))); +} + concrete production quotePattern top::Expr ::= 'Silver_Pattern' '{' ast::Pattern '}' { @@ -46,6 +53,14 @@ top::Expr ::= '$Expr' '{' e::Expr '}' location=top.location); } +concrete production antiquoteExprInhs +top::ExprInhs ::= '$ExprInhs' '{' e::Expr '}' +{ + top.unparse = s"$$ExprInhs{${e.unparse}}"; + -- TODO: [err(top.location, "$ExprInhs should not occur outside of quoted Silver literal")] + forwards to exprInhsEmpty(location=top.location); +} + concrete production antiquoteTypeExpr top::TypeExpr ::= '$TypeExpr' '{' e::Expr '}' { diff --git a/grammars/silver/extension/silverconstruction/Terminals.sv b/grammars/silver/extension/silverconstruction/Terminals.sv index 6a0ab974d..2d8214b8c 100644 --- a/grammars/silver/extension/silverconstruction/Terminals.sv +++ b/grammars/silver/extension/silverconstruction/Terminals.sv @@ -1,6 +1,7 @@ grammar silver:extension:silverconstruction; marking terminal SilverExpr_t 'Silver_Expr' lexer classes {KEYWORD, RESERVED}; +marking terminal SilverExprInh_t 'Silver_ExprInh' lexer classes {KEYWORD, RESERVED}; marking terminal SilverPattern_t 'Silver_Pattern' lexer classes {KEYWORD, RESERVED}; marking terminal SilverAGDcl_t 'Silver_AGDcl' lexer classes {KEYWORD, RESERVED}; marking terminal SilverProductionStmt_t 'Silver_ProductionStmt' lexer classes {KEYWORD, RESERVED}; @@ -9,6 +10,7 @@ temp_imp_ide_font font_escape color(160, 32, 240) bold italic; lexer class Antiquote font=font_escape; terminal AntiquoteExpr_t '$Expr' lexer classes {Antiquote}; +terminal AntiquoteExprInhs_t '$ExprInhs' lexer classes {Antiquote}; terminal AntiquoteTypeExpr_t '$TypeExpr' lexer classes {Antiquote}; terminal AntiquotePattern_t '$Pattern' lexer classes {Antiquote}; terminal AntiquoteQName_t '$QName' lexer classes {Antiquote}; diff --git a/grammars/silver/extension/silverconstruction/Translation.sv b/grammars/silver/extension/silverconstruction/Translation.sv index ccf06ff22..fc79e4528 100644 --- a/grammars/silver/extension/silverconstruction/Translation.sv +++ b/grammars/silver/extension/silverconstruction/Translation.sv @@ -8,6 +8,7 @@ top::AST ::= prodName::String children::ASTs annotations::NamedASTs { directAntiquoteProductions <- ["silver:extension:silverconstruction:antiquoteExpr", + "silver:extension:silverconstruction:antiquoteExprInhs", "silver:extension:silverconstruction:antiquoteTypeExpr", "silver:extension:silverconstruction:antiquoteQName", "silver:extension:silverconstruction:antiquoteQNameAttrOccur", From f8f67450d45d1950bffb3699d1d3e84721cc0ede Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Thu, 9 Apr 2020 12:38:19 -0500 Subject: [PATCH 21/78] Generate proper inh equations in sequence translation --- .../extension/strategyattr/StrategyExpr.sv | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/grammars/silver/extension/strategyattr/StrategyExpr.sv b/grammars/silver/extension/strategyattr/StrategyExpr.sv index 71542dbd4..1ec912888 100644 --- a/grammars/silver/extension/strategyattr/StrategyExpr.sv +++ b/grammars/silver/extension/strategyattr/StrategyExpr.sv @@ -62,7 +62,7 @@ aspect default production top::StrategyExpr ::= { top.attrRefName = nothing(); - top.matchesFrame := true; + top.matchesFrame := true; -- Consulted only when attrRefName is just(...) } -- Basic combinators @@ -96,6 +96,25 @@ top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr s2.outerAttr = nothing(); local s2Name::String = fromMaybe(s2.genName, s2.attrRefName); + -- Equations for all inh attributes on the nt that we know about. + -- This is safe because the MWDA requires that all inh dependencies of a syn attribute + -- be exported by the syn occurence anyway. + -- TODO - future optimization potential: this is where common sub-trees shared between + -- the incoming tree and the result of s1 get re-decorated. + local allInhs::ExprInhs = + foldr( + exprInhsCons(_, _, location=top.location), + exprInhsEmpty(location=top.location), + map( + \ a::DclInfo -> + Silver_ExprInh { + $name{a.fullName} = $name{top.frame.signature.outputElement.elementName}.$name{a.fullName}; + }, + filter( + (.isInherited), + flatMap( + getAttrDcl(_, top.env), + map((.attrOccurring), getAttrsOn(top.frame.lhsNtName, top.env)))))); top.translation = if !s1.matchesFrame || !s2.matchesFrame then Silver_Expr { core:nothing() } @@ -105,26 +124,26 @@ top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr Silver_Expr { core:just( decorate $name{top.frame.signature.outputElement.elementName}.$QNameAttrOccur{attr1} - with {}.$QNameAttrOccur{attr2}) -- TODO: Decorate with all inh attributes + with { $ExprInhs{allInhs} }.$QNameAttrOccur{attr2}) } | functorRef(attr1), _ -> Silver_Expr { decorate $name{top.frame.signature.outputElement.elementName}.$QNameAttrOccur{attr1} - with {}.$name{s2Name} + with { $ExprInhs{allInhs} }.$name{s2Name} } | _, functorRef(attr2) -> Silver_Expr { core:monad:bindMaybe( $Expr{s1.translation}, \ res::$TypeExpr{typerepTypeExpr(top.frame.signature.outputElement.typerep, location=top.location)} -> - decorate res with {}.$QNameAttrOccur{attr2}) -- TODO: Decorate with all inh attributes + decorate res with { $ExprInhs{allInhs} }.$QNameAttrOccur{attr2}) } | _, _ -> Silver_Expr { core:monad:bindMaybe( $Expr{s1.translation}, \ res::$TypeExpr{typerepTypeExpr(top.frame.signature.outputElement.typerep, location=top.location)} -> - decorate res with {}.$name{s2Name}) -- TODO: Decorate with all inh attributes + decorate res with { $ExprInhs{allInhs} }.$name{s2Name}) } end; } From 7168773b4f53090302c2c0ddaa1d3af230d2aac2 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Thu, 9 Apr 2020 13:00:50 -0500 Subject: [PATCH 22/78] Add strategy attribute version of expression simplification term rewriting example test case --- .../rewrite/expreval/AbstractSyntax.sv | 66 +++++++++++++++++++ .../silver_features/rewrite/expreval/Tests.sv | 60 ++++++++++++----- 2 files changed, 108 insertions(+), 18 deletions(-) diff --git a/test/silver_features/rewrite/expreval/AbstractSyntax.sv b/test/silver_features/rewrite/expreval/AbstractSyntax.sv index 8d84c2d3d..258e3d809 100644 --- a/test/silver_features/rewrite/expreval/AbstractSyntax.sv +++ b/test/silver_features/rewrite/expreval/AbstractSyntax.sv @@ -3,6 +3,7 @@ grammar silver_features:rewrite:expreval; imports silver:langutil; imports silver:langutil:pp; imports silver:rewrite; +imports core:monad; synthesized attribute needsParens::Boolean; @@ -63,6 +64,7 @@ String ::= e::Expr return show(80, e.pp); } +-- Term rewriting library/extension function subst Strategy ::= n::String e::Expr { @@ -120,3 +122,67 @@ global simplifyFrac::Strategy = end; global eval::Strategy = innermost(evalStep <+ simplifyConstIdent <+ simplifyFrac); + +-- Strategy attributes +autocopy attribute substName::String; +autocopy attribute substExpr::Expr; +strategy attribute substRes = + bottomUp(try( + rule on top::Expr of + | var(n1) when top.substName == n1 -> top.substExpr + end)); +attribute substName, substExpr, substRes occurs on Expr; +propagate substRes on Expr; + +strategy attribute evalStep = + rule on Expr of + | add(const(a), const(b)) -> const(a + b) + | sub(const(a), const(b)) -> const(a - b) + | mul(const(a), const(b)) -> const(a * b) + | div(const(a), const(b)) when b != 0 && a % b == 0 -> const(a / b) + | div(const(a), const(b)) when b != 0 && gcd(a, b) > 1 -> + let g::Integer = gcd(a, b) in div(const(a / g), const(b / g)) end + -- This rule does not respect lexical shadowing; + -- it is assumed that the overall rewrite will be done in an innermost order. + | letE(n, e1, e2) -> decorate e2 with {substName = n; substExpr = e1;}.substRes.fromJust + end; + +strategy attribute simplifyConstIdent = + rule on Expr of + | add(a, const(0)) -> a + | add(const(0), a) -> a + + | sub(a, const(0)) -> a + + | mul(_, const(0)) -> const(0) + | mul(const(0), _) -> const(0) + | mul(a, const(1)) -> a + | mul(const(1), a) -> a + + | div(const(0), _) -> const(0) + | div(a, const(1)) -> a + end; + +strategy attribute simplifyFrac = + rule on Expr of + | add(div(a, b), c) -> div(add(a, mul(b, c)), b) + | sub(div(a, b), c) -> div(sub(a, mul(b, c)), b) + | mul(div(a, b), c) -> div(mul(a, c), b) + | div(div(a, b), c) -> div(a, mul(b, c)) + + | add(a, div(b, c)) -> div(add(mul(a, c), b), c) + | sub(a, div(b, c)) -> div(sub(mul(a, c), b), c) + | mul(a, div(b, c)) -> div(mul(a, b), c) + | div(a, div(b, c)) -> div(mul(a, c), b) + + | add(div(a, b), div(c, d)) -> div(add(mul(a, d), mul(c, b)), mul(b, d)) + | sub(div(a, b), div(c, d)) -> div(sub(mul(a, d), mul(c, b)), mul(b, d)) + | mul(div(a, b), div(c, d)) -> div(mul(a, c), mul(c, d)) + | div(div(a, b), div(c, d)) -> div(mul(a, d), mul(b, c)) + end; + +strategy attribute eval = innermost(evalStep <+ simplifyConstIdent <+ simplifyFrac); + +attribute evalStep, simplifyConstIdent, simplifyFrac, eval occurs on Expr; +propagate evalStep, simplifyConstIdent, simplifyFrac, eval on Expr; + diff --git a/test/silver_features/rewrite/expreval/Tests.sv b/test/silver_features/rewrite/expreval/Tests.sv index 3efc9e0d0..3d5794e9e 100644 --- a/test/silver_features/rewrite/expreval/Tests.sv +++ b/test/silver_features/rewrite/expreval/Tests.sv @@ -4,26 +4,50 @@ import silver:testing; import lib:extcore; import silver_features; -global result1::Maybe = rewriteWith(eval, parseExpr("1 + (2 * 3)")); -equalityTest(result1.isJust, true, Boolean, silver_tests); -equalityTest(showExpr(fromMaybe(const(12345), result1)), "7", String, silver_tests); +global test1::Expr = parseExpr("1 + (2 * 3)"); +global result1a::Maybe = rewriteWith(eval, test1); +equalityTest(result1a.isJust, true, Boolean, silver_tests); +equalityTest(showExpr(fromMaybe(const(12345), result1a)), "7", String, silver_tests); +global result1b::Maybe = test1.eval; +equalityTest(result1b.isJust, true, Boolean, silver_tests); +equalityTest(showExpr(fromMaybe(const(12345), result1b)), "7", String, silver_tests); -global result2::Maybe = rewriteWith(eval, parseExpr("7 + 4 - ((1 + 1) / 0)")); -equalityTest(result2.isJust, true, Boolean, silver_tests); -equalityTest(showExpr(fromMaybe(const(12345), result2)), "-2 / 0", String, silver_tests); +global test2::Expr = parseExpr("7 + 4 - ((1 + 1) / 0)"); +global result2a::Maybe = rewriteWith(eval, test2); +equalityTest(result2a.isJust, true, Boolean, silver_tests); +equalityTest(showExpr(fromMaybe(const(12345), result2a)), "-2 / 0", String, silver_tests); +global result2b::Maybe = test2.eval; +equalityTest(result2b.isJust, true, Boolean, silver_tests); +equalityTest(showExpr(fromMaybe(const(12345), result2b)), "-2 / 0", String, silver_tests); -global result3::Maybe = rewriteWith(eval, parseExpr("(2 + 2) / 6")); -equalityTest(result3.isJust, true, Boolean, silver_tests); -equalityTest(showExpr(fromMaybe(const(12345), result3)), "2 / 3", String, silver_tests); +global test3::Expr = parseExpr("(2 + 2) / 6"); +global result3a::Maybe = rewriteWith(eval, test3); +equalityTest(result3a.isJust, true, Boolean, silver_tests); +equalityTest(showExpr(fromMaybe(const(12345), result3a)), "2 / 3", String, silver_tests); +global result3b::Maybe = test3.eval; +equalityTest(result3b.isJust, true, Boolean, silver_tests); +equalityTest(showExpr(fromMaybe(const(12345), result3b)), "2 / 3", String, silver_tests); -global result4::Maybe = rewriteWith(eval, parseExpr("1 + 1 / (1 + 1 / (1 + 1 / (1 + 1 / (1 + 1 / (1 + 1 / (1 + 1))))))")); -equalityTest(result4.isJust, true, Boolean, silver_tests); -equalityTest(showExpr(fromMaybe(const(12345), result4)), "34 / 21", String, silver_tests); +global test4::Expr = parseExpr("1 + 1 / (1 + 1 / (1 + 1 / (1 + 1 / (1 + 1 / (1 + 1 / (1 + 1))))))"); +global result4a::Maybe = rewriteWith(eval, test4); +equalityTest(result4a.isJust, true, Boolean, silver_tests); +equalityTest(showExpr(fromMaybe(const(12345), result4a)), "34 / 21", String, silver_tests); +global result4b::Maybe = test4.eval; +equalityTest(result4b.isJust, true, Boolean, silver_tests); +equalityTest(showExpr(fromMaybe(const(12345), result4b)), "34 / 21", String, silver_tests); -global result5::Maybe = rewriteWith(eval, parseExpr("let a = 1 / 2 in let b = a * 2 in a + b")); -equalityTest(result5.isJust, true, Boolean, silver_tests); -equalityTest(showExpr(fromMaybe(const(12345), result5)), "3 / 2", String, silver_tests); +global test5::Expr = parseExpr("let a = 1 / 2 in let b = a * 2 in a + b"); +global result5a::Maybe = rewriteWith(eval, test5); +equalityTest(result5a.isJust, true, Boolean, silver_tests); +equalityTest(showExpr(fromMaybe(const(12345), result5a)), "3 / 2", String, silver_tests); +global result5b::Maybe = test5.eval; +equalityTest(result5b.isJust, true, Boolean, silver_tests); +equalityTest(showExpr(fromMaybe(const(12345), result5b)), "3 / 2", String, silver_tests); -global result6::Maybe = rewriteWith(eval, parseExpr("0 + 1 * a - 2 / b")); -equalityTest(result6.isJust, true, Boolean, silver_tests); -equalityTest(showExpr(fromMaybe(const(12345), result6)), "((a * b) - 2) / b", String, silver_tests); +global test6::Expr = parseExpr("0 + 1 * a - 2 / b"); +global result6a::Maybe = rewriteWith(eval, test6); +equalityTest(result6a.isJust, true, Boolean, silver_tests); +equalityTest(showExpr(fromMaybe(const(12345), result6a)), "((a * b) - 2) / b", String, silver_tests); +global result6b::Maybe = test6.eval; +equalityTest(result6b.isJust, true, Boolean, silver_tests); +equalityTest(showExpr(fromMaybe(const(12345), result6b)), "((a * b) - 2) / b", String, silver_tests); From 794eb302ba1890dab97b5e1fe1fb76dff27e4717 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Thu, 9 Apr 2020 14:59:49 -0500 Subject: [PATCH 23/78] Add comment --- grammars/silver/extension/strategyattr/StrategyUtils.sv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grammars/silver/extension/strategyattr/StrategyUtils.sv b/grammars/silver/extension/strategyattr/StrategyUtils.sv index b28637374..c2a2bfdbd 100644 --- a/grammars/silver/extension/strategyattr/StrategyUtils.sv +++ b/grammars/silver/extension/strategyattr/StrategyUtils.sv @@ -10,7 +10,7 @@ top::StrategyExpr ::= s::StrategyExpr }; } -abstract production repeatS +abstract production repeatS -- name clash with repeat from core top::StrategyExpr ::= s::StrategyExpr { forwards to From 4fae8b5c4669209686f9b52ea208833b8e03ffea Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Mon, 13 Apr 2020 11:39:45 -0500 Subject: [PATCH 24/78] Implement more utility strategies for consistency with reflection-based rewriting library --- .../extension/strategyattr/ConcreteSyntax.sv | 52 ++++++++++++++ .../extension/strategyattr/StrategyUtils.sv | 72 +++++++++++++++++++ .../extension/strategyattr/Terminals.sv | 8 +++ 3 files changed, 132 insertions(+) diff --git a/grammars/silver/extension/strategyattr/ConcreteSyntax.sv b/grammars/silver/extension/strategyattr/ConcreteSyntax.sv index 17ddb7662..0df75b793 100644 --- a/grammars/silver/extension/strategyattr/ConcreteSyntax.sv +++ b/grammars/silver/extension/strategyattr/ConcreteSyntax.sv @@ -112,6 +112,51 @@ concrete productions top::StrategyExpr_c top.ast = topDown(s.ast, genName=top.givenGenName, location=top.location); s.givenGenName = top.givenGenName ++ "_topDown_arg"; } +| 'downUp' '(' s1::StrategyExpr_c ',' s2::StrategyExpr_c ')' +{ + top.unparse = s"downUp(${s1.unparse}, ${s2.unparse})"; + top.ast = downUp(s1.ast, s2.ast, genName=top.givenGenName, location=top.location); + s1.givenGenName = top.givenGenName ++ "_downUp_arg1"; + s2.givenGenName = top.givenGenName ++ "_downUp_arg2"; +} +| 'allBottomUp' '(' s::StrategyExpr_c ')' +{ + top.unparse = s"allBottomUp(${s.unparse})"; + top.ast = allBottomUp(s.ast, genName=top.givenGenName, location=top.location); + s.givenGenName = top.givenGenName ++ "_allBottomUp_arg"; +} +| 'allTopDown' '(' s::StrategyExpr_c ')' +{ + top.unparse = s"allTopDown(${s.unparse})"; + top.ast = allTopDown(s.ast, genName=top.givenGenName, location=top.location); + s.givenGenName = top.givenGenName ++ "_allTopDown_arg"; +} +| 'allDownUp' '(' s1::StrategyExpr_c ',' s2::StrategyExpr_c ')' +{ + top.unparse = s"allDownUp(${s1.unparse}, ${s2.unparse})"; + top.ast = allDownUp(s1.ast, s2.ast, genName=top.givenGenName, location=top.location); + s1.givenGenName = top.givenGenName ++ "_allDownUp_arg1"; + s2.givenGenName = top.givenGenName ++ "_allDownUp_arg2"; +} +| 'someBottomUp' '(' s::StrategyExpr_c ')' +{ + top.unparse = s"someBottomUp(${s.unparse})"; + top.ast = someBottomUp(s.ast, genName=top.givenGenName, location=top.location); + s.givenGenName = top.givenGenName ++ "_someBottomUp_arg"; +} +| 'someTopDown' '(' s::StrategyExpr_c ')' +{ + top.unparse = s"someTopDown(${s.unparse})"; + top.ast = someTopDown(s.ast, genName=top.givenGenName, location=top.location); + s.givenGenName = top.givenGenName ++ "_someTopDown_arg"; +} +| 'someDownUp' '(' s1::StrategyExpr_c ',' s2::StrategyExpr_c ')' +{ + top.unparse = s"someDownUp(${s1.unparse}, ${s2.unparse})"; + top.ast = someDownUp(s1.ast, s2.ast, genName=top.givenGenName, location=top.location); + s1.givenGenName = top.givenGenName ++ "_someDownUp_arg1"; + s2.givenGenName = top.givenGenName ++ "_someDownUp_arg2"; +} | 'onceBottomUp' '(' s::StrategyExpr_c ')' { top.unparse = s"onceBottomUp(${s.unparse})"; @@ -124,6 +169,13 @@ concrete productions top::StrategyExpr_c top.ast = onceTopDown(s.ast, genName=top.givenGenName, location=top.location); s.givenGenName = top.givenGenName ++ "_onceTopDown_arg"; } +| 'onceDownUp' '(' s1::StrategyExpr_c ',' s2::StrategyExpr_c ')' +{ + top.unparse = s"onceDownUp(${s1.unparse}, ${s2.unparse})"; + top.ast = onceDownUp(s1.ast, s2.ast, genName=top.givenGenName, location=top.location); + s1.givenGenName = top.givenGenName ++ "_onceDownUp_arg1"; + s2.givenGenName = top.givenGenName ++ "_onceDownUp_arg2"; +} | 'innermost' '(' s::StrategyExpr_c ')' { top.unparse = s"innermost(${s.unparse})"; diff --git a/grammars/silver/extension/strategyattr/StrategyUtils.sv b/grammars/silver/extension/strategyattr/StrategyUtils.sv index c2a2bfdbd..c39c9b5ab 100644 --- a/grammars/silver/extension/strategyattr/StrategyUtils.sv +++ b/grammars/silver/extension/strategyattr/StrategyUtils.sv @@ -46,6 +46,69 @@ top::StrategyExpr ::= s::StrategyExpr }; } +abstract production downUp +top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr +{ + forwards to + Silver_StrategyExpr downUp { + rec res -> $StrategyExpr{s1} <* all(res) <* $StrategyExpr{s2} + }; +} + +abstract production allBottomUp +top::StrategyExpr ::= s::StrategyExpr +{ + forwards to + Silver_StrategyExpr allBottomUp { + rec res -> all(res) <+ $StrategyExpr{s} + }; +} + +abstract production allTopDown +top::StrategyExpr ::= s::StrategyExpr +{ + forwards to + Silver_StrategyExpr allTopDown { + rec res -> $StrategyExpr{s} <+ all(res) + }; +} + +abstract production allDownUp +top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr +{ + forwards to + Silver_StrategyExpr allDownUp { + rec res -> $StrategyExpr{s1} <+ all(res) <+ $StrategyExpr{s2} + }; +} + +abstract production someBottomUp +top::StrategyExpr ::= s::StrategyExpr +{ + forwards to + Silver_StrategyExpr someBottomUp { + rec res -> some(res) <+ $StrategyExpr{s} + }; +} + +abstract production someTopDown +top::StrategyExpr ::= s::StrategyExpr +{ + forwards to + Silver_StrategyExpr someTopDown { + rec res -> $StrategyExpr{s} <+ some(res) + }; +} + +abstract production someDownUp +top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr +{ + forwards to + Silver_StrategyExpr someDownUp { + rec res -> $StrategyExpr{s1} <+ some(res) <+ $StrategyExpr{s2} + }; +} + abstract production onceBottomUp top::StrategyExpr ::= s::StrategyExpr { @@ -64,6 +127,15 @@ top::StrategyExpr ::= s::StrategyExpr }; } +abstract production onceDownUp +top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr +{ + forwards to + Silver_StrategyExpr onceDownUp { + rec res -> $StrategyExpr{s1} <+ one(res) <+ $StrategyExpr{s2} + }; +} + abstract production innermost top::StrategyExpr ::= s::StrategyExpr { diff --git a/grammars/silver/extension/strategyattr/Terminals.sv b/grammars/silver/extension/strategyattr/Terminals.sv index e23185462..373aee77d 100644 --- a/grammars/silver/extension/strategyattr/Terminals.sv +++ b/grammars/silver/extension/strategyattr/Terminals.sv @@ -20,8 +20,16 @@ terminal Repeat_t 'repeat' lexer classes {KEYWORD, Strategy}; terminal Reduce_t 'reduce' lexer classes {KEYWORD, Strategy}; terminal BottomUp_t 'bottomUp' lexer classes {KEYWORD, Strategy}; terminal TopDown_t 'topDown' lexer classes {KEYWORD, Strategy}; +terminal DownUp_t 'downUp' lexer classes {KEYWORD, Strategy}; +terminal AllBottomUp_t 'allBottomUp' lexer classes {KEYWORD, Strategy}; +terminal AllTopDown_t 'allTopDown' lexer classes {KEYWORD, Strategy}; +terminal AllDownUp_t 'allDownUp' lexer classes {KEYWORD, Strategy}; +terminal SomeBottomUp_t 'someBottomUp' lexer classes {KEYWORD, Strategy}; +terminal SomeTopDown_t 'someTopDown' lexer classes {KEYWORD, Strategy}; +terminal SomeDownUp_t 'someDownUp' lexer classes {KEYWORD, Strategy}; terminal OnceBottomUp_t 'onceBottomUp' lexer classes {KEYWORD, Strategy}; terminal OnceTopDown_t 'onceTopDown' lexer classes {KEYWORD, Strategy}; +terminal OnceDownUp_t 'onceDownUp' lexer classes {KEYWORD, Strategy}; terminal Innermost_t 'innermost' lexer classes {KEYWORD, Strategy}; terminal Outermost_t 'outermost' lexer classes {KEYWORD, Strategy}; From 9ca1db4c02bdb56d4451ecb47723f43478ba5a5b Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Mon, 13 Apr 2020 14:45:51 -0500 Subject: [PATCH 25/78] Implement production congruence traversal strategies --- .../extension/strategyattr/ConcreteSyntax.sv | 33 ++++- .../extension/strategyattr/StrategyExpr.sv | 121 +++++++++++++++++- test/silver_features/Strategy.sv | 28 ++++ 3 files changed, 175 insertions(+), 7 deletions(-) diff --git a/grammars/silver/extension/strategyattr/ConcreteSyntax.sv b/grammars/silver/extension/strategyattr/ConcreteSyntax.sv index 0df75b793..017375ef0 100644 --- a/grammars/silver/extension/strategyattr/ConcreteSyntax.sv +++ b/grammars/silver/extension/strategyattr/ConcreteSyntax.sv @@ -55,6 +55,13 @@ concrete productions top::StrategyExpr_c top.ast = oneTraversal(s.ast, genName=top.givenGenName, location=top.location); s.givenGenName = top.givenGenName ++ "_one_arg"; } +| id::StrategyQName '(' s::StrategyExprs_c ')' +{ + top.unparse = s"${id.ast.unparse}(${s.unparse})"; + top.ast = prodTraversal(id.ast, s.ast, genName=top.givenGenName, location=top.location); + s.index = 1; + s.givenGenName = top.givenGenName ++ "_" ++ id.ast.name; +} | 'rec' n::Name Arrow_t s::StrategyExpr_c { top.unparse = s"rec ${n.name} -> (${s.unparse})"; @@ -189,9 +196,33 @@ concrete productions top::StrategyExpr_c s.givenGenName = top.givenGenName ++ "_outermost_arg"; } +autocopy attribute index::Integer; + +nonterminal StrategyExprs_c with location, index, givenGenName, unparse, ast; +concrete productions top::StrategyExprs_c +| h::StrategyExpr_c ',' t::StrategyExprs_c +{ + top.unparse = h.unparse ++ ", " ++ t.unparse; + top.ast = consStrategyExpr(h.ast, t.ast); + h.givenGenName = top.givenGenName ++ "_arg" ++ toString(top.index); + t.givenGenName = top.givenGenName; + t.index = top.index + 1; +} +| h::StrategyExpr_c +{ + top.unparse = h.unparse; + top.ast = consStrategyExpr(h.ast, nilStrategyExpr()); + h.givenGenName = top.givenGenName ++ "_arg" ++ toString(top.index); +} +| +{ + top.unparse = ""; + top.ast = nilStrategyExpr(); +} + nonterminal StrategyQName with location, ast; concrete productions top::StrategyQName | id::StrategyName_t { top.ast = qNameId(name(id.lexeme, id.location), location=top.location); } | id::StrategyName_t ':' qn::StrategyQName -{ top.ast = qNameCons(name(id.lexeme, id.location), $2, qn.ast, location=top.location); } \ No newline at end of file +{ top.ast = qNameCons(name(id.lexeme, id.location), $2, qn.ast, location=top.location); } diff --git a/grammars/silver/extension/strategyattr/StrategyExpr.sv b/grammars/silver/extension/strategyattr/StrategyExpr.sv index 1ec912888..607330662 100644 --- a/grammars/silver/extension/strategyattr/StrategyExpr.sv +++ b/grammars/silver/extension/strategyattr/StrategyExpr.sv @@ -8,6 +8,7 @@ autocopy attribute recVarEnv::[Pair]; inherited attribute outerAttr::Maybe; monoid attribute liftedStrategies::[Pair] with [], ++; synthesized attribute attrRefName::Maybe; +synthesized attribute attrRefNames::[String]; monoid attribute matchesFrame::Boolean with false, ||; monoid attribute freeRecVars::[String] with [], ++; @@ -27,12 +28,15 @@ strategy attribute optimize = | all(id()) -> id() | some(fail()) -> fail() | one(fail()) -> fail() + | prodTraversal(_, s) when s.containsFail -> fail() + | prodTraversal(_, s) when s.allId -> id() | rec(n, s) when !containsBy(stringEq, s.freeRecVars, n.name) -> s -- These don't apply inside traversals/sequence continuations! | all(s) when !attrMatchesChild(top.env, fromMaybe(s.genName, s.attrRefName), top.frame) -> id() | some(s) when !attrMatchesChild(top.env, fromMaybe(s.genName, s.attrRefName), top.frame) -> fail() | one(s) when !attrMatchesChild(top.env, fromMaybe(s.genName, s.attrRefName), top.frame) -> fail() + | prodTraversal(p, s) when p.lookupValue.fullName != top.frame.fullName -> fail() | rewriteRule(_, _, ml) when !ml.matchesFrame -> fail() | strategyRef(n) when !n.matchesFrame -> fail() | functorRef(n) when !n.matchesFrame -> fail() @@ -48,15 +52,21 @@ nonterminal StrategyExpr with genName, recVarEnv, outerAttr, liftedStrategies, attrRefName, translation, matchesFrame, freeRecVars; +nonterminal StrategyExprs with + config, grammarName, env, unparse, errors, frame, compiledGrammars, flowEnv, flowDefs, -- Normal expression stuff + recVarEnv, liftedStrategies, attrRefNames, + freeRecVars; + flowtype StrategyExpr = decorate {grammarName, config, recVarEnv, outerAttr}, -- NOT frame or env unparse {}, errors {decorate, frame, env, compiledGrammars, flowEnv}, flowDefs {decorate, frame, env, compiledGrammars, flowEnv}, liftedStrategies {decorate}, attrRefName {decorate}, translation {decorate, frame, env}, matchesFrame {decorate, frame, env}, freeRecVars {decorate, env}; -propagate errors on StrategyExpr excluding strategyRef, functorRef; -propagate flowDefs on StrategyExpr; -propagate freeRecVars on StrategyExpr excluding rec; +propagate errors on StrategyExpr, StrategyExprs excluding strategyRef, functorRef; +propagate flowDefs on StrategyExpr, StrategyExprs; +propagate liftedStrategies on StrategyExprs; +propagate freeRecVars on StrategyExpr, StrategyExprs excluding rec; aspect default production top::StrategyExpr ::= @@ -182,13 +192,14 @@ top::StrategyExpr ::= s::StrategyExpr local sName::String = fromMaybe(s.genName, s.attrRefName); local sBaseName::String = last(explode(":", sName)); + -- pair(child name, attr occurs on child) local childAccesses::[Pair] = map( \ e::NamedSignatureElement -> pair(e.elementName, attrMatchesFrame(top.env, sName, e.typerep)), top.frame.signature.inputElements); top.translation = - {- Translation of prod::(Foo ::= a::Foo b::Integer c::Bar): + {- Translation of all(s) for prod::(Foo ::= a::Foo b::Integer c::Bar): case a.s, c.s of | just(a_s), just(c_s) -> just(prod(a_s, b, c_s)) | _, _ -> nothing() @@ -251,13 +262,14 @@ top::StrategyExpr ::= s::StrategyExpr s.outerAttr = nothing(); local sName::String = fromMaybe(s.genName, s.attrRefName); + -- pair(child name, attr occurs on child) local childAccesses::[Pair] = map( \ e::NamedSignatureElement -> pair(e.elementName, attrMatchesFrame(top.env, sName, e.typerep)), top.frame.signature.inputElements); top.translation = - {- Translation of prod::(Foo ::= a::Foo b::Integer c::Bar): + {- Translation of some(s) for prod::(Foo ::= a::Foo b::Integer c::Bar): if a.s.isJust || c.s.isJust then just(prod(fromMaybe(a, a.s), b, fromMaybe(c, c.s))) else nothing() @@ -309,6 +321,7 @@ top::StrategyExpr ::= s::StrategyExpr local sName::String = fromMaybe(s.genName, s.attrRefName); local sBaseName::String = last(explode(":", sName)); + -- pair(child name, attr occurs on child) local childAccesses::[Pair] = map( \ e::NamedSignatureElement -> @@ -316,7 +329,7 @@ top::StrategyExpr ::= s::StrategyExpr top.frame.signature.inputElements); local matchingChildren::[String] = map(fst, filter(snd, childAccesses)); top.translation = - {- Translation of prod::(Foo ::= a::Foo b::Integer c::Bar): + {- Translation of one(s) for prod::(Foo ::= a::Foo b::Integer c::Bar): case a.s, c.s of | just(a_s), _ -> just(prod(a_s, b, c)) | _, just(c_s) -> just(prod(a, b, c_s)) @@ -367,6 +380,102 @@ top::StrategyExpr ::= s::StrategyExpr location=top.location); } +abstract production prodTraversal +top::StrategyExpr ::= prod::QName s::StrategyExprs +{ + top.unparse = s"${prod.unparse}(${s.unparse})"; + + local numParams::Integer = length(prod.lookupValue.dcl.namedSignature.inputElements); + local numArgs::Integer = length(s.attrRefNames); + top.errors <- + if numArgs != numParams + then [err(top.location, s"Wrong number of arguments to ${prod.name}: expected ${toString(numParams)}, got ${toString(numArgs)}")] + else []; + + propagate liftedStrategies; + + -- pair(pair(child name, attr name), attr occurs on child) + local childAccesses::[Pair Boolean>] = + zipWith( + \ e::NamedSignatureElement attr::String -> + pair(pair(e.elementName, attr), attrMatchesFrame(top.env, attr, e.typerep)), + top.frame.signature.inputElements, + s.attrRefNames); + top.translation = + if prod.lookupValue.fullName == top.frame.fullName + then + {- Translation of prod(s1, s2, s3) for prod::(Foo ::= a::Foo b::Integer c::Bar): + case a.s1, c.s3 of + | just(a_s1), just(c_s3) -> just(prod(a_s1, b, c_s3)) + | _, _ -> nothing() + end + Could also be implemented as chained monadic binds. Maybe more efficient this way? -} + caseExpr( + flatMap( + \ a::Pair Boolean> -> + if a.snd then [Silver_Expr { $name{a.fst.fst}.$name{a.fst.snd} }] else [], + childAccesses), + [matchRule( + flatMap( + \ a::Pair Boolean> -> + if a.snd + then + [decorate Silver_Pattern { core:just($name{a.fst.fst ++ "_" ++ last(explode(":", a.fst.snd))}) } + with { config = top.config; env = top.env; frame = top.frame; patternVarEnv = []; }] + else [], + childAccesses), + nothing(), + Silver_Expr { + core:just( + $Expr{ + mkFullFunctionInvocation( + top.location, + baseExpr(qName(top.location, top.frame.fullName), location=top.location), + map( + \ a::Pair Boolean> -> + if a.snd + then Silver_Expr { $name{a.fst.fst ++ "_" ++ last(explode(":", a.fst.snd))} } + else Silver_Expr { $name{a.fst.fst} }, + childAccesses), + map( + makeAnnoArg(top.location, top.frame.signature.outputElement.elementName, _), + top.frame.signature.namedInputElements))}) + }, + location=top.location)], + Silver_Expr { core:nothing() }, + nonterminalType("core:Maybe", [top.frame.signature.outputElement.typerep]), + location=top.location) + else Silver_Expr { core:nothing() }; +} + +abstract production consStrategyExpr +top::StrategyExprs ::= h::StrategyExpr t::StrategyExprs +{ + top.unparse = s"${h.unparse}, ${t.unparse}"; + + top.errors <- + case h of + -- TBH this doesn't seem very useful anyway + | functorRef(_) -> [err(h.location, "Functor attributes as arguments to production traversals are not yet supported")] + | _ -> [] + end; + + top.liftedStrategies <- + if h.attrRefName.isJust + then [] + else [pair(h.genName, h)]; + top.attrRefNames = fromMaybe(h.genName, h.attrRefName) :: t.attrRefNames; + + h.outerAttr = nothing(); +} + +abstract production nilStrategyExpr +top::StrategyExprs ::= +{ + top.unparse = ""; + top.attrRefNames = []; +} + -- Recursive strategies abstract production rec top::StrategyExpr ::= n::Name s::StrategyExpr diff --git a/test/silver_features/Strategy.sv b/test/silver_features/Strategy.sv index 2d793a71b..a25408924 100644 --- a/test/silver_features/Strategy.sv +++ b/test/silver_features/Strategy.sv @@ -52,3 +52,31 @@ equalityTest( assignSStmt("b", addSExpr(addSExpr(idSExpr("a"), constSExpr(0)), constSExpr(0)))).elimPlusZero), "core:just(silver_features:seqSStmt(silver_features:assignSStmt(\"a\", silver_features:constSExpr(42)), silver_features:assignSStmt(\"b\", silver_features:idSExpr(\"a\"))))", String, silver_tests); + +strategy attribute removeLastStmt = + rule on SStmt of + | seqSStmt(s, assignSStmt(_, _)) -> s + end <+ + seqSStmt(id, removeLastStmt) + occurs on SStmt, SExpr; +propagate removeLastStmt on SStmt, SExpr; + +equalityTest( + hackUnparse( + seqSStmt( + assignSStmt("a", addSExpr(constSExpr(42), constSExpr(0))), + assignSStmt("b", addSExpr(addSExpr(idSExpr("a"), constSExpr(0)), constSExpr(0)))).removeLastStmt), + "core:just(silver_features:assignSStmt(\"a\", silver_features:addSExpr(silver_features:constSExpr(42), silver_features:constSExpr(0))))", + String, silver_tests); + +equalityTest( + hackUnparse( + assignSStmt("a", addSExpr(constSExpr(42), constSExpr(0))).removeLastStmt), + "core:nothing()", + String, silver_tests); + +equalityTest( + hackUnparse( + addSExpr(constSExpr(42), constSExpr(0)).removeLastStmt), + "core:nothing()", + String, silver_tests); From 1468952b8706f8acbac0775a5ad5d128bf7ed795 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Mon, 13 Apr 2020 15:33:15 -0500 Subject: [PATCH 26/78] Slight improvment to prod traversal translation --- .../extension/strategyattr/StrategyExpr.sv | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/grammars/silver/extension/strategyattr/StrategyExpr.sv b/grammars/silver/extension/strategyattr/StrategyExpr.sv index 607330662..de384f3f1 100644 --- a/grammars/silver/extension/strategyattr/StrategyExpr.sv +++ b/grammars/silver/extension/strategyattr/StrategyExpr.sv @@ -8,6 +8,7 @@ autocopy attribute recVarEnv::[Pair]; inherited attribute outerAttr::Maybe; monoid attribute liftedStrategies::[Pair] with [], ++; synthesized attribute attrRefName::Maybe; +synthesized attribute isId::Boolean; synthesized attribute attrRefNames::[String]; monoid attribute matchesFrame::Boolean with false, ||; monoid attribute freeRecVars::[String] with [], ++; @@ -49,7 +50,7 @@ strategy attribute optimize = nonterminal StrategyExpr with config, grammarName, env, location, unparse, errors, frame, compiledGrammars, flowEnv, flowDefs, -- Normal expression stuff - genName, recVarEnv, outerAttr, liftedStrategies, attrRefName, + genName, recVarEnv, outerAttr, liftedStrategies, attrRefName, isId, translation, matchesFrame, freeRecVars; nonterminal StrategyExprs with @@ -60,9 +61,15 @@ nonterminal StrategyExprs with flowtype StrategyExpr = decorate {grammarName, config, recVarEnv, outerAttr}, -- NOT frame or env unparse {}, errors {decorate, frame, env, compiledGrammars, flowEnv}, flowDefs {decorate, frame, env, compiledGrammars, flowEnv}, - liftedStrategies {decorate}, attrRefName {decorate}, + liftedStrategies {decorate}, attrRefName {decorate}, isId {decorate}, translation {decorate, frame, env}, matchesFrame {decorate, frame, env}, freeRecVars {decorate, env}; +flowtype StrategyExprs = + decorate {grammarName, config, recVarEnv}, -- NOT frame or env + unparse {}, errors {decorate, frame, env, compiledGrammars, flowEnv}, flowDefs {decorate, frame, env, compiledGrammars, flowEnv}, + liftedStrategies {decorate}, attrRefNames {decorate}, + freeRecVars {decorate, env}; + propagate errors on StrategyExpr, StrategyExprs excluding strategyRef, functorRef; propagate flowDefs on StrategyExpr, StrategyExprs; propagate liftedStrategies on StrategyExprs; @@ -73,6 +80,7 @@ top::StrategyExpr ::= { top.attrRefName = nothing(); top.matchesFrame := true; -- Consulted only when attrRefName is just(...) + top.isId = false; } -- Basic combinators @@ -81,6 +89,7 @@ top::StrategyExpr ::= { top.unparse = "id"; propagate liftedStrategies; + top.isId = true; top.translation = Silver_Expr { core:just($name{top.frame.signature.outputElement.elementName}) }; } @@ -461,7 +470,11 @@ top::StrategyExprs ::= h::StrategyExpr t::StrategyExprs end; top.liftedStrategies <- - if h.attrRefName.isJust + -- Slight hack: when h is id (common case for prod traversals), there is no need for a new attribute. + -- However this can't be eliminated during the optumization phase. + -- So, just don't lift the strategy, and we won't find the occurence of the non-existant attribute + -- during translation - which means we will treat it as id anyway! + if h.attrRefName.isJust || h.isId then [] else [pair(h.genName, h)]; top.attrRefNames = fromMaybe(h.genName, h.attrRefName) :: t.attrRefNames; @@ -626,6 +639,7 @@ top::StrategyExpr ::= id::QName -- Forwarding depends on env here, these must be computed without env propagate liftedStrategies; top.attrRefName = just(fromMaybe(id.name, lookupBy(stringEq, id.name, top.recVarEnv))); + top.isId = false; local attrDcl::DclInfo = id.lookupAttribute.dcl; attrDcl.givenNonterminalType = error("Not actually needed"); -- Ugh environment needs refactoring From 1381e876b1376f30682999dc5046a893c8c19aa8 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Mon, 13 Apr 2020 16:14:23 -0500 Subject: [PATCH 27/78] Renaming rec production -> recComb --- .../extension/strategyattr/ConcreteSyntax.sv | 2 +- .../extension/strategyattr/StrategyExpr.sv | 85 +++++++++++++------ 2 files changed, 59 insertions(+), 28 deletions(-) diff --git a/grammars/silver/extension/strategyattr/ConcreteSyntax.sv b/grammars/silver/extension/strategyattr/ConcreteSyntax.sv index 017375ef0..1ca9f29b4 100644 --- a/grammars/silver/extension/strategyattr/ConcreteSyntax.sv +++ b/grammars/silver/extension/strategyattr/ConcreteSyntax.sv @@ -65,7 +65,7 @@ concrete productions top::StrategyExpr_c | 'rec' n::Name Arrow_t s::StrategyExpr_c { top.unparse = s"rec ${n.name} -> (${s.unparse})"; - top.ast = rec(n, s.ast, genName=top.givenGenName, location=top.location); + top.ast = recComb(n, s.ast, genName=top.givenGenName, location=top.location); s.givenGenName = top.givenGenName ++ "_" ++ n.name; } | 'rule' 'on' id::Name '::' ty::TypeExpr 'of' Opt_Vbar_t ml::MRuleList 'end' diff --git a/grammars/silver/extension/strategyattr/StrategyExpr.sv b/grammars/silver/extension/strategyattr/StrategyExpr.sv index de384f3f1..ebd60c0ed 100644 --- a/grammars/silver/extension/strategyattr/StrategyExpr.sv +++ b/grammars/silver/extension/strategyattr/StrategyExpr.sv @@ -1,6 +1,7 @@ grammar silver:extension:strategyattr; import silver:metatranslation; +import core:monad; annotation genName::String; -- Used to generate the names of lifted strategy attributes @@ -10,42 +11,50 @@ monoid attribute liftedStrategies::[Pair] with [] synthesized attribute attrRefName::Maybe; synthesized attribute isId::Boolean; synthesized attribute attrRefNames::[String]; +monoid attribute containsFail::Boolean with false, ||; +monoid attribute allId::Boolean with true, &&; monoid attribute matchesFrame::Boolean with false, ||; monoid attribute freeRecVars::[String] with [], ++; synthesized attribute translation::a; {- -strategy attribute optimize = +-- Frame-independent algebraic simplifications +strategy attribute simplify = innermost( rule on top::StrategyExpr of - | sequence(fail(), _) -> fail() - | sequence(_, fail()) -> fail() + | sequence(fail(), _) -> fail(location=top.location, genName=top.genName) + | sequence(_, fail()) -> fail(location=top.location, genName=top.genName) | sequence(id(), s) -> s | sequence(s, id()) -> s | choice(fail(), s) -> s | choice(s, fail()) -> s - | choice(id(), s) -> id() + | choice(id(), s) -> id(location=top.location, genName=top.genName) | choice(functorRef(n, genName=g, location=l), s) -> functorRef(n, genName=g, location=l) - | all(id()) -> id() - | some(fail()) -> fail() - | one(fail()) -> fail() - | prodTraversal(_, s) when s.containsFail -> fail() - | prodTraversal(_, s) when s.allId -> id() - | rec(n, s) when !containsBy(stringEq, s.freeRecVars, n.name) -> s - - -- These don't apply inside traversals/sequence continuations! - | all(s) when !attrMatchesChild(top.env, fromMaybe(s.genName, s.attrRefName), top.frame) -> id() - | some(s) when !attrMatchesChild(top.env, fromMaybe(s.genName, s.attrRefName), top.frame) -> fail() - | one(s) when !attrMatchesChild(top.env, fromMaybe(s.genName, s.attrRefName), top.frame) -> fail() - | prodTraversal(p, s) when p.lookupValue.fullName != top.frame.fullName -> fail() - | rewriteRule(_, _, ml) when !ml.matchesFrame -> fail() - | strategyRef(n) when !n.matchesFrame -> fail() - | functorRef(n) when !n.matchesFrame -> fail() - | strategyRef(n) when n.matchesFrame && !n.attrDcl.isRecursive && null(n.attrDcl.givenRecVarEnv) -> n.attrDcl.strategyExpr - end <+ - rule on MRuleList of - | mRuleList_cons(h, _, t) when !h.matchesFrame -> t + | allTraversal(id()) -> id(location=top.location, genName=top.genName) + | someTraversal(fail()) -> fail(location=top.location, genName=top.genName) + | oneTraversal(fail()) -> fail(location=top.location, genName=top.genName) + | prodTraversal(_, s) when s.containsFail -> fail(location=top.location, genName=top.genName) + | prodTraversal(_, s) when s.allId -> id(location=top.location, genName=top.genName) + | recComb(n, s) when !containsBy(stringEq, n.name, s.freeRecVars) -> s end); +-- Frame-dependent optimizations +strategy attribute optimizeStep = + rule on top::StrategyExpr of + | allTraversal(s) when !attrMatchesChild(top.env, fromMaybe(s.genName, s.attrRefName), top.frame) -> id(location=top.location, genName=top.genName) + | someTraversal(s) when !attrMatchesChild(top.env, fromMaybe(s.genName, s.attrRefName), top.frame) -> fail(location=top.location, genName=top.genName) + | oneTraversal(s) when !attrMatchesChild(top.env, fromMaybe(s.genName, s.attrRefName), top.frame) -> fail(location=top.location, genName=top.genName) + | prodTraversal(p, s) when p.lookupValue.fullName != top.frame.fullName -> fail(location=top.location, genName=top.genName) + | rewriteRule(_, _, ml) when !ml.matchesFrame -> fail(location=top.location, genName=top.genName) + | strategyRef(n) when !n.matchesFrame -> fail(location=top.location, genName=top.genName) + | functorRef(n) when !n.matchesFrame -> fail(location=top.location, genName=top.genName) + --| strategyRef(n) when n.matchesFrame && !n.attrDcl.isRecursive && null(n.attrDcl.givenRecVarEnv) -> n.attrDcl.strategyExpr + end <+ + rule on MRuleList of + | mRuleList_cons(h, _, t) when !h.matchesFrame -> t + end; +strategy attribute optimize = + (sequence(optimize, id) <+ choice(optimize, optimize) <+ recComb(id, optimize)) <* + try(optimizeStep <* simplify); -} nonterminal StrategyExpr with @@ -56,7 +65,7 @@ nonterminal StrategyExpr with nonterminal StrategyExprs with config, grammarName, env, unparse, errors, frame, compiledGrammars, flowEnv, flowDefs, -- Normal expression stuff recVarEnv, liftedStrategies, attrRefNames, - freeRecVars; + containsFail, allId, freeRecVars; flowtype StrategyExpr = decorate {grammarName, config, recVarEnv, outerAttr}, -- NOT frame or env @@ -68,12 +77,12 @@ flowtype StrategyExprs = decorate {grammarName, config, recVarEnv}, -- NOT frame or env unparse {}, errors {decorate, frame, env, compiledGrammars, flowEnv}, flowDefs {decorate, frame, env, compiledGrammars, flowEnv}, liftedStrategies {decorate}, attrRefNames {decorate}, - freeRecVars {decorate, env}; + containsFail {decorate, env}, allId {decorate, env}, freeRecVars {decorate, env}; propagate errors on StrategyExpr, StrategyExprs excluding strategyRef, functorRef; propagate flowDefs on StrategyExpr, StrategyExprs; -propagate liftedStrategies on StrategyExprs; -propagate freeRecVars on StrategyExpr, StrategyExprs excluding rec; +propagate liftedStrategies, containsFail, allId on StrategyExprs; +propagate freeRecVars on StrategyExpr, StrategyExprs excluding recComb; aspect default production top::StrategyExpr ::= @@ -479,6 +488,9 @@ top::StrategyExprs ::= h::StrategyExpr t::StrategyExprs else [pair(h.genName, h)]; top.attrRefNames = fromMaybe(h.genName, h.attrRefName) :: t.attrRefNames; + top.containsFail <- case h of fail() -> true | _ -> false end; + top.allId <- case h of id() -> true | _ -> false end; + h.outerAttr = nothing(); } @@ -509,6 +521,25 @@ top::StrategyExpr ::= n::Name s::StrategyExpr then s.translation else Silver_Expr { $name{top.frame.signature.outputElement.elementName}.$name{s.genName} }; } +abstract production recComb +top::StrategyExpr ::= n::Name s::StrategyExpr +{ + top.unparse = s"rec ${n.name} -> (${s.unparse})"; + + top.liftedStrategies := + if top.outerAttr.isJust + then s.liftedStrategies + else [pair(s.genName, s)]; + top.freeRecVars := removeBy(stringEq, n.name, s.freeRecVars); + + s.recVarEnv = pair(n.name, fromMaybe(s.genName, top.outerAttr)) :: top.recVarEnv; + s.outerAttr = top.outerAttr; + + top.translation = + if top.outerAttr.isJust + then s.translation + else Silver_Expr { $name{top.frame.signature.outputElement.elementName}.$name{s.genName} }; +} -- Rules abstract production rewriteRule From aead2fd4e3a748ead3fa58dfa7a3445fe980d741 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Mon, 13 Apr 2020 16:25:27 -0500 Subject: [PATCH 28/78] Remove rec production --- .../extension/strategyattr/StrategyExpr.sv | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/grammars/silver/extension/strategyattr/StrategyExpr.sv b/grammars/silver/extension/strategyattr/StrategyExpr.sv index ebd60c0ed..3b7db0f57 100644 --- a/grammars/silver/extension/strategyattr/StrategyExpr.sv +++ b/grammars/silver/extension/strategyattr/StrategyExpr.sv @@ -502,25 +502,6 @@ top::StrategyExprs ::= } -- Recursive strategies -abstract production rec -top::StrategyExpr ::= n::Name s::StrategyExpr -{ - top.unparse = s"rec ${n.name} -> (${s.unparse})"; - - top.liftedStrategies := - if top.outerAttr.isJust - then s.liftedStrategies - else [pair(s.genName, s)]; - top.freeRecVars := removeBy(stringEq, n.name, s.freeRecVars); - - s.recVarEnv = pair(n.name, fromMaybe(s.genName, top.outerAttr)) :: top.recVarEnv; - s.outerAttr = top.outerAttr; - - top.translation = - if top.outerAttr.isJust - then s.translation - else Silver_Expr { $name{top.frame.signature.outputElement.elementName}.$name{s.genName} }; -} abstract production recComb top::StrategyExpr ::= n::Name s::StrategyExpr { From 9fdd946cbae6b7f99d1cee427f1923151dc5cca6 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Mon, 13 Apr 2020 17:04:00 -0500 Subject: [PATCH 29/78] Bug fix: don't propagate liftedStrategies for prod traversal arguments --- .../silver/extension/strategyattr/StrategyExpr.sv | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/grammars/silver/extension/strategyattr/StrategyExpr.sv b/grammars/silver/extension/strategyattr/StrategyExpr.sv index 3b7db0f57..150ee2b2c 100644 --- a/grammars/silver/extension/strategyattr/StrategyExpr.sv +++ b/grammars/silver/extension/strategyattr/StrategyExpr.sv @@ -81,7 +81,7 @@ flowtype StrategyExprs = propagate errors on StrategyExpr, StrategyExprs excluding strategyRef, functorRef; propagate flowDefs on StrategyExpr, StrategyExprs; -propagate liftedStrategies, containsFail, allId on StrategyExprs; +propagate containsFail, allId on StrategyExprs; propagate freeRecVars on StrategyExpr, StrategyExprs excluding recComb; aspect default production @@ -478,14 +478,15 @@ top::StrategyExprs ::= h::StrategyExpr t::StrategyExprs | _ -> [] end; - top.liftedStrategies <- + top.liftedStrategies := -- Slight hack: when h is id (common case for prod traversals), there is no need for a new attribute. -- However this can't be eliminated during the optumization phase. -- So, just don't lift the strategy, and we won't find the occurence of the non-existant attribute -- during translation - which means we will treat it as id anyway! - if h.attrRefName.isJust || h.isId - then [] - else [pair(h.genName, h)]; + (if h.attrRefName.isJust || h.isId + then [] + else [pair(h.genName, h)]) ++ + t.liftedStrategies; top.attrRefNames = fromMaybe(h.genName, h.attrRefName) :: t.attrRefNames; top.containsFail <- case h of fail() -> true | _ -> false end; @@ -498,6 +499,7 @@ abstract production nilStrategyExpr top::StrategyExprs ::= { top.unparse = ""; + top.liftedStrategies := []; top.attrRefNames = []; } From 4acd610ef9b01b64e5b15eb6fd75db376c13e0bd Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Mon, 13 Apr 2020 17:40:36 -0500 Subject: [PATCH 30/78] Better error messages for propagate --- grammars/silver/extension/autoattr/Propagate.sv | 2 +- test/silver_features/Monoid.sv | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/grammars/silver/extension/autoattr/Propagate.sv b/grammars/silver/extension/autoattr/Propagate.sv index 2e8a463b9..df8962182 100644 --- a/grammars/silver/extension/autoattr/Propagate.sv +++ b/grammars/silver/extension/autoattr/Propagate.sv @@ -69,7 +69,7 @@ top::AGDcl ::= d::DclInfo attrs::NameList top.errors := if null(forward.errors) then [] - else [nested(top.location, s"In propagate for production ${d.fullName}:", forward.errors)]; + else [nested(top.location, s"In propagate of ${attrs.unparse} for production ${d.fullName}:", forward.errors)]; forwards to aspectProductionDcl( diff --git a/test/silver_features/Monoid.sv b/test/silver_features/Monoid.sv index 390fac9ab..62b37a64b 100644 --- a/test/silver_features/Monoid.sv +++ b/test/silver_features/Monoid.sv @@ -50,7 +50,7 @@ top::Thing1 ::= Thing2 {} -- Test for both parts of 2-part error message -wrongCode "In propagate for production silver_features:thing2Thing1" { +wrongCode "In propagate of things for production silver_features:thing2Thing1" { propagate things on Thing1; } wrongCode "things has type [Integer] but the expression being assigned to it has type [Float]" { From 2195e753b368795070e537d938a6fa1ad1282f8b Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Mon, 13 Apr 2020 19:32:47 -0500 Subject: [PATCH 31/78] Improved version of quoteStrategyExpr, allow base genName for generated term to be specified at runtime --- .../extension/strategyattr/Construction.sv | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/grammars/silver/extension/strategyattr/Construction.sv b/grammars/silver/extension/strategyattr/Construction.sv index c1ff23c4d..4d27b6779 100644 --- a/grammars/silver/extension/strategyattr/Construction.sv +++ b/grammars/silver/extension/strategyattr/Construction.sv @@ -2,11 +2,12 @@ grammar silver:extension:strategyattr; import silver:reflect; import silver:metatranslation; +import silver:rewrite as s; terminal SilverStrategyExpr_t 'Silver_StrategyExpr' lexer classes {KEYWORD, RESERVED}; terminal AntiquoteStrategyExpr_t '$StrategyExpr' lexer classes {Antiquote, Strategy}; -concrete production quoteStrategyExpr +concrete production quoteStrategyExprOld top::Expr ::= 'Silver_StrategyExpr' genName::Name '{' cst::StrategyExpr_c '}' { top.unparse = s"Silver_StrategyExpr {${cst.unparse}}"; @@ -14,6 +15,21 @@ top::Expr ::= 'Silver_StrategyExpr' genName::Name '{' cst::StrategyExpr_c '}' forwards to translate(top.location, reflect(cst.ast)); } +concrete production quoteStrategyExpr +top::Expr ::= 'Silver_StrategyExpr' '(' genName::Expr ')' '{' cst::StrategyExpr_c '}' +{ + top.unparse = s"Silver_StrategyExpr {${cst.unparse}}"; + cst.givenGenName = ""; + forwards to + rewriteWith( + s:allTopDown( + rule on AnnoExpr of + | annoExpr(n, _, presentAppExpr(e), location=l) when n.name == "genName" -> + annoExpr(n, '=', presentAppExpr(plusPlus(genName, '++', e, location=l), location=l), location=l) + end), + translate(top.location, reflect(cst.ast))).fromJust; +} + concrete production antiquoteStrategyExpr_c top::StrategyExpr_c ::= '$StrategyExpr' '{' e::Expr '}' { From 9e0f38da11c25ceb40d30a0fedfa03bb8b553bf4 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Mon, 13 Apr 2020 19:44:47 -0500 Subject: [PATCH 32/78] Use new version of quoteStrategyExpr --- .../extension/strategyattr/Construction.sv | 16 ++++----- .../extension/strategyattr/StrategyUtils.sv | 34 +++++++++---------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/grammars/silver/extension/strategyattr/Construction.sv b/grammars/silver/extension/strategyattr/Construction.sv index 4d27b6779..f72913c7b 100644 --- a/grammars/silver/extension/strategyattr/Construction.sv +++ b/grammars/silver/extension/strategyattr/Construction.sv @@ -7,18 +7,18 @@ import silver:rewrite as s; terminal SilverStrategyExpr_t 'Silver_StrategyExpr' lexer classes {KEYWORD, RESERVED}; terminal AntiquoteStrategyExpr_t '$StrategyExpr' lexer classes {Antiquote, Strategy}; -concrete production quoteStrategyExprOld -top::Expr ::= 'Silver_StrategyExpr' genName::Name '{' cst::StrategyExpr_c '}' -{ - top.unparse = s"Silver_StrategyExpr {${cst.unparse}}"; - cst.givenGenName = genName.name ++ "_" ++ toString(genInt()); - forwards to translate(top.location, reflect(cst.ast)); -} - concrete production quoteStrategyExpr top::Expr ::= 'Silver_StrategyExpr' '(' genName::Expr ')' '{' cst::StrategyExpr_c '}' { top.unparse = s"Silver_StrategyExpr {${cst.unparse}}"; + -- The meta-translation library directly translates all annotation values into + -- static initialization code, however we want to specify genName at runtime. + -- Solution: construct the term with "" as the base genName and translate it + -- into an expression like normal, then use term rewriting to replace all all + -- occurences of `genName=$e` with `genName=$genName ++ $e`. + -- Confused yet? + -- A "simpler" approach would be to handle this in the meta-translation library + -- in one pass, but we want to keep that code as a generic library as much as possible. cst.givenGenName = ""; forwards to rewriteWith( diff --git a/grammars/silver/extension/strategyattr/StrategyUtils.sv b/grammars/silver/extension/strategyattr/StrategyUtils.sv index c39c9b5ab..7eaaa4e68 100644 --- a/grammars/silver/extension/strategyattr/StrategyUtils.sv +++ b/grammars/silver/extension/strategyattr/StrategyUtils.sv @@ -5,7 +5,7 @@ abstract production try top::StrategyExpr ::= s::StrategyExpr { forwards to - Silver_StrategyExpr try { + Silver_StrategyExpr (top.genName) { $StrategyExpr{s} <+ id }; } @@ -14,7 +14,7 @@ abstract production repeatS -- name clash with repeat from core top::StrategyExpr ::= s::StrategyExpr { forwards to - Silver_StrategyExpr repeat { + Silver_StrategyExpr (top.genName) { rec res -> try($StrategyExpr{s} <* res) }; } @@ -23,7 +23,7 @@ abstract production reduce top::StrategyExpr ::= s::StrategyExpr { forwards to - Silver_StrategyExpr reduce { + Silver_StrategyExpr (top.genName) { repeat(rec res -> some(res) <+ $StrategyExpr{s}) }; } @@ -32,7 +32,7 @@ abstract production bottomUp top::StrategyExpr ::= s::StrategyExpr { forwards to - Silver_StrategyExpr bottomUp { + Silver_StrategyExpr (top.genName) { rec res -> all(res) <* $StrategyExpr{s} }; } @@ -41,7 +41,7 @@ abstract production topDown top::StrategyExpr ::= s::StrategyExpr { forwards to - Silver_StrategyExpr topDown { + Silver_StrategyExpr (top.genName) { rec res -> $StrategyExpr{s} <* all(res) }; } @@ -50,7 +50,7 @@ abstract production downUp top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr { forwards to - Silver_StrategyExpr downUp { + Silver_StrategyExpr (top.genName) { rec res -> $StrategyExpr{s1} <* all(res) <* $StrategyExpr{s2} }; } @@ -59,7 +59,7 @@ abstract production allBottomUp top::StrategyExpr ::= s::StrategyExpr { forwards to - Silver_StrategyExpr allBottomUp { + Silver_StrategyExpr (top.genName) { rec res -> all(res) <+ $StrategyExpr{s} }; } @@ -68,7 +68,7 @@ abstract production allTopDown top::StrategyExpr ::= s::StrategyExpr { forwards to - Silver_StrategyExpr allTopDown { + Silver_StrategyExpr (top.genName) { rec res -> $StrategyExpr{s} <+ all(res) }; } @@ -77,7 +77,7 @@ abstract production allDownUp top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr { forwards to - Silver_StrategyExpr allDownUp { + Silver_StrategyExpr (top.genName) { rec res -> $StrategyExpr{s1} <+ all(res) <+ $StrategyExpr{s2} }; } @@ -86,7 +86,7 @@ abstract production someBottomUp top::StrategyExpr ::= s::StrategyExpr { forwards to - Silver_StrategyExpr someBottomUp { + Silver_StrategyExpr (top.genName) { rec res -> some(res) <+ $StrategyExpr{s} }; } @@ -95,7 +95,7 @@ abstract production someTopDown top::StrategyExpr ::= s::StrategyExpr { forwards to - Silver_StrategyExpr someTopDown { + Silver_StrategyExpr (top.genName) { rec res -> $StrategyExpr{s} <+ some(res) }; } @@ -104,7 +104,7 @@ abstract production someDownUp top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr { forwards to - Silver_StrategyExpr someDownUp { + Silver_StrategyExpr (top.genName) { rec res -> $StrategyExpr{s1} <+ some(res) <+ $StrategyExpr{s2} }; } @@ -113,7 +113,7 @@ abstract production onceBottomUp top::StrategyExpr ::= s::StrategyExpr { forwards to - Silver_StrategyExpr onceBottomUp { + Silver_StrategyExpr (top.genName) { rec res -> one(res) <+ $StrategyExpr{s} }; } @@ -122,7 +122,7 @@ abstract production onceTopDown top::StrategyExpr ::= s::StrategyExpr { forwards to - Silver_StrategyExpr onceTopDown { + Silver_StrategyExpr (top.genName) { rec res -> $StrategyExpr{s} <+ one(res) }; } @@ -131,7 +131,7 @@ abstract production onceDownUp top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr { forwards to - Silver_StrategyExpr onceDownUp { + Silver_StrategyExpr (top.genName) { rec res -> $StrategyExpr{s1} <+ one(res) <+ $StrategyExpr{s2} }; } @@ -140,7 +140,7 @@ abstract production innermost top::StrategyExpr ::= s::StrategyExpr { forwards to - Silver_StrategyExpr innermost { + Silver_StrategyExpr (top.genName) { rec res -> bottomUp(try($StrategyExpr{s} <* res)) }; } @@ -149,7 +149,7 @@ abstract production outermost top::StrategyExpr ::= s::StrategyExpr { forwards to - Silver_StrategyExpr outermost { + Silver_StrategyExpr (top.genName) { rec res -> topDown(try($StrategyExpr{s} <* res)) }; } From a4928c007c5aa46aff0b4e3b466191a4c54b0b19 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Mon, 13 Apr 2020 19:46:18 -0500 Subject: [PATCH 33/78] Trigger build --- grammars/silver/extension/strategyattr/Construction.sv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grammars/silver/extension/strategyattr/Construction.sv b/grammars/silver/extension/strategyattr/Construction.sv index f72913c7b..571c43ee2 100644 --- a/grammars/silver/extension/strategyattr/Construction.sv +++ b/grammars/silver/extension/strategyattr/Construction.sv @@ -18,7 +18,7 @@ top::Expr ::= 'Silver_StrategyExpr' '(' genName::Expr ')' '{' cst::StrategyExpr_ -- occurences of `genName=$e` with `genName=$genName ++ $e`. -- Confused yet? -- A "simpler" approach would be to handle this in the meta-translation library - -- in one pass, but we want to keep that code as a generic library as much as possible. + -- in one pass, but we want to keep that code as a generic library as much as possible. cst.givenGenName = ""; forwards to rewriteWith( From eaea1d5863506c4264ddf0c257da6607acb42e80 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Mon, 13 Apr 2020 20:26:52 -0500 Subject: [PATCH 34/78] Add printTerm debugging strategy --- .../extension/strategyattr/ConcreteSyntax.sv | 5 +++++ .../extension/strategyattr/StrategyUtils.sv | 20 +++++++++++++++++++ .../extension/strategyattr/Terminals.sv | 1 + 3 files changed, 26 insertions(+) diff --git a/grammars/silver/extension/strategyattr/ConcreteSyntax.sv b/grammars/silver/extension/strategyattr/ConcreteSyntax.sv index 1ca9f29b4..6ca04e2e5 100644 --- a/grammars/silver/extension/strategyattr/ConcreteSyntax.sv +++ b/grammars/silver/extension/strategyattr/ConcreteSyntax.sv @@ -89,6 +89,11 @@ concrete productions top::StrategyExpr_c top.ast = s.ast; s.givenGenName = top.givenGenName; } +| 'printTerm' +{ + top.unparse = s"printTerm"; + top.ast = printTerm(genName=top.givenGenName, location=top.location); +} | 'try' '(' s::StrategyExpr_c ')' { top.unparse = s"try(${s.unparse})"; diff --git a/grammars/silver/extension/strategyattr/StrategyUtils.sv b/grammars/silver/extension/strategyattr/StrategyUtils.sv index 7eaaa4e68..2c1297ad3 100644 --- a/grammars/silver/extension/strategyattr/StrategyUtils.sv +++ b/grammars/silver/extension/strategyattr/StrategyUtils.sv @@ -1,5 +1,25 @@ grammar silver:extension:strategyattr; +import silver:metatranslation; +import silver:modification:copper; -- print keyword + +-- Debugging +abstract production printTerm +top::StrategyExpr ::= +{ + top.unparse = s"printTerm"; + + propagate liftedStrategies; + top.translation = + Silver_Expr { + core:unsafeTrace( + core:just($name{top.frame.signature.outputElement.elementName}), + core:print( + hackUnparse($name{top.frame.signature.outputElement.elementName}) ++ "\n\n", + core:unsafeIO())) + }; +} + -- Utilities abstract production try top::StrategyExpr ::= s::StrategyExpr diff --git a/grammars/silver/extension/strategyattr/Terminals.sv b/grammars/silver/extension/strategyattr/Terminals.sv index 373aee77d..6483e45eb 100644 --- a/grammars/silver/extension/strategyattr/Terminals.sv +++ b/grammars/silver/extension/strategyattr/Terminals.sv @@ -15,6 +15,7 @@ terminal One_t 'one' lexer classes {KEYWORD, Strategy}; terminal Rule_t 'rule' lexer classes {KEYWORD, Strategy}; terminal Rec_t 'rec' lexer classes {KEYWORD, Strategy}; +terminal PrintTerm_t 'printTerm' lexer classes {KEYWORD, Strategy}; terminal Try_t 'try' lexer classes {KEYWORD, Strategy}; terminal Repeat_t 'repeat' lexer classes {KEYWORD, Strategy}; terminal Reduce_t 'reduce' lexer classes {KEYWORD, Strategy}; From 50939e71bfdf17a1cffa54d23c4fc876c395580e Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Mon, 13 Apr 2020 20:45:39 -0500 Subject: [PATCH 35/78] Avoid duplicate genNames with e.g. (a <* b) <* c --- grammars/silver/extension/strategyattr/ConcreteSyntax.sv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/grammars/silver/extension/strategyattr/ConcreteSyntax.sv b/grammars/silver/extension/strategyattr/ConcreteSyntax.sv index 6ca04e2e5..00a791a65 100644 --- a/grammars/silver/extension/strategyattr/ConcreteSyntax.sv +++ b/grammars/silver/extension/strategyattr/ConcreteSyntax.sv @@ -27,8 +27,8 @@ concrete productions top::StrategyExpr_c { top.unparse = s"(${s1.unparse} <* ${s2.unparse})"; top.ast = sequence(s1.ast, s2.ast, genName=top.givenGenName, location=top.location); - s1.givenGenName = top.givenGenName; - s2.givenGenName = top.givenGenName ++ "_cont"; + s1.givenGenName = top.givenGenName ++ "_fst"; + s2.givenGenName = top.givenGenName ++ "_snd"; } | s1::StrategyExpr_c '<+' s2::StrategyExpr_c { From 6004f89b00c227d3fbb9f027600152deb30f0814 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Tue, 14 Apr 2020 13:29:05 -0500 Subject: [PATCH 36/78] Fix error message location --- grammars/silver/extension/rewriting/Expr.sv | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/grammars/silver/extension/rewriting/Expr.sv b/grammars/silver/extension/rewriting/Expr.sv index a119d6998..f9429b551 100644 --- a/grammars/silver/extension/rewriting/Expr.sv +++ b/grammars/silver/extension/rewriting/Expr.sv @@ -36,7 +36,11 @@ top::Expr ::= q::Decorated QName _ _ Silver_Expr { silver:rewrite:anyASTExpr( \ e::$TypeExpr{typerepTypeExpr(finalType(top).decoratedType, location=builtin)} -> - decorate e with {}) + $Expr{ + decorateExprWith( + 'decorate', Silver_Expr { e }, 'with', + '{', exprInhsEmpty(location=top.location), '}', + location=top.location)}) }), consASTExpr(varASTExpr(q.name), nilASTExpr()), nilNamedASTExpr()) @@ -51,7 +55,7 @@ top::Expr ::= q::Decorated QName _ _ }), consASTExpr(varASTExpr(q.name), nilASTExpr()), nilNamedASTExpr()) - -- Neither the bound value nor desired type is a decorated nonterminal - just return the value + -- Both (or neither) the bound value/desired type is a decorated nonterminal - just return the value else varASTExpr(q.name) | nothing() -> -- The variable is bound in an enclosing let/match From 2e4310bee7e885966f4b693d94a5bd741a3b4355 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Tue, 14 Apr 2020 14:46:09 -0500 Subject: [PATCH 37/78] Bug fixes to avoid flow errors in rewriting translation --- grammars/silver/extension/rewriting/Expr.sv | 53 ++++++++++++++++----- 1 file changed, 42 insertions(+), 11 deletions(-) diff --git a/grammars/silver/extension/rewriting/Expr.sv b/grammars/silver/extension/rewriting/Expr.sv index f9429b551..b5bf47b19 100644 --- a/grammars/silver/extension/rewriting/Expr.sv +++ b/grammars/silver/extension/rewriting/Expr.sv @@ -2,6 +2,7 @@ grammar silver:extension:rewriting; -- Environment mapping variables that were defined on the rule RHS to Booleans indicating whether -- the variable was explicitly (i.e. not implicitly) decorated in the pattern. +-- TODO: Lots of flow errors in this grammar because we are pretending this attribute is in the reference set autocopy attribute boundVars::[Pair] occurs on Expr, Exprs, ExprInhs, ExprInh, AppExprs, AppExpr, AnnoAppExprs, AnnoExpr, AssignExpr, PrimPatterns, PrimPattern; attribute transform occurs on Expr; @@ -37,9 +38,8 @@ top::Expr ::= q::Decorated QName _ _ silver:rewrite:anyASTExpr( \ e::$TypeExpr{typerepTypeExpr(finalType(top).decoratedType, location=builtin)} -> $Expr{ - decorateExprWith( - 'decorate', Silver_Expr { e }, 'with', - '{', exprInhsEmpty(location=top.location), '}', + decorateExprWithEmpty( + 'decorate', Silver_Expr { e }, 'with', '{', '}', location=top.location)}) }), consASTExpr(varASTExpr(q.name), nilASTExpr()), @@ -189,14 +189,45 @@ aspect production synDecoratedAccessHandler top::Expr ::= e::Decorated Expr q::Decorated QNameAttrOccur { top.transform = - applyASTExpr( - antiquoteASTExpr( - Silver_Expr { - silver:rewrite:anyASTExpr( - \ e::$TypeExpr{typerepTypeExpr(finalType(e), location=builtin)} -> e.$qName{q.name}) - }), - consASTExpr(e.transform, nilASTExpr()), - nilNamedASTExpr()); + case e of + -- Special cases to avoid introducing a reference and causing flow errors. + | decorateExprWith(_, eUndec, _, _, inhs, _) -> + applyASTExpr( + antiquoteASTExpr( + Silver_Expr { + silver:rewrite:anyASTExpr( + \ e::$TypeExpr{typerepTypeExpr(finalType(eUndec), location=builtin)} -> + $Expr{ + decorateExprWith( + 'decorate', Silver_Expr { e }, 'with', + '{', inhs, '}', + location=top.location)}.$qName{q.name}) + }), + consASTExpr(eUndec.transform, nilASTExpr()), + nilNamedASTExpr()) + | lexicalLocalReference(qn, _, _) when + case lookupBy(stringEq, qn.name, top.boundVars) of + | just(bindingIsDecorated) -> !bindingIsDecorated + | nothing() -> false + end -> + applyASTExpr( + antiquoteASTExpr( + Silver_Expr { + silver:rewrite:anyASTExpr( + \ e::$TypeExpr{typerepTypeExpr(finalType(e).decoratedType, location=builtin)} -> e.$qName{q.name}) + }), + consASTExpr(varASTExpr(qn.name), nilASTExpr()), + nilNamedASTExpr()) + | _ -> + applyASTExpr( + antiquoteASTExpr( + Silver_Expr { + silver:rewrite:anyASTExpr( + \ e::$TypeExpr{typerepTypeExpr(finalType(e), location=builtin)} -> e.$qName{q.name}) + }), + consASTExpr(e.transform, nilASTExpr()), + nilNamedASTExpr()) + end; } aspect production inhDecoratedAccessHandler From ca7bf51aad64c975e87f2553bd1e982a636be026 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Tue, 14 Apr 2020 15:05:20 -0500 Subject: [PATCH 38/78] Fix bug in last commit --- grammars/silver/extension/rewriting/Expr.sv | 27 +++++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/grammars/silver/extension/rewriting/Expr.sv b/grammars/silver/extension/rewriting/Expr.sv index b5bf47b19..b916855fe 100644 --- a/grammars/silver/extension/rewriting/Expr.sv +++ b/grammars/silver/extension/rewriting/Expr.sv @@ -191,19 +191,30 @@ top::Expr ::= e::Decorated Expr q::Decorated QNameAttrOccur top.transform = case e of -- Special cases to avoid introducing a reference and causing flow errors. - | decorateExprWith(_, eUndec, _, _, inhs, _) -> + | decorateExprWith(_, eUndec, _, _, inh, _) -> applyASTExpr( antiquoteASTExpr( Silver_Expr { silver:rewrite:anyASTExpr( - \ e::$TypeExpr{typerepTypeExpr(finalType(eUndec), location=builtin)} -> - $Expr{ - decorateExprWith( - 'decorate', Silver_Expr { e }, 'with', - '{', inhs, '}', - location=top.location)}.$qName{q.name}) + $Expr{ + lambdap( + productionRHSCons( + productionRHSElem( + name("_e", builtin), '::', + typerepTypeExpr(finalType(eUndec), location=builtin), + location=builtin), + inh.lambdaParams, + location=builtin), + Silver_Expr { + $Expr{ + decorateExprWith( + 'decorate', baseExpr(qName(builtin, "_e"), location=builtin), + 'with', '{', inh.bodyExprInhTransform, '}', + location=builtin)}.$qName{q.name} + }, + location=builtin)}) }), - consASTExpr(eUndec.transform, nilASTExpr()), + consASTExpr(eUndec.transform, inh.transform), nilNamedASTExpr()) | lexicalLocalReference(qn, _, _) when case lookupBy(stringEq, qn.name, top.boundVars) of From fbb806acea2cd7ae935bf9862d28c7f657569169 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Tue, 14 Apr 2020 15:06:19 -0500 Subject: [PATCH 39/78] Use strategy attribute to optimize StrategyExprs before translation --- .../silver/extension/strategyattr/Strategy.sv | 60 +++++--- .../extension/strategyattr/StrategyExpr.sv | 139 ++++++++++-------- 2 files changed, 119 insertions(+), 80 deletions(-) diff --git a/grammars/silver/extension/strategyattr/Strategy.sv b/grammars/silver/extension/strategyattr/Strategy.sv index e941d602f..346c77317 100644 --- a/grammars/silver/extension/strategyattr/Strategy.sv +++ b/grammars/silver/extension/strategyattr/Strategy.sv @@ -35,7 +35,7 @@ top::AGDcl ::= a::Name recVarEnv::[Pair] e::StrategyExpr e.recVarEnv = recVarEnv; e.outerAttr = just(a.name); - forwards to-- unsafeTrace( + local fwrd::AGDcl = foldr( appendAGDcl(_, _, location=top.location), defsAGDcl( @@ -48,8 +48,10 @@ top::AGDcl ::= a::Name recVarEnv::[Pair] e::StrategyExpr map( \ d::Pair -> strategyAttributeDcl(name(d.fst, top.location), d.snd.recVarEnv, new(d.snd), location=top.location), - e.liftedStrategies));--, - --print(a.name ++ " = " ++ e.unparse ++ "; lifted " ++ implode(", ", map(fst, e.liftedStrategies)) ++ "\n\n", unsafeIO())); + e.liftedStrategies)); + + --forwards to unsafeTrace(fwrd, print(a.name ++ " = " ++ e.unparse ++ "; lifted " ++ implode(", ", map(fst, e.liftedStrategies)) ++ "\n\n", unsafeIO())); + forwards to fwrd; } abstract production strategyAttributionDcl @@ -102,22 +104,40 @@ top::ProductionStmt ::= attr::Decorated QName e.recVarEnv = attr.lookupAttribute.dcl.givenRecVarEnv; e.outerAttr = just(attr.lookupAttribute.fullName); - forwards to + production e2::StrategyExpr = + case e.optimize of + | just(e2) -> e2 + | nothing() -> error("optimize failed for " ++ e.unparse) + end; + e2.grammarName = e.grammarName; + e2.config = e.config; + e2.frame = e.frame; + e2.env = e.env; + e2.recVarEnv = e.recVarEnv; + e2.outerAttr = e.outerAttr; + + -- Can't do this with forwarding to avoid circular dependency of + -- forward -> dcl.containsErrors -> dcl.flowEnv -> forward.flowDefs + top.errors := if attr.lookupAttribute.dcl.containsErrors - then errorProductionStmt([], location=top.location) - else-- unsafeTrace( - foldr( - productionStmtAppend(_, _, location=top.location), - attributeDef( - concreteDefLHS(qName(top.location, top.frame.signature.outputElement.elementName), location=top.location), - '.', - qNameAttrOccur(new(attr), location=top.location), - '=', - e.translation, - ';', - location=top.location), - map( - \ n::String -> propagateOneAttr(qName(top.location, n), location=top.location), - attr.lookupAttribute.dcl.liftedStrategyNames));--, - --print(attr.name ++ " on " ++ top.frame.fullName ++ " = " ++ e.translation.unparse ++ ";\n\n", unsafeIO())); + then [] + else forward.errors; + + local fwrd::ProductionStmt = + foldr( + productionStmtAppend(_, _, location=top.location), + attributeDef( + concreteDefLHS(qName(top.location, top.frame.signature.outputElement.elementName), location=top.location), + '.', + qNameAttrOccur(new(attr), location=top.location), + '=', + e2.translation, + ';', + location=top.location), + map( + \ n::String -> propagateOneAttr(qName(top.location, n), location=top.location), + attr.lookupAttribute.dcl.liftedStrategyNames)); + + --forwards to unsafeTrace(fwrd, print(attr.name ++ " on " ++ top.frame.fullName ++ " = " ++ e2.translation.unparse ++ ";\n\n", unsafeIO())); + forwards to fwrd; } diff --git a/grammars/silver/extension/strategyattr/StrategyExpr.sv b/grammars/silver/extension/strategyattr/StrategyExpr.sv index 150ee2b2c..965034353 100644 --- a/grammars/silver/extension/strategyattr/StrategyExpr.sv +++ b/grammars/silver/extension/strategyattr/StrategyExpr.sv @@ -10,33 +10,34 @@ inherited attribute outerAttr::Maybe; monoid attribute liftedStrategies::[Pair] with [], ++; synthesized attribute attrRefName::Maybe; synthesized attribute isId::Boolean; -synthesized attribute attrRefNames::[String]; +inherited attribute givenInputElements::[NamedSignatureElement]; +synthesized attribute attrRefNames::[Maybe]; monoid attribute containsFail::Boolean with false, ||; monoid attribute allId::Boolean with true, &&; monoid attribute matchesFrame::Boolean with false, ||; monoid attribute freeRecVars::[String] with [], ++; synthesized attribute translation::a; -{- + -- Frame-independent algebraic simplifications -strategy attribute simplify = - innermost( - rule on top::StrategyExpr of - | sequence(fail(), _) -> fail(location=top.location, genName=top.genName) - | sequence(_, fail()) -> fail(location=top.location, genName=top.genName) - | sequence(id(), s) -> s - | sequence(s, id()) -> s - | choice(fail(), s) -> s - | choice(s, fail()) -> s - | choice(id(), s) -> id(location=top.location, genName=top.genName) - | choice(functorRef(n, genName=g, location=l), s) -> functorRef(n, genName=g, location=l) - | allTraversal(id()) -> id(location=top.location, genName=top.genName) - | someTraversal(fail()) -> fail(location=top.location, genName=top.genName) - | oneTraversal(fail()) -> fail(location=top.location, genName=top.genName) - | prodTraversal(_, s) when s.containsFail -> fail(location=top.location, genName=top.genName) - | prodTraversal(_, s) when s.allId -> id(location=top.location, genName=top.genName) - | recComb(n, s) when !containsBy(stringEq, n.name, s.freeRecVars) -> s - end); +strategy attribute simplifyStep = + rule on top::StrategyExpr of + | sequence(fail(), _) -> fail(location=top.location, genName=top.genName) + | sequence(_, fail()) -> fail(location=top.location, genName=top.genName) + | sequence(id(), s) -> s + | sequence(s, id()) -> s + | choice(fail(), s) -> s + | choice(s, fail()) -> s + | choice(id(), s) -> id(location=top.location, genName=top.genName) + | choice(functorRef(n, genName=g, location=l), s) -> functorRef(n, genName=g, location=l) + | allTraversal(id()) -> id(location=top.location, genName=top.genName) + | someTraversal(fail()) -> fail(location=top.location, genName=top.genName) + | oneTraversal(fail()) -> fail(location=top.location, genName=top.genName) + | prodTraversal(_, s) when s.containsFail -> fail(location=top.location, genName=top.genName) + | prodTraversal(_, s) when s.allId -> id(location=top.location, genName=top.genName) + | recComb(n, s) when !containsBy(stringEq, n.name, s.freeRecVars) -> s + end; +strategy attribute simplify = innermost(simplifyStep); -- Frame-dependent optimizations strategy attribute optimizeStep = rule on top::StrategyExpr of @@ -49,23 +50,35 @@ strategy attribute optimizeStep = | functorRef(n) when !n.matchesFrame -> fail(location=top.location, genName=top.genName) --| strategyRef(n) when n.matchesFrame && !n.attrDcl.isRecursive && null(n.attrDcl.givenRecVarEnv) -> n.attrDcl.strategyExpr end <+ - rule on MRuleList of - | mRuleList_cons(h, _, t) when !h.matchesFrame -> t - end; + rewriteRule( + id, id, + onceBottomUp( + rule on MRuleList of + | mRuleList_cons(h, _, t) when !h.matchesFrame -> t + end)); +attribute optimizeStep occurs on MRuleList; strategy attribute optimize = - (sequence(optimize, id) <+ choice(optimize, optimize) <+ recComb(id, optimize)) <* - try(optimizeStep <* simplify); --} + (sequence(optimize, simplify) <+ + choice(optimize, optimize) <+ + allTraversal(simplify) <+ + someTraversal(simplify) <+ + oneTraversal(simplify) <+ + prodTraversal(id, simplify) <+ + recComb(id, optimize) <+ + id) <* + try((optimizeStep <+ simplifyStep) <* optimize); nonterminal StrategyExpr with config, grammarName, env, location, unparse, errors, frame, compiledGrammars, flowEnv, flowDefs, -- Normal expression stuff genName, recVarEnv, outerAttr, liftedStrategies, attrRefName, isId, - translation, matchesFrame, freeRecVars; + translation, matchesFrame, freeRecVars, + simplifyStep, simplify, optimizeStep, optimize; nonterminal StrategyExprs with config, grammarName, env, unparse, errors, frame, compiledGrammars, flowEnv, flowDefs, -- Normal expression stuff - recVarEnv, liftedStrategies, attrRefNames, - containsFail, allId, freeRecVars; + recVarEnv, givenInputElements, liftedStrategies, attrRefNames, + containsFail, allId, freeRecVars, + simplify; flowtype StrategyExpr = decorate {grammarName, config, recVarEnv, outerAttr}, -- NOT frame or env @@ -75,14 +88,17 @@ flowtype StrategyExpr = flowtype StrategyExprs = decorate {grammarName, config, recVarEnv}, -- NOT frame or env - unparse {}, errors {decorate, frame, env, compiledGrammars, flowEnv}, flowDefs {decorate, frame, env, compiledGrammars, flowEnv}, - liftedStrategies {decorate}, attrRefNames {decorate}, + unparse {}, errors {decorate, frame, env, givenInputElements, compiledGrammars, flowEnv}, flowDefs {decorate, frame, env, compiledGrammars, flowEnv}, + liftedStrategies {decorate}, attrRefNames {decorate, env, givenInputElements}, containsFail {decorate, env}, allId {decorate, env}, freeRecVars {decorate, env}; propagate errors on StrategyExpr, StrategyExprs excluding strategyRef, functorRef; propagate flowDefs on StrategyExpr, StrategyExprs; propagate containsFail, allId on StrategyExprs; propagate freeRecVars on StrategyExpr, StrategyExprs excluding recComb; +propagate simplify on StrategyExprs; +propagate optimizeStep on MRuleList; +propagate simplifyStep, simplify, optimizeStep, optimize on StrategyExpr; aspect default production top::StrategyExpr ::= @@ -403,7 +419,7 @@ top::StrategyExpr ::= prod::QName s::StrategyExprs { top.unparse = s"${prod.unparse}(${s.unparse})"; - local numParams::Integer = length(prod.lookupValue.dcl.namedSignature.inputElements); + local numParams::Integer = length(s.givenInputElements); local numArgs::Integer = length(s.attrRefNames); top.errors <- if numArgs != numParams @@ -412,13 +428,11 @@ top::StrategyExpr ::= prod::QName s::StrategyExprs propagate liftedStrategies; - -- pair(pair(child name, attr name), attr occurs on child) - local childAccesses::[Pair Boolean>] = - zipWith( - \ e::NamedSignatureElement attr::String -> - pair(pair(e.elementName, attr), attrMatchesFrame(top.env, attr, e.typerep)), - top.frame.signature.inputElements, - s.attrRefNames); + s.givenInputElements = prod.lookupValue.dcl.namedSignature.inputElements; + + -- pair(child name, if attr occurs on child then just(attr name) else nothing()) + local childAccesses::[Pair>] = + zipWith(pair, top.frame.signature.inputNames, s.attrRefNames); top.translation = if prod.lookupValue.fullName == top.frame.fullName then @@ -430,17 +444,18 @@ top::StrategyExpr ::= prod::QName s::StrategyExprs Could also be implemented as chained monadic binds. Maybe more efficient this way? -} caseExpr( flatMap( - \ a::Pair Boolean> -> - if a.snd then [Silver_Expr { $name{a.fst.fst}.$name{a.fst.snd} }] else [], + \ a::Pair> -> + case a.snd of just(attr) -> [Silver_Expr { $name{a.fst}.$name{attr} }] | nothing() -> [] end, childAccesses), [matchRule( flatMap( - \ a::Pair Boolean> -> - if a.snd - then - [decorate Silver_Pattern { core:just($name{a.fst.fst ++ "_" ++ last(explode(":", a.fst.snd))}) } + \ a::Pair> -> + case a.snd of + | just(attr) -> + [decorate Silver_Pattern { core:just($name{a.fst ++ "_" ++ last(explode(":", attr))}) } with { config = top.config; env = top.env; frame = top.frame; patternVarEnv = []; }] - else [], + | nothing() -> [] + end, childAccesses), nothing(), Silver_Expr { @@ -450,10 +465,11 @@ top::StrategyExpr ::= prod::QName s::StrategyExprs top.location, baseExpr(qName(top.location, top.frame.fullName), location=top.location), map( - \ a::Pair Boolean> -> - if a.snd - then Silver_Expr { $name{a.fst.fst ++ "_" ++ last(explode(":", a.fst.snd))} } - else Silver_Expr { $name{a.fst.fst} }, + \ a::Pair> -> + case a.snd of + | just(attr) -> Silver_Expr { $name{a.fst ++ "_" ++ last(explode(":", attr))} } + | nothing() -> Silver_Expr { $name{a.fst} } + end, childAccesses), map( makeAnnoArg(top.location, top.frame.signature.outputElement.elementName, _), @@ -477,7 +493,7 @@ top::StrategyExprs ::= h::StrategyExpr t::StrategyExprs | functorRef(_) -> [err(h.location, "Functor attributes as arguments to production traversals are not yet supported")] | _ -> [] end; - + top.liftedStrategies := -- Slight hack: when h is id (common case for prod traversals), there is no need for a new attribute. -- However this can't be eliminated during the optumization phase. @@ -487,12 +503,21 @@ top::StrategyExprs ::= h::StrategyExpr t::StrategyExprs then [] else [pair(h.genName, h)]) ++ t.liftedStrategies; - top.attrRefNames = fromMaybe(h.genName, h.attrRefName) :: t.attrRefNames; + local hType::Type = head(top.givenInputElements).typerep; + local attr::String = fromMaybe(h.genName, h.attrRefName); + local attrMatch::Boolean = attrMatchesFrame(top.env, attr, hType); + top.attrRefNames = (if attrMatch && !h.isId then just(attr) else nothing()) :: t.attrRefNames; + top.errors <- + if !null(top.givenInputElements) && !attrMatch && !h.isId + then [wrn(h.location, s"This (non-identity) strategy attribute does not occur on ${prettyType(hType)} and will be treated as identity")] + else []; top.containsFail <- case h of fail() -> true | _ -> false end; top.allId <- case h of id() -> true | _ -> false end; h.outerAttr = nothing(); + t.givenInputElements = + if !null(top.givenInputElements) then tail(top.givenInputElements) else []; } abstract production nilStrategyExpr @@ -597,19 +622,13 @@ attribute translation<[AbstractMatchRule]> occurs on MRuleList; aspect production mRuleList_one top::MRuleList ::= m::MatchRule { - top.translation = - if m.matchesFrame - then [m.translation] - else []; + top.translation = [m.translation]; } aspect production mRuleList_cons top::MRuleList ::= h::MatchRule '|' t::MRuleList { - top.translation = - if h.matchesFrame - then h.translation :: t.translation - else t.translation; + top.translation = h.translation :: t.translation; } attribute translation occurs on MatchRule; From 610cb08c1d3b73a8771307f60d14fa0ba2ebe1f3 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Tue, 14 Apr 2020 16:22:57 -0500 Subject: [PATCH 40/78] Bug fix: allow last clause in a rule to be eliminated when not applicable --- grammars/silver/extension/strategyattr/StrategyExpr.sv | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/grammars/silver/extension/strategyattr/StrategyExpr.sv b/grammars/silver/extension/strategyattr/StrategyExpr.sv index 965034353..34764be08 100644 --- a/grammars/silver/extension/strategyattr/StrategyExpr.sv +++ b/grammars/silver/extension/strategyattr/StrategyExpr.sv @@ -53,8 +53,9 @@ strategy attribute optimizeStep = rewriteRule( id, id, onceBottomUp( - rule on MRuleList of + rule on top::MRuleList of | mRuleList_cons(h, _, t) when !h.matchesFrame -> t + | mRuleList_cons(h, _, mRuleList_one(t)) when !t.matchesFrame -> mRuleList_one(h, location=top.location) end)); attribute optimizeStep occurs on MRuleList; strategy attribute optimize = From 5b3871bcf0809c38528deb9176a7b11a431813fa Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Tue, 14 Apr 2020 17:10:50 -0500 Subject: [PATCH 41/78] Perform inlining of simple strategies during optimization --- .../silver/extension/strategyattr/DclInfo.sv | 5 ++++- .../silver/extension/strategyattr/Strategy.sv | 2 +- .../extension/strategyattr/StrategyExpr.sv | 18 +++++++++++++----- .../rewrite/expreval/AbstractSyntax.sv | 2 +- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/grammars/silver/extension/strategyattr/DclInfo.sv b/grammars/silver/extension/strategyattr/DclInfo.sv index 589349f14..00ff2267e 100644 --- a/grammars/silver/extension/strategyattr/DclInfo.sv +++ b/grammars/silver/extension/strategyattr/DclInfo.sv @@ -1,6 +1,7 @@ grammar silver:extension:strategyattr; synthesized attribute containsErrors::Boolean occurs on DclInfo; +attribute isRecursive occurs on DclInfo; synthesized attribute liftedStrategyNames::[String] occurs on DclInfo; synthesized attribute givenRecVarEnv::[Pair] occurs on DclInfo; synthesized attribute strategyExpr :: StrategyExpr occurs on DclInfo; @@ -9,6 +10,7 @@ aspect default production top::DclInfo ::= { top.containsErrors = false; + top.isRecursive := false; top.liftedStrategyNames = []; top.givenRecVarEnv = []; top.strategyExpr = error("Internal compiler error: must be defined for all strategy attribute declarations"); @@ -17,7 +19,7 @@ top::DclInfo ::= abstract production strategyDcl top::DclInfo ::= sg::String sl::Location fn::String tyVar::TyVar - containsErrors::Boolean liftedStrategyNames::[String] givenRecVarEnv::[Pair] + containsErrors::Boolean isRecursive::Boolean liftedStrategyNames::[String] givenRecVarEnv::[Pair] e::StrategyExpr { top.sourceGrammar = sg; @@ -35,6 +37,7 @@ top::DclInfo ::= top.propagateDispatcher = propagateStrategy(_, location=_); top.containsErrors = containsErrors; + top.isRecursive := isRecursive; top.liftedStrategyNames = liftedStrategyNames; top.givenRecVarEnv = givenRecVarEnv; top.strategyExpr = e; diff --git a/grammars/silver/extension/strategyattr/Strategy.sv b/grammars/silver/extension/strategyattr/Strategy.sv index 346c77317..e0f4ae387 100644 --- a/grammars/silver/extension/strategyattr/Strategy.sv +++ b/grammars/silver/extension/strategyattr/Strategy.sv @@ -43,7 +43,7 @@ top::AGDcl ::= a::Name recVarEnv::[Pair] e::StrategyExpr defaultEnvItem( strategyDcl( top.grammarName, a.location, fName, freshTyVar(), - !null(top.errors), map(fst, e.liftedStrategies), recVarEnv, e)))], + !null(top.errors), e.isRecursive, map(fst, e.liftedStrategies), recVarEnv, e)))], location=top.location), map( \ d::Pair -> diff --git a/grammars/silver/extension/strategyattr/StrategyExpr.sv b/grammars/silver/extension/strategyattr/StrategyExpr.sv index 34764be08..7e4669ffd 100644 --- a/grammars/silver/extension/strategyattr/StrategyExpr.sv +++ b/grammars/silver/extension/strategyattr/StrategyExpr.sv @@ -16,6 +16,7 @@ monoid attribute containsFail::Boolean with false, ||; monoid attribute allId::Boolean with true, &&; monoid attribute matchesFrame::Boolean with false, ||; monoid attribute freeRecVars::[String] with [], ++; +monoid attribute isRecursive::Boolean with false, ||; synthesized attribute translation::a; @@ -48,7 +49,7 @@ strategy attribute optimizeStep = | rewriteRule(_, _, ml) when !ml.matchesFrame -> fail(location=top.location, genName=top.genName) | strategyRef(n) when !n.matchesFrame -> fail(location=top.location, genName=top.genName) | functorRef(n) when !n.matchesFrame -> fail(location=top.location, genName=top.genName) - --| strategyRef(n) when n.matchesFrame && !n.attrDcl.isRecursive && null(n.attrDcl.givenRecVarEnv) -> n.attrDcl.strategyExpr + | strategyRef(n) when n.matchesFrame && !n.attrDcl.isRecursive && null(n.attrDcl.givenRecVarEnv) -> n.attrDcl.strategyExpr end <+ rewriteRule( id, id, @@ -72,31 +73,32 @@ strategy attribute optimize = nonterminal StrategyExpr with config, grammarName, env, location, unparse, errors, frame, compiledGrammars, flowEnv, flowDefs, -- Normal expression stuff genName, recVarEnv, outerAttr, liftedStrategies, attrRefName, isId, - translation, matchesFrame, freeRecVars, + translation, matchesFrame, freeRecVars, isRecursive, simplifyStep, simplify, optimizeStep, optimize; nonterminal StrategyExprs with config, grammarName, env, unparse, errors, frame, compiledGrammars, flowEnv, flowDefs, -- Normal expression stuff recVarEnv, givenInputElements, liftedStrategies, attrRefNames, - containsFail, allId, freeRecVars, + containsFail, allId, freeRecVars, isRecursive, simplify; flowtype StrategyExpr = decorate {grammarName, config, recVarEnv, outerAttr}, -- NOT frame or env unparse {}, errors {decorate, frame, env, compiledGrammars, flowEnv}, flowDefs {decorate, frame, env, compiledGrammars, flowEnv}, liftedStrategies {decorate}, attrRefName {decorate}, isId {decorate}, - translation {decorate, frame, env}, matchesFrame {decorate, frame, env}, freeRecVars {decorate, env}; + translation {decorate, frame, env}, matchesFrame {decorate, frame, env}, freeRecVars {decorate, env}, isRecursive {decorate, env}; flowtype StrategyExprs = decorate {grammarName, config, recVarEnv}, -- NOT frame or env unparse {}, errors {decorate, frame, env, givenInputElements, compiledGrammars, flowEnv}, flowDefs {decorate, frame, env, compiledGrammars, flowEnv}, liftedStrategies {decorate}, attrRefNames {decorate, env, givenInputElements}, - containsFail {decorate, env}, allId {decorate, env}, freeRecVars {decorate, env}; + containsFail {decorate, env}, allId {decorate, env}, freeRecVars {decorate, env}, isRecursive {decorate, env}; propagate errors on StrategyExpr, StrategyExprs excluding strategyRef, functorRef; propagate flowDefs on StrategyExpr, StrategyExprs; propagate containsFail, allId on StrategyExprs; propagate freeRecVars on StrategyExpr, StrategyExprs excluding recComb; +propagate isRecursive on StrategyExpr, StrategyExprs; propagate simplify on StrategyExprs; propagate optimizeStep on MRuleList; propagate simplifyStep, simplify, optimizeStep, optimize on StrategyExpr; @@ -732,6 +734,12 @@ top::StrategyExpr ::= id::QNameAttrOccur top.attrRefName = just(id.name); top.matchesFrame := id.matchesFrame; + -- TODO: Actually figuring out if a strategy is recursive would involve building a transitive + -- closure of all references between strategy attributes... somewhere. Doing that repreatedly + -- here would be very inefficient. For now just assume that all strategies that reference other + -- strategies are recursive. + top.isRecursive <- true; + id.attrFor = top.frame.signature.outputElement.typerep; top.translation = diff --git a/test/silver_features/rewrite/expreval/AbstractSyntax.sv b/test/silver_features/rewrite/expreval/AbstractSyntax.sv index 258e3d809..0c31c94e1 100644 --- a/test/silver_features/rewrite/expreval/AbstractSyntax.sv +++ b/test/silver_features/rewrite/expreval/AbstractSyntax.sv @@ -126,7 +126,7 @@ global eval::Strategy = innermost(evalStep <+ simplifyConstIdent <+ simplifyFrac -- Strategy attributes autocopy attribute substName::String; autocopy attribute substExpr::Expr; -strategy attribute substRes = +strategy attribute substRes = -- This would actually be simpler as a functor, but this is a test... bottomUp(try( rule on top::Expr of | var(n1) when top.substName == n1 -> top.substExpr From 0525438e43b8de32134da81533cd8b68af426f62 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Thu, 16 Apr 2020 12:26:55 -0500 Subject: [PATCH 42/78] Add missing import error checking to term rewriting extension --- .../silver/extension/rewriting/Rewriting.sv | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/grammars/silver/extension/rewriting/Rewriting.sv b/grammars/silver/extension/rewriting/Rewriting.sv index 6baf16822..6a95f5e25 100644 --- a/grammars/silver/extension/rewriting/Rewriting.sv +++ b/grammars/silver/extension/rewriting/Rewriting.sv @@ -28,15 +28,16 @@ top::Expr ::= 'rewriteWith' '(' s::Expr ',' e::Expr ')' errCheckS.finalSubst = top.finalSubst; local localErrors::[Message] = - if errCheckS.typeerror - then [err(top.location, "First argument to rewriteWith must be Strategy. Instead got " ++ errCheckS.leftpp)] - else []; + s.errors ++ e.errors ++ + (if errCheckS.typeerror + then [err(top.location, "First argument to rewriteWith must be Strategy. Instead got " ++ errCheckS.leftpp)] + else []) ++ + (if null(getTypeDcl("silver:rewrite:Strategy", top.env)) + then [err(top.location, "Term rewriting requires import of silver:rewrite")] + else []); -- Can't use an error production here, unfourtunately, due to circular dependency issues. - top.errors := - if !null(s.errors ++ e.errors ++ localErrors) - then s.errors ++ e.errors ++ localErrors - else forward.errors; + top.errors := if !null(localErrors) then localErrors else forward.errors; -- TODO: Equation needed due to weirdness with lets auto-undecorating bindings. -- See comments in definition of lexicalLocalReference (grammars/silver/modification/let_fix/Let.sv) @@ -101,7 +102,11 @@ top::Expr ::= 'traverse' n::QName '(' es::AppExprs ',' anns::AnnoAppExprs ')' map(namedArgType(_, nonterminalType("silver:rewrite:Strategy", [])), annotations); anns.remainingFuncAnnotations = anns.funcAnnotations; - local localErrors::[Message] = es.errors ++ anns.traverseErrors; + local localErrors::[Message] = + es.errors ++ anns.traverseErrors ++ + if null(getTypeDcl("silver:rewrite:Strategy", top.env)) + then [err(top.location, "Term rewriting requires import of silver:rewrite")] + else []; es.downSubst = top.downSubst; anns.downSubst = es.upSubst; @@ -265,11 +270,14 @@ top::Expr ::= 'rule' 'on' ty::TypeExpr 'of' Opt_Vbar_t ml::MRuleList 'end' ml.ruleIndex = 0; ml.decRuleExprsIn = checkExpr.decRuleExprs; + local localErrors::[Message] = + ty.errors ++ ml.errors ++ checkExpr.errors ++ + if null(getTypeDcl("silver:rewrite:Strategy", top.env)) + then [err(top.location, "Term rewriting requires import of silver:rewrite")] + else []; + -- Can't use an error production here, unfourtunately, due to circular dependency issues. - top.errors := - if !null(ty.errors ++ ml.errors ++ checkExpr.errors) - then ty.errors ++ ml.errors ++ checkExpr.errors - else forward.errors; + top.errors := if !null(localErrors) then localErrors else forward.errors; checkExpr.downSubst = top.downSubst; forward.downSubst = checkExpr.upSubst; From 073596586ed24fdd94ff6b7c39a39501f295e328 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Thu, 16 Apr 2020 13:13:04 -0500 Subject: [PATCH 43/78] Use term rewriting in silver IDE spec --- grammars/silver/composed/idetest/Analyze.sv | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/grammars/silver/composed/idetest/Analyze.sv b/grammars/silver/composed/idetest/Analyze.sv index a3912c85d..0292addc4 100644 --- a/grammars/silver/composed/idetest/Analyze.sv +++ b/grammars/silver/composed/idetest/Analyze.sv @@ -9,6 +9,8 @@ import silver:util:cmdargs; import silver:definition:core; import silver:definition:env; +import silver:rewrite; + -- This function is mostly copied from function cmdLineRun in driver/BuildProcess.sv function ideAnalyze IOVal<[Message]> ::= args::[String] svParser::SVParser ioin::IO @@ -102,12 +104,12 @@ function rewriteMessages function rewriteMessage Message ::= path::String m::Message { - return case m of - | err(loc(file, a, b, c, d, e, f), g) -> err(loc(path ++ "/" ++ file, a, b, c, d, e, f), g) - | wrn(loc(file, a, b, c, d, e, f), g) -> wrn(loc(path ++ "/" ++ file, a, b, c, d, e, f), g) - | info(loc(file, a, b, c, d, e, f), g) -> info(loc(path ++ "/" ++ file, a, b, c, d, e, f), g) - | nested(loc(file, a, b, c, d, e, f), g, others) -> - nested(loc(path ++ "/" ++ file, a, b, c, d, e, f), g, map(rewriteMessage(path, _), others)) - end; + return + rewriteWith( + allTopDown( + rule on Location of + | loc(file, a, b, c, d, e, f) -> loc(path ++ "/" ++ file, a, b, c, d, e, f) + end), + m).fromJust; } From 05e9be43351659482ee78a739aff77c780205202 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Thu, 16 Apr 2020 17:15:17 -0500 Subject: [PATCH 44/78] Slightly more aggressive inlining optimizations --- .../silver/extension/strategyattr/DclInfo.sv | 5 +- .../silver/extension/strategyattr/Strategy.sv | 4 +- .../extension/strategyattr/StrategyExpr.sv | 95 +++++++++++-------- 3 files changed, 59 insertions(+), 45 deletions(-) diff --git a/grammars/silver/extension/strategyattr/DclInfo.sv b/grammars/silver/extension/strategyattr/DclInfo.sv index 00ff2267e..589349f14 100644 --- a/grammars/silver/extension/strategyattr/DclInfo.sv +++ b/grammars/silver/extension/strategyattr/DclInfo.sv @@ -1,7 +1,6 @@ grammar silver:extension:strategyattr; synthesized attribute containsErrors::Boolean occurs on DclInfo; -attribute isRecursive occurs on DclInfo; synthesized attribute liftedStrategyNames::[String] occurs on DclInfo; synthesized attribute givenRecVarEnv::[Pair] occurs on DclInfo; synthesized attribute strategyExpr :: StrategyExpr occurs on DclInfo; @@ -10,7 +9,6 @@ aspect default production top::DclInfo ::= { top.containsErrors = false; - top.isRecursive := false; top.liftedStrategyNames = []; top.givenRecVarEnv = []; top.strategyExpr = error("Internal compiler error: must be defined for all strategy attribute declarations"); @@ -19,7 +17,7 @@ top::DclInfo ::= abstract production strategyDcl top::DclInfo ::= sg::String sl::Location fn::String tyVar::TyVar - containsErrors::Boolean isRecursive::Boolean liftedStrategyNames::[String] givenRecVarEnv::[Pair] + containsErrors::Boolean liftedStrategyNames::[String] givenRecVarEnv::[Pair] e::StrategyExpr { top.sourceGrammar = sg; @@ -37,7 +35,6 @@ top::DclInfo ::= top.propagateDispatcher = propagateStrategy(_, location=_); top.containsErrors = containsErrors; - top.isRecursive := isRecursive; top.liftedStrategyNames = liftedStrategyNames; top.givenRecVarEnv = givenRecVarEnv; top.strategyExpr = e; diff --git a/grammars/silver/extension/strategyattr/Strategy.sv b/grammars/silver/extension/strategyattr/Strategy.sv index e0f4ae387..3c69040e4 100644 --- a/grammars/silver/extension/strategyattr/Strategy.sv +++ b/grammars/silver/extension/strategyattr/Strategy.sv @@ -43,7 +43,7 @@ top::AGDcl ::= a::Name recVarEnv::[Pair] e::StrategyExpr defaultEnvItem( strategyDcl( top.grammarName, a.location, fName, freshTyVar(), - !null(top.errors), e.isRecursive, map(fst, e.liftedStrategies), recVarEnv, e)))], + !null(top.errors), map(fst, e.liftedStrategies), recVarEnv, e)))], location=top.location), map( \ d::Pair -> @@ -103,6 +103,7 @@ top::ProductionStmt ::= attr::Decorated QName e.env = top.env; e.recVarEnv = attr.lookupAttribute.dcl.givenRecVarEnv; e.outerAttr = just(attr.lookupAttribute.fullName); + e.inlinedStrategies = [attr.lookupAttribute.fullName]; -- Don't unfold the top-level strategy within itself production e2::StrategyExpr = case e.optimize of @@ -115,6 +116,7 @@ top::ProductionStmt ::= attr::Decorated QName e2.env = e.env; e2.recVarEnv = e.recVarEnv; e2.outerAttr = e.outerAttr; + e2.inlinedStrategies = e.inlinedStrategies; -- Can't do this with forwarding to avoid circular dependency of -- forward -> dcl.containsErrors -> dcl.flowEnv -> forward.flowDefs diff --git a/grammars/silver/extension/strategyattr/StrategyExpr.sv b/grammars/silver/extension/strategyattr/StrategyExpr.sv index 7e4669ffd..e7f744bba 100644 --- a/grammars/silver/extension/strategyattr/StrategyExpr.sv +++ b/grammars/silver/extension/strategyattr/StrategyExpr.sv @@ -7,6 +7,7 @@ annotation genName::String; -- Used to generate the names of lifted strategy att autocopy attribute recVarEnv::[Pair]; inherited attribute outerAttr::Maybe; +autocopy attribute inlinedStrategies::[String]; monoid attribute liftedStrategies::[Pair] with [], ++; synthesized attribute attrRefName::Maybe; synthesized attribute isId::Boolean; @@ -16,11 +17,10 @@ monoid attribute containsFail::Boolean with false, ||; monoid attribute allId::Boolean with true, &&; monoid attribute matchesFrame::Boolean with false, ||; monoid attribute freeRecVars::[String] with [], ++; -monoid attribute isRecursive::Boolean with false, ||; synthesized attribute translation::a; --- Frame-independent algebraic simplifications +-- Production-independent algebraic simplifications strategy attribute simplifyStep = rule on top::StrategyExpr of | sequence(fail(), _) -> fail(location=top.location, genName=top.genName) @@ -37,9 +37,16 @@ strategy attribute simplifyStep = | prodTraversal(_, s) when s.containsFail -> fail(location=top.location, genName=top.genName) | prodTraversal(_, s) when s.allId -> id(location=top.location, genName=top.genName) | recComb(n, s) when !containsBy(stringEq, n.name, s.freeRecVars) -> s + | strategyRef(n) when !n.matchesFrame -> fail(location=top.location, genName=top.genName) + | functorRef(n) when !n.matchesFrame -> fail(location=top.location, genName=top.genName) + | strategyRef(n) when n.matchesFrame && !containsBy(stringEq, n.attrDcl.fullName, top.inlinedStrategies) && null(n.attrDcl.givenRecVarEnv) -> + inlined(n, n.attrDcl.strategyExpr, location=top.location, genName=top.genName) + | inlined(_, fail()) -> fail(location=top.location, genName=top.genName) + | inlined(n, id()) when n.matchesFrame -> id(location=top.location, genName=top.genName) + | inlined(n1, functorRef(n2)) when n1.matchesFrame -> functorRef(n2, location=top.location, genName=top.genName) end; strategy attribute simplify = innermost(simplifyStep); --- Frame-dependent optimizations +-- Production-dependent optimizations strategy attribute optimizeStep = rule on top::StrategyExpr of | allTraversal(s) when !attrMatchesChild(top.env, fromMaybe(s.genName, s.attrRefName), top.frame) -> id(location=top.location, genName=top.genName) @@ -47,9 +54,6 @@ strategy attribute optimizeStep = | oneTraversal(s) when !attrMatchesChild(top.env, fromMaybe(s.genName, s.attrRefName), top.frame) -> fail(location=top.location, genName=top.genName) | prodTraversal(p, s) when p.lookupValue.fullName != top.frame.fullName -> fail(location=top.location, genName=top.genName) | rewriteRule(_, _, ml) when !ml.matchesFrame -> fail(location=top.location, genName=top.genName) - | strategyRef(n) when !n.matchesFrame -> fail(location=top.location, genName=top.genName) - | functorRef(n) when !n.matchesFrame -> fail(location=top.location, genName=top.genName) - | strategyRef(n) when n.matchesFrame && !n.attrDcl.isRecursive && null(n.attrDcl.givenRecVarEnv) -> n.attrDcl.strategyExpr end <+ rewriteRule( id, id, @@ -67,38 +71,38 @@ strategy attribute optimize = oneTraversal(simplify) <+ prodTraversal(id, simplify) <+ recComb(id, optimize) <+ + inlined(id, optimize) <+ id) <* try((optimizeStep <+ simplifyStep) <* optimize); nonterminal StrategyExpr with config, grammarName, env, location, unparse, errors, frame, compiledGrammars, flowEnv, flowDefs, -- Normal expression stuff genName, recVarEnv, outerAttr, liftedStrategies, attrRefName, isId, - translation, matchesFrame, freeRecVars, isRecursive, - simplifyStep, simplify, optimizeStep, optimize; + translation, matchesFrame, freeRecVars, + inlinedStrategies, simplifyStep, simplify, optimizeStep, optimize; nonterminal StrategyExprs with config, grammarName, env, unparse, errors, frame, compiledGrammars, flowEnv, flowDefs, -- Normal expression stuff recVarEnv, givenInputElements, liftedStrategies, attrRefNames, - containsFail, allId, freeRecVars, isRecursive, - simplify; + containsFail, allId, freeRecVars, + inlinedStrategies, simplify; flowtype StrategyExpr = decorate {grammarName, config, recVarEnv, outerAttr}, -- NOT frame or env unparse {}, errors {decorate, frame, env, compiledGrammars, flowEnv}, flowDefs {decorate, frame, env, compiledGrammars, flowEnv}, liftedStrategies {decorate}, attrRefName {decorate}, isId {decorate}, - translation {decorate, frame, env}, matchesFrame {decorate, frame, env}, freeRecVars {decorate, env}, isRecursive {decorate, env}; + translation {decorate, frame, env}, matchesFrame {decorate, frame, env}, freeRecVars {decorate, env}; flowtype StrategyExprs = decorate {grammarName, config, recVarEnv}, -- NOT frame or env unparse {}, errors {decorate, frame, env, givenInputElements, compiledGrammars, flowEnv}, flowDefs {decorate, frame, env, compiledGrammars, flowEnv}, liftedStrategies {decorate}, attrRefNames {decorate, env, givenInputElements}, - containsFail {decorate, env}, allId {decorate, env}, freeRecVars {decorate, env}, isRecursive {decorate, env}; + containsFail {decorate, env}, allId {decorate, env}, freeRecVars {decorate, env}; propagate errors on StrategyExpr, StrategyExprs excluding strategyRef, functorRef; propagate flowDefs on StrategyExpr, StrategyExprs; propagate containsFail, allId on StrategyExprs; propagate freeRecVars on StrategyExpr, StrategyExprs excluding recComb; -propagate isRecursive on StrategyExpr, StrategyExprs; propagate simplify on StrategyExprs; propagate optimizeStep on MRuleList; propagate simplifyStep, simplify, optimizeStep, optimize on StrategyExpr; @@ -712,72 +716,84 @@ top::StrategyExpr ::= id::Decorated QName top.translation = Silver_Expr { $name{top.frame.signature.outputElement.elementName}.$qName{top.attrRefName.fromJust} }; } abstract production strategyRef -top::StrategyExpr ::= id::QNameAttrOccur +top::StrategyExpr ::= attr::QNameAttrOccur { - top.unparse = id.unparse; + top.unparse = attr.unparse; - local attrDcl::DclInfo = case id of qNameAttrOccur(a) -> a.lookupAttribute.dcl end; + -- Lookup for error checking is *not* contextual, since we don't know the frame here + local attrDcl::DclInfo = case attr of qNameAttrOccur(a) -> a.lookupAttribute.dcl end; attrDcl.givenNonterminalType = error("Not actually needed"); -- Ugh environment needs refactoring top.errors := case attrDcl.typerep, attrDcl.dclBoundVars of | nonterminalType("core:Maybe", [varType(a1)]), [a2] when tyVarEqual(a1, a2) -> [] | nonterminalType("core:Maybe", [nonterminalType(nt, _)]), _ -> case getOccursDcl(attrDcl.fullName, nt, top.env) of - | [] -> [wrn(id.location, s"Attribute ${id.name} cannot be used as a strategy, because it doesn't occur on its own nonterminal type ${nt}")] + | [] -> [wrn(attr.location, s"Attribute ${attr.name} cannot be used as a strategy, because it doesn't occur on its own nonterminal type ${nt}")] | _ -> [] end | errorType(), _ -> [] - | _, _ -> [err(id.location, s"Attribute ${id.name} cannot be used as a strategy")] + | _, _ -> [err(attr.location, s"Attribute ${attr.name} cannot be used as a strategy")] end; propagate liftedStrategies; - top.attrRefName = just(id.name); - top.matchesFrame := id.matchesFrame; - - -- TODO: Actually figuring out if a strategy is recursive would involve building a transitive - -- closure of all references between strategy attributes... somewhere. Doing that repreatedly - -- here would be very inefficient. For now just assume that all strategies that reference other - -- strategies are recursive. - top.isRecursive <- true; + top.attrRefName = just(attr.name); + top.matchesFrame := attr.matchesFrame; - id.attrFor = top.frame.signature.outputElement.typerep; + attr.attrFor = top.frame.signature.outputElement.typerep; top.translation = - if id.matchesFrame - then Silver_Expr { $name{top.frame.signature.outputElement.elementName}.$QNameAttrOccur{id} } + if attr.matchesFrame + then Silver_Expr { $name{top.frame.signature.outputElement.elementName}.$QNameAttrOccur{attr} } else Silver_Expr { core:nothing() }; } abstract production functorRef -top::StrategyExpr ::= id::QNameAttrOccur +top::StrategyExpr ::= attr::QNameAttrOccur { - top.unparse = id.unparse; + top.unparse = attr.unparse; - local attrDcl::DclInfo = case id of qNameAttrOccur(a) -> a.lookupAttribute.dcl end; + -- Lookup for error checking is *not* contextual, since we don't know the frame here + local attrDcl::DclInfo = case attr of qNameAttrOccur(a) -> a.lookupAttribute.dcl end; attrDcl.givenNonterminalType = error("Not actually needed"); -- Ugh environment needs refactoring top.errors := case attrDcl.typerep, attrDcl.dclBoundVars of | varType(a1), [a2] when tyVarEqual(a1, a2) -> [] | nonterminalType(nt, _), _ -> case getOccursDcl(attrDcl.fullName, nt, top.env) of - | [] -> [wrn(id.location, s"Attribute ${id.name} cannot be used as a functor, because it doesn't occur on its own nonterminal type ${nt}")] + | [] -> [wrn(attr.location, s"Attribute ${attr.name} cannot be used as a functor, because it doesn't occur on its own nonterminal type ${nt}")] | _ -> [] end | errorType(), _ -> [] - | _, _ -> [err(id.location, s"Attribute ${id.name} cannot be used as a functor")] + | _, _ -> [err(attr.location, s"Attribute ${attr.name} cannot be used as a functor")] end; propagate liftedStrategies; - top.attrRefName = just(id.name); - top.matchesFrame := id.matchesFrame; + top.attrRefName = just(attr.name); + top.matchesFrame := attr.matchesFrame; - id.attrFor = top.frame.signature.outputElement.typerep; + attr.attrFor = top.frame.signature.outputElement.typerep; top.translation = - if id.matchesFrame - then Silver_Expr { core:just($name{top.frame.signature.outputElement.elementName}.$QNameAttrOccur{id}) } + if attr.matchesFrame + then Silver_Expr { core:just($name{top.frame.signature.outputElement.elementName}.$QNameAttrOccur{attr}) } else Silver_Expr { core:nothing() }; } +-- The result of performing an inlining optimization +abstract production inlined +top::StrategyExpr ::= attr::Decorated QNameAttrOccur s::StrategyExpr +{ + top.unparse = s"(${s.unparse} aka ${attr.unparse})"; + propagate liftedStrategies; + top.attrRefName = just(attr.attrDcl.fullName); + top.translation = + if attr.matchesFrame + then s.translation + else Silver_Expr { core:nothing() }; + + s.outerAttr = top.outerAttr; + s.inlinedStrategies = attr.attrDcl.fullName :: top.inlinedStrategies; +} + attribute matchesFrame occurs on QNameAttrOccur; aspect production qNameAttrOccur @@ -807,4 +823,3 @@ Boolean ::= env::Decorated Env attrName::String frame::BlockContext \ e::NamedSignatureElement -> attrMatchesFrame(env, attrName, e.typerep), frame.signature.inputElements)); } - From 2090004f818e3de413c7dab31ab8601bf51fc9d8 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Thu, 16 Apr 2020 18:14:55 -0500 Subject: [PATCH 45/78] Refactoring of optimization strategies --- .../extension/strategyattr/StrategyExpr.sv | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/grammars/silver/extension/strategyattr/StrategyExpr.sv b/grammars/silver/extension/strategyattr/StrategyExpr.sv index e7f744bba..ca5ff39c7 100644 --- a/grammars/silver/extension/strategyattr/StrategyExpr.sv +++ b/grammars/silver/extension/strategyattr/StrategyExpr.sv @@ -20,8 +20,10 @@ monoid attribute freeRecVars::[String] with [], ++; synthesized attribute translation::a; --- Production-independent algebraic simplifications -strategy attribute simplifyStep = +-- Nonterminal-independent algebraic simplifications +-- Theoretically these could be applied to the strategy before lifting/propagation, +-- but probably not much of an improvement. +strategy attribute genericStep = rule on top::StrategyExpr of | sequence(fail(), _) -> fail(location=top.location, genName=top.genName) | sequence(_, fail()) -> fail(location=top.location, genName=top.genName) @@ -29,25 +31,29 @@ strategy attribute simplifyStep = | sequence(s, id()) -> s | choice(fail(), s) -> s | choice(s, fail()) -> s - | choice(id(), s) -> id(location=top.location, genName=top.genName) - | choice(functorRef(n, genName=g, location=l), s) -> functorRef(n, genName=g, location=l) + | choice(id(), _) -> id(location=top.location, genName=top.genName) + | choice(functorRef(n, genName=g, location=l), _) -> functorRef(n, genName=g, location=l) | allTraversal(id()) -> id(location=top.location, genName=top.genName) | someTraversal(fail()) -> fail(location=top.location, genName=top.genName) | oneTraversal(fail()) -> fail(location=top.location, genName=top.genName) | prodTraversal(_, s) when s.containsFail -> fail(location=top.location, genName=top.genName) | prodTraversal(_, s) when s.allId -> id(location=top.location, genName=top.genName) | recComb(n, s) when !containsBy(stringEq, n.name, s.freeRecVars) -> s - | strategyRef(n) when !n.matchesFrame -> fail(location=top.location, genName=top.genName) - | functorRef(n) when !n.matchesFrame -> fail(location=top.location, genName=top.genName) + | inlined(_, fail()) -> fail(location=top.location, genName=top.genName) + end; +-- Nonterminal-dependent, production-independent optimizations +strategy attribute ntStep = + rule on top::StrategyExpr of | strategyRef(n) when n.matchesFrame && !containsBy(stringEq, n.attrDcl.fullName, top.inlinedStrategies) && null(n.attrDcl.givenRecVarEnv) -> inlined(n, n.attrDcl.strategyExpr, location=top.location, genName=top.genName) - | inlined(_, fail()) -> fail(location=top.location, genName=top.genName) + | strategyRef(n) when !n.matchesFrame -> fail(location=top.location, genName=top.genName) + | functorRef(n) when !n.matchesFrame -> fail(location=top.location, genName=top.genName) + | inlined(n, _) when !n.matchesFrame -> fail(location=top.location, genName=top.genName) | inlined(n, id()) when n.matchesFrame -> id(location=top.location, genName=top.genName) | inlined(n1, functorRef(n2)) when n1.matchesFrame -> functorRef(n2, location=top.location, genName=top.genName) end; -strategy attribute simplify = innermost(simplifyStep); -- Production-dependent optimizations -strategy attribute optimizeStep = +strategy attribute prodStep = rule on top::StrategyExpr of | allTraversal(s) when !attrMatchesChild(top.env, fromMaybe(s.genName, s.attrRefName), top.frame) -> id(location=top.location, genName=top.genName) | someTraversal(s) when !attrMatchesChild(top.env, fromMaybe(s.genName, s.attrRefName), top.frame) -> fail(location=top.location, genName=top.genName) @@ -62,7 +68,9 @@ strategy attribute optimizeStep = | mRuleList_cons(h, _, t) when !h.matchesFrame -> t | mRuleList_cons(h, _, mRuleList_one(t)) when !t.matchesFrame -> mRuleList_one(h, location=top.location) end)); -attribute optimizeStep occurs on MRuleList; +attribute prodStep occurs on MRuleList; + +strategy attribute simplify = innermost(genericStep <+ ntStep); strategy attribute optimize = (sequence(optimize, simplify) <+ choice(optimize, optimize) <+ @@ -73,13 +81,13 @@ strategy attribute optimize = recComb(id, optimize) <+ inlined(id, optimize) <+ id) <* - try((optimizeStep <+ simplifyStep) <* optimize); + try((genericStep <+ ntStep <+ prodStep) <* optimize); nonterminal StrategyExpr with config, grammarName, env, location, unparse, errors, frame, compiledGrammars, flowEnv, flowDefs, -- Normal expression stuff genName, recVarEnv, outerAttr, liftedStrategies, attrRefName, isId, translation, matchesFrame, freeRecVars, - inlinedStrategies, simplifyStep, simplify, optimizeStep, optimize; + inlinedStrategies, genericStep, ntStep, prodStep, simplify, optimize; nonterminal StrategyExprs with config, grammarName, env, unparse, errors, frame, compiledGrammars, flowEnv, flowDefs, -- Normal expression stuff @@ -104,8 +112,8 @@ propagate flowDefs on StrategyExpr, StrategyExprs; propagate containsFail, allId on StrategyExprs; propagate freeRecVars on StrategyExpr, StrategyExprs excluding recComb; propagate simplify on StrategyExprs; -propagate optimizeStep on MRuleList; -propagate simplifyStep, simplify, optimizeStep, optimize on StrategyExpr; +propagate prodStep on MRuleList; +propagate genericStep, ntStep, prodStep, simplify, optimize on StrategyExpr; aspect default production top::StrategyExpr ::= From 59413e21148b36b3340b665eb2ca59f2b5725fff Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Thu, 16 Apr 2020 18:27:10 -0500 Subject: [PATCH 46/78] Another improved optimization --- .../silver/extension/strategyattr/StrategyExpr.sv | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/grammars/silver/extension/strategyattr/StrategyExpr.sv b/grammars/silver/extension/strategyattr/StrategyExpr.sv index ca5ff39c7..e652fa2c0 100644 --- a/grammars/silver/extension/strategyattr/StrategyExpr.sv +++ b/grammars/silver/extension/strategyattr/StrategyExpr.sv @@ -11,6 +11,7 @@ autocopy attribute inlinedStrategies::[String]; monoid attribute liftedStrategies::[Pair] with [], ++; synthesized attribute attrRefName::Maybe; synthesized attribute isId::Boolean; +synthesized attribute isSuccess::Boolean; inherited attribute givenInputElements::[NamedSignatureElement]; synthesized attribute attrRefNames::[Maybe]; monoid attribute containsFail::Boolean with false, ||; @@ -31,8 +32,7 @@ strategy attribute genericStep = | sequence(s, id()) -> s | choice(fail(), s) -> s | choice(s, fail()) -> s - | choice(id(), _) -> id(location=top.location, genName=top.genName) - | choice(functorRef(n, genName=g, location=l), _) -> functorRef(n, genName=g, location=l) + | choice(s, _) when s.isSuccess -> s | allTraversal(id()) -> id(location=top.location, genName=top.genName) | someTraversal(fail()) -> fail(location=top.location, genName=top.genName) | oneTraversal(fail()) -> fail(location=top.location, genName=top.genName) @@ -85,7 +85,7 @@ strategy attribute optimize = nonterminal StrategyExpr with config, grammarName, env, location, unparse, errors, frame, compiledGrammars, flowEnv, flowDefs, -- Normal expression stuff - genName, recVarEnv, outerAttr, liftedStrategies, attrRefName, isId, + genName, recVarEnv, outerAttr, liftedStrategies, attrRefName, isId, isSuccess, translation, matchesFrame, freeRecVars, inlinedStrategies, genericStep, ntStep, prodStep, simplify, optimize; @@ -98,7 +98,7 @@ nonterminal StrategyExprs with flowtype StrategyExpr = decorate {grammarName, config, recVarEnv, outerAttr}, -- NOT frame or env unparse {}, errors {decorate, frame, env, compiledGrammars, flowEnv}, flowDefs {decorate, frame, env, compiledGrammars, flowEnv}, - liftedStrategies {decorate}, attrRefName {decorate}, isId {decorate}, + liftedStrategies {decorate}, attrRefName {decorate}, isId {decorate}, isSuccess {decorate}, translation {decorate, frame, env}, matchesFrame {decorate, frame, env}, freeRecVars {decorate, env}; flowtype StrategyExprs = @@ -121,6 +121,7 @@ top::StrategyExpr ::= top.attrRefName = nothing(); top.matchesFrame := true; -- Consulted only when attrRefName is just(...) top.isId = false; + top.isSuccess = false; } -- Basic combinators @@ -130,6 +131,7 @@ top::StrategyExpr ::= top.unparse = "id"; propagate liftedStrategies; top.isId = true; + top.isSuccess = true; top.translation = Silver_Expr { core:just($name{top.frame.signature.outputElement.elementName}) }; } @@ -150,6 +152,7 @@ top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr if s2.attrRefName.isJust then [] else [pair(s2.genName, s2)]; + top.isSuccess = s1.isSuccess && s2.isSuccess; s1.outerAttr = nothing(); s2.outerAttr = nothing(); @@ -212,6 +215,7 @@ top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr { top.unparse = s"(${s1.unparse} <+ ${s2.unparse})"; propagate liftedStrategies; + top.isSuccess = s1.isSuccess || s2.isSuccess; s1.outerAttr = nothing(); s2.outerAttr = nothing(); @@ -236,6 +240,7 @@ top::StrategyExpr ::= s::StrategyExpr if s.attrRefName.isJust then [] else [pair(s.genName, s)]; + top.isSuccess = s.isSuccess; s.outerAttr = nothing(); @@ -777,6 +782,7 @@ top::StrategyExpr ::= attr::QNameAttrOccur propagate liftedStrategies; top.attrRefName = just(attr.name); top.matchesFrame := attr.matchesFrame; + top.isSuccess = true; attr.attrFor = top.frame.signature.outputElement.typerep; @@ -793,6 +799,7 @@ top::StrategyExpr ::= attr::Decorated QNameAttrOccur s::StrategyExpr top.unparse = s"(${s.unparse} aka ${attr.unparse})"; propagate liftedStrategies; top.attrRefName = just(attr.attrDcl.fullName); + top.isSuccess = s.isSuccess; top.translation = if attr.matchesFrame then s.translation From af99a20fb3cfe277315aa6c9d483263d3fedd62b Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Fri, 17 Apr 2020 19:36:15 -0500 Subject: [PATCH 47/78] Bug fix to term rewriting extension, avoid crashing when the wrong number of patterns are given in a production's pattern list --- grammars/silver/extension/rewriting/Pattern.sv | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/grammars/silver/extension/rewriting/Pattern.sv b/grammars/silver/extension/rewriting/Pattern.sv index 81d63fb7c..ee752f15b 100644 --- a/grammars/silver/extension/rewriting/Pattern.sv +++ b/grammars/silver/extension/rewriting/Pattern.sv @@ -133,7 +133,11 @@ top::PatternList ::= p::Pattern top.transform = consASTPattern(p.transform, nilASTPattern()); top.firstTransform = p.transform; top.isPolymorphic = p.isPolymorphic; - p.typeHasUniversalVars = head(top.typesHaveUniversalVars); + p.typeHasUniversalVars = + case top.typesHaveUniversalVars of + | h :: _ -> h + | _ -> false + end; } aspect production patternList_more top::PatternList ::= p::Pattern ',' ps::PatternList @@ -141,8 +145,16 @@ top::PatternList ::= p::Pattern ',' ps::PatternList top.transform = consASTPattern(p.transform, ps.transform); top.firstTransform = p.transform; top.isPolymorphic = p.isPolymorphic || ps.isPolymorphic; - p.typeHasUniversalVars = head(top.typesHaveUniversalVars); - ps.typesHaveUniversalVars = tail(top.typesHaveUniversalVars); + p.typeHasUniversalVars = + case top.typesHaveUniversalVars of + | h :: _ -> h + | _ -> false + end; + ps.typesHaveUniversalVars = + case top.typesHaveUniversalVars of + | _ :: t -> t + | _ -> [] + end; } aspect production patternList_nil From 9498ff675a6f987ea59acc87c042bb158e0a1a87 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Fri, 17 Apr 2020 19:37:58 -0500 Subject: [PATCH 48/78] Add antiquote production for StrategyQName --- .../extension/strategyattr/ConcreteSyntax.sv | 4 ++-- .../silver/extension/strategyattr/Project.sv | 1 + .../{ => construction}/Construction.sv | 22 ++++++++++++++----- 3 files changed, 20 insertions(+), 7 deletions(-) rename grammars/silver/extension/strategyattr/{ => construction}/Construction.sv (74%) diff --git a/grammars/silver/extension/strategyattr/ConcreteSyntax.sv b/grammars/silver/extension/strategyattr/ConcreteSyntax.sv index 00a791a65..94ee84756 100644 --- a/grammars/silver/extension/strategyattr/ConcreteSyntax.sv +++ b/grammars/silver/extension/strategyattr/ConcreteSyntax.sv @@ -227,7 +227,7 @@ concrete productions top::StrategyExprs_c nonterminal StrategyQName with location, ast; concrete productions top::StrategyQName -| id::StrategyName_t +(strategyQNameOne) | id::StrategyName_t { top.ast = qNameId(name(id.lexeme, id.location), location=top.location); } -| id::StrategyName_t ':' qn::StrategyQName +(strategyQNameCons) | id::StrategyName_t ':' qn::StrategyQName { top.ast = qNameCons(name(id.lexeme, id.location), $2, qn.ast, location=top.location); } diff --git a/grammars/silver/extension/strategyattr/Project.sv b/grammars/silver/extension/strategyattr/Project.sv index a783a32e3..49a1ffc1a 100644 --- a/grammars/silver/extension/strategyattr/Project.sv +++ b/grammars/silver/extension/strategyattr/Project.sv @@ -13,3 +13,4 @@ imports silver:modification:let_fix; imports silver:modification:lambda_fn; exports silver:extension:strategyattr:convenience; +exports silver:extension:strategyattr:construction; diff --git a/grammars/silver/extension/strategyattr/Construction.sv b/grammars/silver/extension/strategyattr/construction/Construction.sv similarity index 74% rename from grammars/silver/extension/strategyattr/Construction.sv rename to grammars/silver/extension/strategyattr/construction/Construction.sv index 571c43ee2..37d7d137a 100644 --- a/grammars/silver/extension/strategyattr/Construction.sv +++ b/grammars/silver/extension/strategyattr/construction/Construction.sv @@ -1,11 +1,17 @@ -grammar silver:extension:strategyattr; +grammar silver:extension:strategyattr:construction; -import silver:reflect; -import silver:metatranslation; -import silver:rewrite as s; +imports silver:definition:core; +imports silver:extension:strategyattr; +imports silver:extension:silverconstruction; + +imports silver:reflect; +imports silver:metatranslation; +imports silver:rewrite as s; +imports silver:langutil:pp; terminal SilverStrategyExpr_t 'Silver_StrategyExpr' lexer classes {KEYWORD, RESERVED}; terminal AntiquoteStrategyExpr_t '$StrategyExpr' lexer classes {Antiquote, Strategy}; +terminal AntiquoteStrategyQName_t '$strategyQName' lexer classes {Antiquote, Strategy}; concrete production quoteStrategyExpr top::Expr ::= 'Silver_StrategyExpr' '(' genName::Expr ')' '{' cst::StrategyExpr_c '}' @@ -37,6 +43,12 @@ top::StrategyExpr_c ::= '$StrategyExpr' '{' e::Expr '}' top.ast = antiquoteStrategyExpr(e, genName=top.givenGenName, location=top.location); } +concrete production antiquote_strategyQName +top::StrategyQName ::= '$strategyQName' '{' e::Expr '}' +{ + top.ast = antiquote_qName('$qName', $2, e, $4, location=top.location); +} + abstract production antiquoteStrategyExpr top::StrategyExpr ::= e::Expr { @@ -48,5 +60,5 @@ aspect production nonterminalAST top::AST ::= prodName::String children::ASTs annotations::NamedASTs { directAntiquoteProductions <- - ["silver:extension:strategyattr:antiquoteStrategyExpr"]; + ["silver:extension:strategyattr:construction:antiquoteStrategyExpr"]; } From 1c72875ef9f225319722cad0aa020f76bfbb090e Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Fri, 17 Apr 2020 20:04:59 -0500 Subject: [PATCH 49/78] Bug fix to util strategies, use unique name for generated rec vars --- .../extension/strategyattr/StrategyUtils.sv | 48 ++++++++++++------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/grammars/silver/extension/strategyattr/StrategyUtils.sv b/grammars/silver/extension/strategyattr/StrategyUtils.sv index 2c1297ad3..8cc2d0747 100644 --- a/grammars/silver/extension/strategyattr/StrategyUtils.sv +++ b/grammars/silver/extension/strategyattr/StrategyUtils.sv @@ -33,143 +33,159 @@ top::StrategyExpr ::= s::StrategyExpr abstract production repeatS -- name clash with repeat from core top::StrategyExpr ::= s::StrategyExpr { + local recVarName::String = "repeat_" ++ toString(genInt()); forwards to Silver_StrategyExpr (top.genName) { - rec res -> try($StrategyExpr{s} <* res) + rec $name{recVarName} -> try($StrategyExpr{s} <* $strategyQName{recVarName}) }; } abstract production reduce top::StrategyExpr ::= s::StrategyExpr { + local recVarName::String = "reduce_" ++ toString(genInt()); forwards to Silver_StrategyExpr (top.genName) { - repeat(rec res -> some(res) <+ $StrategyExpr{s}) + repeat(rec $name{recVarName} -> some($strategyQName{recVarName}) <+ $StrategyExpr{s}) }; } abstract production bottomUp top::StrategyExpr ::= s::StrategyExpr { + local recVarName::String = "bottomUp_" ++ toString(genInt()); forwards to Silver_StrategyExpr (top.genName) { - rec res -> all(res) <* $StrategyExpr{s} + rec $name{recVarName} -> all($strategyQName{recVarName}) <* $StrategyExpr{s} }; } abstract production topDown top::StrategyExpr ::= s::StrategyExpr { + local recVarName::String = "topDown_" ++ toString(genInt()); forwards to Silver_StrategyExpr (top.genName) { - rec res -> $StrategyExpr{s} <* all(res) + rec $name{recVarName} -> $StrategyExpr{s} <* all($strategyQName{recVarName}) }; } abstract production downUp top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr { + local recVarName::String = "downUp_" ++ toString(genInt()); forwards to Silver_StrategyExpr (top.genName) { - rec res -> $StrategyExpr{s1} <* all(res) <* $StrategyExpr{s2} + rec $name{recVarName} -> $StrategyExpr{s1} <* all($strategyQName{recVarName}) <* $StrategyExpr{s2} }; } abstract production allBottomUp top::StrategyExpr ::= s::StrategyExpr { + local recVarName::String = "allBottomUp_" ++ toString(genInt()); forwards to Silver_StrategyExpr (top.genName) { - rec res -> all(res) <+ $StrategyExpr{s} + rec $name{recVarName} -> all($strategyQName{recVarName}) <+ $StrategyExpr{s} }; } abstract production allTopDown top::StrategyExpr ::= s::StrategyExpr { + local recVarName::String = "allTopDown_" ++ toString(genInt()); forwards to Silver_StrategyExpr (top.genName) { - rec res -> $StrategyExpr{s} <+ all(res) + rec $name{recVarName} -> $StrategyExpr{s} <+ all($strategyQName{recVarName}) }; } abstract production allDownUp top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr { + local recVarName::String = "allDownUp_" ++ toString(genInt()); forwards to Silver_StrategyExpr (top.genName) { - rec res -> $StrategyExpr{s1} <+ all(res) <+ $StrategyExpr{s2} + rec $name{recVarName} -> $StrategyExpr{s1} <+ all($strategyQName{recVarName}) <+ $StrategyExpr{s2} }; } abstract production someBottomUp top::StrategyExpr ::= s::StrategyExpr { + local recVarName::String = "someBottomUp_" ++ toString(genInt()); forwards to Silver_StrategyExpr (top.genName) { - rec res -> some(res) <+ $StrategyExpr{s} + rec $name{recVarName} -> some($strategyQName{recVarName}) <+ $StrategyExpr{s} }; } abstract production someTopDown top::StrategyExpr ::= s::StrategyExpr { + local recVarName::String = "someTopDown_" ++ toString(genInt()); forwards to Silver_StrategyExpr (top.genName) { - rec res -> $StrategyExpr{s} <+ some(res) + rec $name{recVarName} -> $StrategyExpr{s} <+ some($strategyQName{recVarName}) }; } abstract production someDownUp top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr { + local recVarName::String = "someDownUp_" ++ toString(genInt()); forwards to Silver_StrategyExpr (top.genName) { - rec res -> $StrategyExpr{s1} <+ some(res) <+ $StrategyExpr{s2} + rec $name{recVarName} -> $StrategyExpr{s1} <+ some($strategyQName{recVarName}) <+ $StrategyExpr{s2} }; } abstract production onceBottomUp top::StrategyExpr ::= s::StrategyExpr { + local recVarName::String = "onceBottomUp_" ++ toString(genInt()); forwards to Silver_StrategyExpr (top.genName) { - rec res -> one(res) <+ $StrategyExpr{s} + rec $name{recVarName} -> one($strategyQName{recVarName}) <+ $StrategyExpr{s} }; } abstract production onceTopDown top::StrategyExpr ::= s::StrategyExpr { + local recVarName::String = "onceTopDown_" ++ toString(genInt()); forwards to Silver_StrategyExpr (top.genName) { - rec res -> $StrategyExpr{s} <+ one(res) + rec $name{recVarName} -> $StrategyExpr{s} <+ one($strategyQName{recVarName}) }; } abstract production onceDownUp top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr { + local recVarName::String = "onceDownUp_" ++ toString(genInt()); forwards to Silver_StrategyExpr (top.genName) { - rec res -> $StrategyExpr{s1} <+ one(res) <+ $StrategyExpr{s2} + rec $name{recVarName} -> $StrategyExpr{s1} <+ one($strategyQName{recVarName}) <+ $StrategyExpr{s2} }; } abstract production innermost top::StrategyExpr ::= s::StrategyExpr { + local recVarName::String = "innermost_" ++ toString(genInt()); forwards to Silver_StrategyExpr (top.genName) { - rec res -> bottomUp(try($StrategyExpr{s} <* res)) + rec $name{recVarName} -> bottomUp(try($StrategyExpr{s} <* $strategyQName{recVarName})) }; } abstract production outermost top::StrategyExpr ::= s::StrategyExpr { + local recVarName::String = "outermost_" ++ toString(genInt()); forwards to Silver_StrategyExpr (top.genName) { - rec res -> topDown(try($StrategyExpr{s} <* res)) + rec res -> topDown(try($StrategyExpr{s} <* $strategyQName{recVarName})) }; } From d3df80cae2ae93b9bca18f957f930c597b382b0f Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Mon, 20 Apr 2020 13:59:13 -0500 Subject: [PATCH 50/78] Fix missed in last commit --- grammars/silver/extension/strategyattr/StrategyUtils.sv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grammars/silver/extension/strategyattr/StrategyUtils.sv b/grammars/silver/extension/strategyattr/StrategyUtils.sv index 8cc2d0747..63fbdd93e 100644 --- a/grammars/silver/extension/strategyattr/StrategyUtils.sv +++ b/grammars/silver/extension/strategyattr/StrategyUtils.sv @@ -186,6 +186,6 @@ top::StrategyExpr ::= s::StrategyExpr local recVarName::String = "outermost_" ++ toString(genInt()); forwards to Silver_StrategyExpr (top.genName) { - rec res -> topDown(try($StrategyExpr{s} <* $strategyQName{recVarName})) + rec $name{recVarName} -> topDown(try($StrategyExpr{s} <* $strategyQName{recVarName})) }; } From 0f2962af530bc7174efdb02ce81da8987cf03a87 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Wed, 22 Apr 2020 12:45:08 -0500 Subject: [PATCH 51/78] Bug fix, tests involving functor attributes --- .../extension/strategyattr/StrategyExpr.sv | 6 +-- test/silver_features/Strategy.sv | 47 +++++++++++++++++++ 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/grammars/silver/extension/strategyattr/StrategyExpr.sv b/grammars/silver/extension/strategyattr/StrategyExpr.sv index e652fa2c0..bb678999d 100644 --- a/grammars/silver/extension/strategyattr/StrategyExpr.sv +++ b/grammars/silver/extension/strategyattr/StrategyExpr.sv @@ -195,10 +195,10 @@ top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr } | _, functorRef(attr2) -> Silver_Expr { - core:monad:bindMaybe( - $Expr{s1.translation}, + core:mapMaybe( \ res::$TypeExpr{typerepTypeExpr(top.frame.signature.outputElement.typerep, location=top.location)} -> - decorate res with { $ExprInhs{allInhs} }.$QNameAttrOccur{attr2}) + decorate res with { $ExprInhs{allInhs} }.$QNameAttrOccur{attr2}, + $Expr{s1.translation}) } | _, _ -> Silver_Expr { diff --git a/test/silver_features/Strategy.sv b/test/silver_features/Strategy.sv index a25408924..797e3559f 100644 --- a/test/silver_features/Strategy.sv +++ b/test/silver_features/Strategy.sv @@ -80,3 +80,50 @@ equalityTest( addSExpr(constSExpr(42), constSExpr(0)).removeLastStmt), "core:nothing()", String, silver_tests); + + +functor attribute incAllConsts occurs on SStmt, SExpr; +propagate incAllConsts on SStmt, SExpr excluding constSExpr; +aspect production constSExpr +top::SExpr ::= i::Integer +{ top.incAllConsts = constSExpr(i + 1); } + +strategy attribute incTwice = incAllConsts <* incAllConsts + occurs on SStmt, SExpr; +propagate incTwice on SStmt, SExpr; + +equalityTest( + hackUnparse( + assignSStmt("a", addSExpr(constSExpr(42), constSExpr(0))).incTwice), + "core:just(silver_features:assignSStmt(\"a\", silver_features:addSExpr(silver_features:constSExpr(44), silver_features:constSExpr(2))))", + String, silver_tests); + + +autocopy attribute target::String occurs on SStmt, SExpr; +strategy attribute incTargetConsts = + allTopDown( + rule on top::SStmt of + | assignSStmt(n, _) when n == top.target -> top + end <* incAllConsts) + occurs on SStmt, SExpr; +propagate incTargetConsts on SStmt, SExpr; + +equalityTest( + hackUnparse( + decorate + seqSStmt( + assignSStmt("a", addSExpr(constSExpr(42), constSExpr(0))), + assignSStmt("b", addSExpr(addSExpr(idSExpr("a"), constSExpr(2)), constSExpr(17)))) + with {target = "b";}.incTargetConsts), + "core:just(silver_features:seqSStmt(silver_features:assignSStmt(\"a\", silver_features:addSExpr(silver_features:constSExpr(42), silver_features:constSExpr(0))), silver_features:assignSStmt(\"b\", silver_features:addSExpr(silver_features:addSExpr(silver_features:idSExpr(\"a\"), silver_features:constSExpr(3)), silver_features:constSExpr(18)))))", + String, silver_tests); + +strategy attribute incThenElim = incAllConsts <* elimPlusZero + occurs on SStmt, SExpr; +propagate incThenElim on SStmt, SExpr; + +equalityTest( + hackUnparse( + assignSStmt("a", addSExpr(constSExpr(42), constSExpr(-1))).incThenElim), + "core:just(silver_features:assignSStmt(\"a\", silver_features:constSExpr(43)))", + String, silver_tests); From 2ad624bc34ea5aded9861f374dd6c28e94dd978d Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Wed, 22 Apr 2020 14:27:02 -0500 Subject: [PATCH 52/78] Support and tests for functor attributes in traversal strategies --- .../extension/strategyattr/StrategyExpr.sv | 358 ++++++++++-------- test/silver_features/Strategy.sv | 48 ++- 2 files changed, 241 insertions(+), 165 deletions(-) diff --git a/grammars/silver/extension/strategyattr/StrategyExpr.sv b/grammars/silver/extension/strategyattr/StrategyExpr.sv index bb678999d..b79e30c58 100644 --- a/grammars/silver/extension/strategyattr/StrategyExpr.sv +++ b/grammars/silver/extension/strategyattr/StrategyExpr.sv @@ -13,7 +13,7 @@ synthesized attribute attrRefName::Maybe; synthesized attribute isId::Boolean; synthesized attribute isSuccess::Boolean; inherited attribute givenInputElements::[NamedSignatureElement]; -synthesized attribute attrRefNames::[Maybe]; +synthesized attribute attrRefNames::[Maybe>]; monoid attribute containsFail::Boolean with false, ||; monoid attribute allId::Boolean with true, &&; monoid attribute matchesFrame::Boolean with false, ||; @@ -98,7 +98,7 @@ nonterminal StrategyExprs with flowtype StrategyExpr = decorate {grammarName, config, recVarEnv, outerAttr}, -- NOT frame or env unparse {}, errors {decorate, frame, env, compiledGrammars, flowEnv}, flowDefs {decorate, frame, env, compiledGrammars, flowEnv}, - liftedStrategies {decorate}, attrRefName {decorate}, isId {decorate}, isSuccess {decorate}, + liftedStrategies {decorate}, attrRefName {decorate}, isId {decorate}, isSuccess {decorate, env}, translation {decorate, frame, env}, matchesFrame {decorate, frame, env}, freeRecVars {decorate, env}; flowtype StrategyExprs = @@ -229,13 +229,6 @@ top::StrategyExpr ::= s::StrategyExpr { top.unparse = s"all(${s.unparse})"; - top.errors <- - case s of - -- TBH this doesn't seem very useful anyway - | functorRef(_) -> [err(s.location, "Functor attributes as arguments to generic traversals are not yet supported")] - | _ -> [] - end; - top.liftedStrategies := if s.attrRefName.isJust then [] @@ -253,47 +246,67 @@ top::StrategyExpr ::= s::StrategyExpr pair(e.elementName, attrMatchesFrame(top.env, sName, e.typerep)), top.frame.signature.inputElements); top.translation = - {- Translation of all(s) for prod::(Foo ::= a::Foo b::Integer c::Bar): - case a.s, c.s of - | just(a_s), just(c_s) -> just(prod(a_s, b, c_s)) - | _, _ -> nothing() - end - Could also be implemented as chained monadic binds. Maybe more efficient this way? -} - caseExpr( - flatMap( - \ a::Pair -> - if a.snd then [Silver_Expr { $name{a.fst}.$name{sName} }] else [], - childAccesses), - [matchRule( - flatMap( - \ a::Pair -> - if a.snd - then - [decorate Silver_Pattern { core:just($name{a.fst ++ "_" ++ sBaseName}) } - with { config = top.config; env = top.env; frame = top.frame; patternVarEnv = []; }] - else [], - childAccesses), - nothing(), - Silver_Expr { - core:just( - $Expr{ - mkFullFunctionInvocation( - top.location, - baseExpr(qName(top.location, top.frame.fullName), location=top.location), - map( - \ a::Pair -> - if a.snd - then Silver_Expr { $name{a.fst ++ "_" ++ sBaseName} } - else Silver_Expr { $name{a.fst} }, - childAccesses), - map( - makeAnnoArg(top.location, top.frame.signature.outputElement.elementName, _), - top.frame.signature.namedInputElements))}) - }, - location=top.location)], - Silver_Expr { core:nothing() }, - nonterminalType("core:Maybe", [top.frame.signature.outputElement.typerep]), - location=top.location); + case s of + | functorRef(attr) -> + Silver_Expr { + core:just( + $Expr{ + mkFullFunctionInvocation( + top.location, + baseExpr(qName(top.location, top.frame.fullName), location=top.location), + map( + \ a::Pair -> + if a.snd + then Silver_Expr { $name{a.fst}.$QNameAttrOccur{attr} } + else Silver_Expr { $name{a.fst} }, + childAccesses), + map( + makeAnnoArg(top.location, top.frame.signature.outputElement.elementName, _), + top.frame.signature.namedInputElements))}) + } + | _ -> + {- Translation of all(s) for prod::(Foo ::= a::Foo b::Integer c::Bar): + case a.s, c.s of + | just(a_s), just(c_s) -> just(prod(a_s, b, c_s)) + | _, _ -> nothing() + end + Could also be implemented as chained monadic binds. Maybe more efficient this way? -} + caseExpr( + flatMap( + \ a::Pair -> + if a.snd then [Silver_Expr { $name{a.fst}.$name{sName} }] else [], + childAccesses), + [matchRule( + flatMap( + \ a::Pair -> + if a.snd + then + [decorate Silver_Pattern { core:just($name{a.fst ++ "_" ++ sBaseName}) } + with { config = top.config; env = top.env; frame = top.frame; patternVarEnv = []; }] + else [], + childAccesses), + nothing(), + Silver_Expr { + core:just( + $Expr{ + mkFullFunctionInvocation( + top.location, + baseExpr(qName(top.location, top.frame.fullName), location=top.location), + map( + \ a::Pair -> + if a.snd + then Silver_Expr { $name{a.fst ++ "_" ++ sBaseName} } + else Silver_Expr { $name{a.fst} }, + childAccesses), + map( + makeAnnoArg(top.location, top.frame.signature.outputElement.elementName, _), + top.frame.signature.namedInputElements))}) + }, + location=top.location)], + Silver_Expr { core:nothing() }, + nonterminalType("core:Maybe", [top.frame.signature.outputElement.typerep]), + location=top.location) + end; } abstract production someTraversal @@ -301,13 +314,6 @@ top::StrategyExpr ::= s::StrategyExpr { top.unparse = s"some(${s.unparse})"; - top.errors <- - case s of - -- TBH this doesn't seem very useful anyway - | functorRef(_) -> [err(s.location, "Functor attributes as arguments to generic traversals are not yet supported")] - | _ -> [] - end; - top.liftedStrategies := if s.attrRefName.isJust then [] @@ -323,49 +329,62 @@ top::StrategyExpr ::= s::StrategyExpr pair(e.elementName, attrMatchesFrame(top.env, sName, e.typerep)), top.frame.signature.inputElements); top.translation = - {- Translation of some(s) for prod::(Foo ::= a::Foo b::Integer c::Bar): - if a.s.isJust || c.s.isJust - then just(prod(fromMaybe(a, a.s), b, fromMaybe(c, c.s))) - else nothing() - Not sure of a clean way to do this with monads -} - Silver_Expr { - if $Expr{ - foldr( - or(_, '||', _, location=top.location), - falseConst('false', location=top.location), - map( - \ a::String -> Silver_Expr { $name{a}.$name{sName}.isJust }, - map(fst, filter(snd, childAccesses))))} - then - core:just( - $Expr{ - mkFullFunctionInvocation( - top.location, - baseExpr(qName(top.location, top.frame.fullName), location=top.location), - map( - \ a::Pair -> - if a.snd - then Silver_Expr { core:fromMaybe($name{a.fst}, $name{a.fst}.$name{sName}) } - else Silver_Expr { $name{a.fst} }, - childAccesses), - map( - makeAnnoArg(top.location, top.frame.signature.outputElement.elementName, _), - top.frame.signature.namedInputElements))}) - else core:nothing() - }; + case s of + | functorRef(attr) -> + Silver_Expr { + core:just( + $Expr{ + mkFullFunctionInvocation( + top.location, + baseExpr(qName(top.location, top.frame.fullName), location=top.location), + map( + \ a::Pair -> + if a.snd + then Silver_Expr { $name{a.fst}.$QNameAttrOccur{attr} } + else Silver_Expr { $name{a.fst} }, + childAccesses), + map( + makeAnnoArg(top.location, top.frame.signature.outputElement.elementName, _), + top.frame.signature.namedInputElements))}) + } + | _ -> + {- Translation of some(s) for prod::(Foo ::= a::Foo b::Integer c::Bar): + if a.s.isJust || c.s.isJust + then just(prod(fromMaybe(a, a.s), b, fromMaybe(c, c.s))) + else nothing() + Not sure of a clean way to do this with monads -} + Silver_Expr { + if $Expr{ + foldr( + or(_, '||', _, location=top.location), + falseConst('false', location=top.location), + map( + \ a::String -> Silver_Expr { $name{a}.$name{sName}.isJust }, + map(fst, filter(snd, childAccesses))))} + then + core:just( + $Expr{ + mkFullFunctionInvocation( + top.location, + baseExpr(qName(top.location, top.frame.fullName), location=top.location), + map( + \ a::Pair -> + if a.snd + then Silver_Expr { core:fromMaybe($name{a.fst}, $name{a.fst}.$name{sName}) } + else Silver_Expr { $name{a.fst} }, + childAccesses), + map( + makeAnnoArg(top.location, top.frame.signature.outputElement.elementName, _), + top.frame.signature.namedInputElements))}) + else core:nothing() + } + end; } abstract production oneTraversal top::StrategyExpr ::= s::StrategyExpr { top.unparse = s"one(${s.unparse})"; - top.errors <- - case s of - -- TBH this doesn't seem very useful anyway - | functorRef(_) -> [err(s.location, "Functor attributes as arguments to generic traversals are not yet supported")] - | _ -> [] - end; - top.liftedStrategies := if s.attrRefName.isJust then [] @@ -383,55 +402,76 @@ top::StrategyExpr ::= s::StrategyExpr top.frame.signature.inputElements); local matchingChildren::[String] = map(fst, filter(snd, childAccesses)); top.translation = - {- Translation of one(s) for prod::(Foo ::= a::Foo b::Integer c::Bar): - case a.s, c.s of - | just(a_s), _ -> just(prod(a_s, b, c)) - | _, just(c_s) -> just(prod(a, b, c_s)) - | _, _ -> nothing() - end - Could also be implemented as - orElse( - bindMaybe(a.s, \ a_s::Foo -> returnMaybe(prod(a_s, b, c))), - bindMaybe(c.s, \ c_s::Bar -> returnMaybe(prod(a, b, c_s))) -} - caseExpr( - map( - \ a::String -> Silver_Expr { $name{a}.$name{sName} }, - matchingChildren), - map( - \ i::Integer -> - let childI::String = head(drop(i, matchingChildren)) - in let childIndex::Integer = positionOf(stringEq, childI, map(fst, childAccesses)) - in - matchRule( - map( - \ p::Pattern -> decorate p with { config = top.config; env = top.env; frame = top.frame; patternVarEnv = []; }, - repeat(wildcPattern('_', location=top.location), i) ++ - Silver_Pattern { core:just($name{childI ++ "_" ++ sBaseName}) } :: - repeat(wildcPattern('_', location=top.location), length(matchingChildren) - (i + 1))), - nothing(), - Silver_Expr { - core:just( - $Expr{ - mkFullFunctionInvocation( - top.location, - baseExpr(qName(top.location, top.frame.fullName), location=top.location), - map( - \ a::Pair -> Silver_Expr { $name{a.fst} }, - take(childIndex, childAccesses)) ++ - Silver_Expr { $name{childI ++ "_" ++ sBaseName} } :: - map( - \ a::Pair -> Silver_Expr { $name{a.fst} }, - drop(childIndex + 1, childAccesses)), - map( - makeAnnoArg(top.location, top.frame.signature.outputElement.elementName, _), - top.frame.signature.namedInputElements))}) - }, - location=top.location) - end end, - range(0, length(matchingChildren))), - Silver_Expr { core:nothing() }, - nonterminalType("core:Maybe", [top.frame.signature.outputElement.typerep]), - location=top.location); + case s of + | functorRef(attr) when !null(matchingChildren) -> + Silver_Expr { + core:just( + $Expr{ + mkFullFunctionInvocation( + top.location, + baseExpr(qName(top.location, top.frame.fullName), location=top.location), + map( + \ a::Pair -> + if a.fst == head(matchingChildren) + then Silver_Expr { $name{a.fst}.$QNameAttrOccur{attr} } + else Silver_Expr { $name{a.fst} }, + childAccesses), + map( + makeAnnoArg(top.location, top.frame.signature.outputElement.elementName, _), + top.frame.signature.namedInputElements))}) + } + | functorRef(_) -> Silver_Expr { core:nothing() } + | _ -> + {- Translation of one(s) for prod::(Foo ::= a::Foo b::Integer c::Bar): + case a.s, c.s of + | just(a_s), _ -> just(prod(a_s, b, c)) + | _, just(c_s) -> just(prod(a, b, c_s)) + | _, _ -> nothing() + end + Could also be implemented as + orElse( + bindMaybe(a.s, \ a_s::Foo -> returnMaybe(prod(a_s, b, c))), + bindMaybe(c.s, \ c_s::Bar -> returnMaybe(prod(a, b, c_s))) -} + caseExpr( + map( + \ a::String -> Silver_Expr { $name{a}.$name{sName} }, + matchingChildren), + map( + \ i::Integer -> + let childI::String = head(drop(i, matchingChildren)) + in let childIndex::Integer = positionOf(stringEq, childI, map(fst, childAccesses)) + in + matchRule( + map( + \ p::Pattern -> decorate p with { config = top.config; env = top.env; frame = top.frame; patternVarEnv = []; }, + repeat(wildcPattern('_', location=top.location), i) ++ + Silver_Pattern { core:just($name{childI ++ "_" ++ sBaseName}) } :: + repeat(wildcPattern('_', location=top.location), length(matchingChildren) - (i + 1))), + nothing(), + Silver_Expr { + core:just( + $Expr{ + mkFullFunctionInvocation( + top.location, + baseExpr(qName(top.location, top.frame.fullName), location=top.location), + map( + \ a::Pair -> Silver_Expr { $name{a.fst} }, + take(childIndex, childAccesses)) ++ + Silver_Expr { $name{childI ++ "_" ++ sBaseName} } :: + map( + \ a::Pair -> Silver_Expr { $name{a.fst} }, + drop(childIndex + 1, childAccesses)), + map( + makeAnnoArg(top.location, top.frame.signature.outputElement.elementName, _), + top.frame.signature.namedInputElements))}) + }, + location=top.location) + end end, + range(0, length(matchingChildren))), + Silver_Expr { core:nothing() }, + nonterminalType("core:Maybe", [top.frame.signature.outputElement.typerep]), + location=top.location) + end; } abstract production prodTraversal @@ -451,7 +491,7 @@ top::StrategyExpr ::= prod::QName s::StrategyExprs s.givenInputElements = prod.lookupValue.dcl.namedSignature.inputElements; -- pair(child name, if attr occurs on child then just(attr name) else nothing()) - local childAccesses::[Pair>] = + local childAccesses::[Pair>>] = zipWith(pair, top.frame.signature.inputNames, s.attrRefNames); top.translation = if prod.lookupValue.fullName == top.frame.fullName @@ -464,17 +504,20 @@ top::StrategyExpr ::= prod::QName s::StrategyExprs Could also be implemented as chained monadic binds. Maybe more efficient this way? -} caseExpr( flatMap( - \ a::Pair> -> - case a.snd of just(attr) -> [Silver_Expr { $name{a.fst}.$name{attr} }] | nothing() -> [] end, + \ a::Pair>> -> + case a.snd of + | just(pair(false, attr)) -> [Silver_Expr { $name{a.fst}.$name{attr} }] + | _ -> [] + end, childAccesses), [matchRule( flatMap( - \ a::Pair> -> + \ a::Pair>> -> case a.snd of - | just(attr) -> + | just(pair(false, attr)) -> [decorate Silver_Pattern { core:just($name{a.fst ++ "_" ++ last(explode(":", attr))}) } with { config = top.config; env = top.env; frame = top.frame; patternVarEnv = []; }] - | nothing() -> [] + | _ -> [] end, childAccesses), nothing(), @@ -485,9 +528,10 @@ top::StrategyExpr ::= prod::QName s::StrategyExprs top.location, baseExpr(qName(top.location, top.frame.fullName), location=top.location), map( - \ a::Pair> -> + \ a::Pair>> -> case a.snd of - | just(attr) -> Silver_Expr { $name{a.fst ++ "_" ++ last(explode(":", attr))} } + | just(pair(true, attr)) -> Silver_Expr { $name{a.fst}.$name{attr} } + | just(pair(false, attr)) -> Silver_Expr { $name{a.fst ++ "_" ++ last(explode(":", attr))} } | nothing() -> Silver_Expr { $name{a.fst} } end, childAccesses), @@ -506,13 +550,6 @@ abstract production consStrategyExpr top::StrategyExprs ::= h::StrategyExpr t::StrategyExprs { top.unparse = s"${h.unparse}, ${t.unparse}"; - - top.errors <- - case h of - -- TBH this doesn't seem very useful anyway - | functorRef(_) -> [err(h.location, "Functor attributes as arguments to production traversals are not yet supported")] - | _ -> [] - end; top.liftedStrategies := -- Slight hack: when h is id (common case for prod traversals), there is no need for a new attribute. @@ -526,7 +563,10 @@ top::StrategyExprs ::= h::StrategyExpr t::StrategyExprs local hType::Type = head(top.givenInputElements).typerep; local attr::String = fromMaybe(h.genName, h.attrRefName); local attrMatch::Boolean = attrMatchesFrame(top.env, attr, hType); - top.attrRefNames = (if attrMatch && !h.isId then just(attr) else nothing()) :: t.attrRefNames; + top.attrRefNames = + (if attrMatch && !h.isId + then just(pair(case h of functorRef(_) -> true | _ -> false end, attr)) + else nothing()) :: t.attrRefNames; top.errors <- if !null(top.givenInputElements) && !attrMatch && !h.isId then [wrn(h.location, s"This (non-identity) strategy attribute does not occur on ${prettyType(hType)} and will be treated as identity")] diff --git a/test/silver_features/Strategy.sv b/test/silver_features/Strategy.sv index 797e3559f..b94255b63 100644 --- a/test/silver_features/Strategy.sv +++ b/test/silver_features/Strategy.sv @@ -82,13 +82,13 @@ equalityTest( String, silver_tests); -functor attribute incAllConsts occurs on SStmt, SExpr; -propagate incAllConsts on SStmt, SExpr excluding constSExpr; +functor attribute incConsts occurs on SStmt, SExpr; +propagate incConsts on SStmt, SExpr excluding constSExpr; aspect production constSExpr top::SExpr ::= i::Integer -{ top.incAllConsts = constSExpr(i + 1); } +{ top.incConsts = constSExpr(i + 1); } -strategy attribute incTwice = incAllConsts <* incAllConsts +strategy attribute incTwice = incConsts <* incConsts occurs on SStmt, SExpr; propagate incTwice on SStmt, SExpr; @@ -104,7 +104,7 @@ strategy attribute incTargetConsts = allTopDown( rule on top::SStmt of | assignSStmt(n, _) when n == top.target -> top - end <* incAllConsts) + end <* incConsts) occurs on SStmt, SExpr; propagate incTargetConsts on SStmt, SExpr; @@ -118,7 +118,7 @@ equalityTest( "core:just(silver_features:seqSStmt(silver_features:assignSStmt(\"a\", silver_features:addSExpr(silver_features:constSExpr(42), silver_features:constSExpr(0))), silver_features:assignSStmt(\"b\", silver_features:addSExpr(silver_features:addSExpr(silver_features:idSExpr(\"a\"), silver_features:constSExpr(3)), silver_features:constSExpr(18)))))", String, silver_tests); -strategy attribute incThenElim = incAllConsts <* elimPlusZero +strategy attribute incThenElim = incConsts <* elimPlusZero occurs on SStmt, SExpr; propagate incThenElim on SStmt, SExpr; @@ -127,3 +127,39 @@ equalityTest( assignSStmt("a", addSExpr(constSExpr(42), constSExpr(-1))).incThenElim), "core:just(silver_features:assignSStmt(\"a\", silver_features:constSExpr(43)))", String, silver_tests); + + +strategy attribute incAll = all(incConsts) occurs on SStmt, SExpr; +strategy attribute incSome = some(incConsts) occurs on SStmt, SExpr; +strategy attribute incOne = one(incConsts) occurs on SStmt, SExpr; +strategy attribute incFstElimSnd = seqSStmt(incConsts, elimPlusZero) occurs on SStmt, SExpr; +propagate incAll, incSome, incOne, incFstElimSnd on SStmt, SExpr; + +equalityTest( + hackUnparse( + seqSStmt( + assignSStmt("a", constSExpr(1)), + assignSStmt("b", constSExpr(2))).incAll), + "core:just(silver_features:seqSStmt(silver_features:assignSStmt(\"a\", silver_features:constSExpr(2)), silver_features:assignSStmt(\"b\", silver_features:constSExpr(3))))", + String, silver_tests); +equalityTest( + hackUnparse( + seqSStmt( + assignSStmt("a", constSExpr(1)), + assignSStmt("b", constSExpr(2))).incSome), + "core:just(silver_features:seqSStmt(silver_features:assignSStmt(\"a\", silver_features:constSExpr(2)), silver_features:assignSStmt(\"b\", silver_features:constSExpr(3))))", + String, silver_tests); +equalityTest( + hackUnparse( + seqSStmt( + assignSStmt("a", constSExpr(1)), + assignSStmt("b", constSExpr(2))).incOne), + "core:just(silver_features:seqSStmt(silver_features:assignSStmt(\"a\", silver_features:constSExpr(2)), silver_features:assignSStmt(\"b\", silver_features:constSExpr(2))))", + String, silver_tests); +equalityTest( + hackUnparse( + seqSStmt( + assignSStmt("a", addSExpr(constSExpr(1), constSExpr(0))), + assignSStmt("b", addSExpr(constSExpr(2), constSExpr(0)))).incFstElimSnd), + "core:just(silver_features:seqSStmt(silver_features:assignSStmt(\"a\", silver_features:addSExpr(silver_features:constSExpr(2), silver_features:constSExpr(1))), silver_features:assignSStmt(\"b\", silver_features:constSExpr(2))))", + String, silver_tests); From 302ec99ce33cd9079b460251fbf6c25ad8f207b2 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Tue, 28 Apr 2020 15:39:22 -0500 Subject: [PATCH 53/78] Fix StrategyExpr construction translation bug causing recComb genNames to contain 'err' --- grammars/silver/extension/strategyattr/ConcreteSyntax.sv | 2 +- .../silver/extension/strategyattr/construction/Construction.sv | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/grammars/silver/extension/strategyattr/ConcreteSyntax.sv b/grammars/silver/extension/strategyattr/ConcreteSyntax.sv index 94ee84756..a5d3822a0 100644 --- a/grammars/silver/extension/strategyattr/ConcreteSyntax.sv +++ b/grammars/silver/extension/strategyattr/ConcreteSyntax.sv @@ -66,7 +66,7 @@ concrete productions top::StrategyExpr_c { top.unparse = s"rec ${n.name} -> (${s.unparse})"; top.ast = recComb(n, s.ast, genName=top.givenGenName, location=top.location); - s.givenGenName = top.givenGenName ++ "_" ++ n.name; + s.givenGenName = top.givenGenName; } | 'rule' 'on' id::Name '::' ty::TypeExpr 'of' Opt_Vbar_t ml::MRuleList 'end' { diff --git a/grammars/silver/extension/strategyattr/construction/Construction.sv b/grammars/silver/extension/strategyattr/construction/Construction.sv index 37d7d137a..5300ec7cc 100644 --- a/grammars/silver/extension/strategyattr/construction/Construction.sv +++ b/grammars/silver/extension/strategyattr/construction/Construction.sv @@ -16,7 +16,7 @@ terminal AntiquoteStrategyQName_t '$strategyQName' lexer classes {Antiquote, Str concrete production quoteStrategyExpr top::Expr ::= 'Silver_StrategyExpr' '(' genName::Expr ')' '{' cst::StrategyExpr_c '}' { - top.unparse = s"Silver_StrategyExpr {${cst.unparse}}"; + top.unparse = s"Silver_StrategyExpr (${genName.unparse}) {${cst.unparse}}"; -- The meta-translation library directly translates all annotation values into -- static initialization code, however we want to specify genName at runtime. -- Solution: construct the term with "" as the base genName and translate it From a1572e5efc67455510110e2575e09d955192c623 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Sat, 2 May 2020 15:07:47 -0500 Subject: [PATCH 54/78] More comments about functor translation cases --- .../silver/extension/strategyattr/StrategyExpr.sv | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/grammars/silver/extension/strategyattr/StrategyExpr.sv b/grammars/silver/extension/strategyattr/StrategyExpr.sv index b79e30c58..3b6aced04 100644 --- a/grammars/silver/extension/strategyattr/StrategyExpr.sv +++ b/grammars/silver/extension/strategyattr/StrategyExpr.sv @@ -181,6 +181,8 @@ top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr if !s1.matchesFrame || !s2.matchesFrame then Silver_Expr { core:nothing() } else + -- Optimizations when one or both of these is a functor, in this case a + -- monadic bind may not be required. case s1, s2 of | functorRef(attr1), functorRef(attr2) -> Silver_Expr { @@ -248,6 +250,8 @@ top::StrategyExpr ::= s::StrategyExpr top.translation = case s of | functorRef(attr) -> + {- When s is a functor, optimized translation of all(s) for prod::(Foo ::= a::Foo b::Integer c::Bar): + just(prod(a.s, b, c.s)) -} Silver_Expr { core:just( $Expr{ @@ -331,6 +335,8 @@ top::StrategyExpr ::= s::StrategyExpr top.translation = case s of | functorRef(attr) -> + {- When s is a functor, optimized translation of all(s) for prod::(Foo ::= a::Foo b::Integer c::Bar): + just(prod(a.s, b, c.s)) -} Silver_Expr { core:just( $Expr{ @@ -404,6 +410,8 @@ top::StrategyExpr ::= s::StrategyExpr top.translation = case s of | functorRef(attr) when !null(matchingChildren) -> + {- When s is a functor, optimized translation of all(s) for prod::(Foo ::= a::Foo b::Integer c::Bar): + just(prod(a.s, b, c)) -} Silver_Expr { core:just( $Expr{ @@ -496,9 +504,10 @@ top::StrategyExpr ::= prod::QName s::StrategyExprs top.translation = if prod.lookupValue.fullName == top.frame.fullName then - {- Translation of prod(s1, s2, s3) for prod::(Foo ::= a::Foo b::Integer c::Bar): + {- Translation of prod(s1, s2, s3, s4) for prod::(Foo ::= a::Foo b::Integer c::Bar d::Baz) + where s4 is a functor: case a.s1, c.s3 of - | just(a_s1), just(c_s3) -> just(prod(a_s1, b, c_s3)) + | just(a_s1), just(c_s3) -> just(prod(a_s1, b, c_s3, d.s4)) | _, _ -> nothing() end Could also be implemented as chained monadic binds. Maybe more efficient this way? -} From 97c9c5fb113d9257e6ee845b395ffe13c8beed90 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Wed, 6 May 2020 21:04:37 -0500 Subject: [PATCH 55/78] Distinguish partial/total strategies, translate total strategy attributes like functors --- grammars/silver/definition/core/QName.sv | 2 + .../extension/strategyattr/ConcreteSyntax.sv | 12 +- .../silver/extension/strategyattr/DclInfo.sv | 20 +- .../silver/extension/strategyattr/Strategy.sv | 51 +- .../extension/strategyattr/StrategyExpr.sv | 450 +++++++++++------- .../extension/strategyattr/StrategyUtils.sv | 5 +- .../extension/strategyattr/Terminals.sv | 1 + .../strategyattr/convenience/Convenience.sv | 15 +- test/silver_features/Strategy.sv | 43 +- .../rewrite/expreval/AbstractSyntax.sv | 14 +- .../silver_features/rewrite/expreval/Tests.sv | 30 +- 11 files changed, 393 insertions(+), 250 deletions(-) diff --git a/grammars/silver/definition/core/QName.sv b/grammars/silver/definition/core/QName.sv index b97321526..f5a7252bf 100644 --- a/grammars/silver/definition/core/QName.sv +++ b/grammars/silver/definition/core/QName.sv @@ -216,6 +216,8 @@ top::QNameAttrOccur ::= at::QName top.dcl = if top.found then head(dclsNarrowed) else error("INTERNAL ERROR: Accessing dcl of occurrence " ++ at.name ++ " at " ++ top.grammarName ++ " " ++ top.location.unparse); top.attrDcl = if top.found then head(attrsNarrowed) else + -- Workaround fix for proper error reporting - appairently there are some places where this is still demanded. + if !null(at.lookupAttribute.dcls) then head(at.lookupAttribute.dcls) else error("INTERNAL ERROR: Accessing dcl of attribute " ++ at.name ++ " at " ++ top.grammarName ++ " " ++ top.location.unparse); } diff --git a/grammars/silver/extension/strategyattr/ConcreteSyntax.sv b/grammars/silver/extension/strategyattr/ConcreteSyntax.sv index a5d3822a0..60ce9cebb 100644 --- a/grammars/silver/extension/strategyattr/ConcreteSyntax.sv +++ b/grammars/silver/extension/strategyattr/ConcreteSyntax.sv @@ -2,12 +2,20 @@ grammar silver:extension:strategyattr; inherited attribute givenGenName::String; -concrete production strategyAttributeDcl_c +concrete production partialStrategyAttributeDcl +top::AGDcl ::= 'partial' 'strategy' 'attribute' a::Name '=' e::StrategyExpr_c ';' +{ + top.unparse = "strategy attribute " ++ a.unparse ++ "=" ++ e.unparse ++ ";"; + e.givenGenName = a.name; + forwards to strategyAttributeDcl(false, a, [], e.ast, location=top.location); +} + +concrete production totalStrategyAttributeDcl top::AGDcl ::= 'strategy' 'attribute' a::Name '=' e::StrategyExpr_c ';' { top.unparse = "strategy attribute " ++ a.unparse ++ "=" ++ e.unparse ++ ";"; e.givenGenName = a.name; - forwards to strategyAttributeDcl(a, [], e.ast, location=top.location); + forwards to strategyAttributeDcl(true, a, [], e.ast, location=top.location); } closed nonterminal StrategyExpr_c with location, givenGenName, unparse, ast; diff --git a/grammars/silver/extension/strategyattr/DclInfo.sv b/grammars/silver/extension/strategyattr/DclInfo.sv index 589349f14..f68ea7ed3 100644 --- a/grammars/silver/extension/strategyattr/DclInfo.sv +++ b/grammars/silver/extension/strategyattr/DclInfo.sv @@ -1,32 +1,42 @@ grammar silver:extension:strategyattr; +synthesized attribute isStrategy::Boolean occurs on DclInfo; +attribute isTotal occurs on DclInfo; synthesized attribute containsErrors::Boolean occurs on DclInfo; synthesized attribute liftedStrategyNames::[String] occurs on DclInfo; -synthesized attribute givenRecVarEnv::[Pair] occurs on DclInfo; +synthesized attribute givenRecVarEnv::[Pair>] occurs on DclInfo; +attribute totalRefs occurs on DclInfo; synthesized attribute strategyExpr :: StrategyExpr occurs on DclInfo; aspect default production top::DclInfo ::= { + top.isStrategy = false; + top.isTotal = true; top.containsErrors = false; top.liftedStrategyNames = []; top.givenRecVarEnv = []; + top.totalRefs := []; top.strategyExpr = error("Internal compiler error: must be defined for all strategy attribute declarations"); } abstract production strategyDcl top::DclInfo ::= - sg::String sl::Location fn::String tyVar::TyVar - containsErrors::Boolean liftedStrategyNames::[String] givenRecVarEnv::[Pair] + sg::String sl::Location fn::String isTotal::Boolean tyVar::TyVar + containsErrors::Boolean liftedStrategyNames::[String] givenRecVarEnv::[Pair>] totalRefs::[String] e::StrategyExpr { top.sourceGrammar = sg; top.sourceLocation = sl; top.fullName = fn; - top.typerep = nonterminalType("core:Maybe", [varType(tyVar)]); + top.typerep = + if isTotal + then varType(tyVar) + else nonterminalType("core:Maybe", [varType(tyVar)]); top.dclBoundVars = [tyVar]; top.isSynthesized = true; + top.isStrategy = true; top.decoratedAccessHandler = synDecoratedAccessHandler(_, _, location=_); top.undecoratedAccessHandler = accessBounceDecorate(synDecoratedAccessHandler(_, _, location=_), _, _, _); @@ -34,8 +44,10 @@ top::DclInfo ::= top.attributionDispatcher = strategyAttributionDcl(_, _, _, _, location=_); top.propagateDispatcher = propagateStrategy(_, location=_); + top.isTotal = isTotal; top.containsErrors = containsErrors; top.liftedStrategyNames = liftedStrategyNames; top.givenRecVarEnv = givenRecVarEnv; + top.totalRefs := totalRefs; top.strategyExpr = e; } diff --git a/grammars/silver/extension/strategyattr/Strategy.sv b/grammars/silver/extension/strategyattr/Strategy.sv index 3c69040e4..2ca9a940e 100644 --- a/grammars/silver/extension/strategyattr/Strategy.sv +++ b/grammars/silver/extension/strategyattr/Strategy.sv @@ -4,9 +4,9 @@ import silver:definition:flow:driver only ProductionGraph, FlowType, constructAn import silver:driver:util; abstract production strategyAttributeDcl -top::AGDcl ::= a::Name recVarEnv::[Pair] e::StrategyExpr +top::AGDcl ::= isTotal::Boolean a::Name recVarEnv::[Pair>] e::StrategyExpr { - top.unparse = "strategy attribute " ++ a.unparse ++ "=" ++ e.unparse ++ ";"; + top.unparse = (if isTotal then "" else "partial ") ++ "strategy attribute " ++ a.unparse ++ "=" ++ e.unparse ++ ";"; production attribute fName :: String; fName = top.grammarName ++ ":" ++ a.name; @@ -23,6 +23,11 @@ top::AGDcl ::= a::Name recVarEnv::[Pair] e::StrategyExpr if null(getValueDcl("core:monad:bindMaybe", top.env)) then [err(top.location, "Strategy attributes require import of core:monad")] else []; + top.errors <- + if isTotal && !e.isTotal + -- Not an error since we can still translate this, but the translation may raise run-time errors in case of failure + then [wrn(e.location, s"Implementation of total strategy ${a.name} is not total")] + else []; -- Frame doesn't really matter, since we will re-check any expressions occuring in e when propagated. -- Need all this to construct a bogus frame... @@ -33,7 +38,7 @@ top::AGDcl ::= a::Name recVarEnv::[Pair] e::StrategyExpr e.frame = globalExprContext(myFlowGraph); e.recVarEnv = recVarEnv; - e.outerAttr = just(a.name); + e.outerAttr = just(pair(isTotal, a.name)); local fwrd::AGDcl = foldr( @@ -42,12 +47,12 @@ top::AGDcl ::= a::Name recVarEnv::[Pair] e::StrategyExpr [attrDef( defaultEnvItem( strategyDcl( - top.grammarName, a.location, fName, freshTyVar(), - !null(top.errors), map(fst, e.liftedStrategies), recVarEnv, e)))], + top.grammarName, a.location, fName, isTotal, freshTyVar(), + !null(top.errors), map(fst, e.liftedStrategies), recVarEnv, e.totalRefs, e)))], location=top.location), map( \ d::Pair -> - strategyAttributeDcl(name(d.fst, top.location), d.snd.recVarEnv, new(d.snd), location=top.location), + strategyAttributeDcl(d.snd.isTotalInf, name(d.fst, top.location), d.snd.recVarEnv, new(d.snd), location=top.location), e.liftedStrategies)); --forwards to unsafeTrace(fwrd, print(a.name ++ " = " ++ e.unparse ++ "; lifted " ++ implode(", ", map(fst, e.liftedStrategies)) ++ "\n\n", unsafeIO())); @@ -57,11 +62,23 @@ top::AGDcl ::= a::Name recVarEnv::[Pair] e::StrategyExpr abstract production strategyAttributionDcl top::AGDcl ::= at::Decorated QName attl::BracketedOptTypeExprs nt::QName nttl::BracketedOptTypeExprs { - local localErrors::[Message] = - attl.errors ++ attl.errorsTyVars ++ nt.lookupType.errors ++ nttl.errors ++ nttl.errorsTyVars ++ + production attribute localErrors::[Message] with ++; + localErrors := + attl.errors ++ attl.errorsTyVars ++ nt.lookupType.errors ++ nttl.errors ++ nttl.errorsTyVars; + localErrors <- if length(attl.types) > 0 then [err(attl.location, "Explicit type arguments are not allowed for strategy attributes")] else []; + + -- Technically we could do this check on the propagate, but it seems clearer to raise it here + localErrors <- + flatMap( + \ totalAttr::String -> + if null(getOccursDcl(totalAttr, nt.lookupType.fullName, top.env)) + then [err(top.location, s"Total strategy attribute ${totalAttr} referenced by ${at.name} does not occur on ${nt.name}")] + else [], + at.lookupAttribute.dcl.totalRefs); + -- TODO: Check that the type parameters of any rules of type nt match nttl top.errors := if !null(localErrors) then localErrors else forward.errors; @@ -96,20 +113,17 @@ top::ProductionStmt ::= attr::Decorated QName { top.unparse = s"propagate ${attr.unparse}"; + production isTotal::Boolean = attr.lookupAttribute.dcl.isTotal; production e::StrategyExpr = attr.lookupAttribute.dcl.strategyExpr; e.grammarName = top.grammarName; e.config = top.config; e.frame = top.frame; e.env = top.env; e.recVarEnv = attr.lookupAttribute.dcl.givenRecVarEnv; - e.outerAttr = just(attr.lookupAttribute.fullName); + e.outerAttr = just(pair(isTotal, attr.lookupAttribute.fullName)); e.inlinedStrategies = [attr.lookupAttribute.fullName]; -- Don't unfold the top-level strategy within itself - production e2::StrategyExpr = - case e.optimize of - | just(e2) -> e2 - | nothing() -> error("optimize failed for " ++ e.unparse) - end; + production e2::StrategyExpr = e.optimize; e2.grammarName = e.grammarName; e2.config = e.config; e2.frame = e.frame; @@ -121,7 +135,10 @@ top::ProductionStmt ::= attr::Decorated QName -- Can't do this with forwarding to avoid circular dependency of -- forward -> dcl.containsErrors -> dcl.flowEnv -> forward.flowDefs top.errors := - if attr.lookupAttribute.dcl.containsErrors + if + attr.lookupAttribute.dcl.containsErrors || + -- Check for total strategy ref occurs errors that would already be reported on the occurence + any(map(null, map(getOccursDcl(_, top.frame.signature.outputElement.typerep.typeName, top.env), attr.lookupAttribute.dcl.totalRefs))) then [] else forward.errors; @@ -133,13 +150,13 @@ top::ProductionStmt ::= attr::Decorated QName '.', qNameAttrOccur(new(attr), location=top.location), '=', - e2.translation, + if isTotal then e2.totalTranslation else e2.partialTranslation, ';', location=top.location), map( \ n::String -> propagateOneAttr(qName(top.location, n), location=top.location), attr.lookupAttribute.dcl.liftedStrategyNames)); - --forwards to unsafeTrace(fwrd, print(attr.name ++ " on " ++ top.frame.fullName ++ " = " ++ e2.translation.unparse ++ ";\n\n", unsafeIO())); + --forwards to unsafeTrace(fwrd, print(attr.name ++ " on " ++ top.frame.fullName ++ " = " ++ (if isTotal then e2.totalTranslation else e2.partialTranslation).unparse ++ ";\n\n", unsafeIO())); forwards to fwrd; } diff --git a/grammars/silver/extension/strategyattr/StrategyExpr.sv b/grammars/silver/extension/strategyattr/StrategyExpr.sv index 3b6aced04..9484b3db0 100644 --- a/grammars/silver/extension/strategyattr/StrategyExpr.sv +++ b/grammars/silver/extension/strategyattr/StrategyExpr.sv @@ -5,26 +5,29 @@ import core:monad; annotation genName::String; -- Used to generate the names of lifted strategy attributes -autocopy attribute recVarEnv::[Pair]; -inherited attribute outerAttr::Maybe; +autocopy attribute recVarEnv::[Pair>]; -- name, (isTotal, genName) +inherited attribute outerAttr::Maybe>; -- isTotal, genName autocopy attribute inlinedStrategies::[String]; monoid attribute liftedStrategies::[Pair] with [], ++; synthesized attribute attrRefName::Maybe; synthesized attribute isId::Boolean; -synthesized attribute isSuccess::Boolean; +synthesized attribute isTotalInf::Boolean; -- Env-independant, used for inference +synthesized attribute isTotal::Boolean; -- Env-dependant, used for translation / optimization inherited attribute givenInputElements::[NamedSignatureElement]; synthesized attribute attrRefNames::[Maybe>]; monoid attribute containsFail::Boolean with false, ||; monoid attribute allId::Boolean with true, &&; -monoid attribute matchesFrame::Boolean with false, ||; monoid attribute freeRecVars::[String] with [], ++; +monoid attribute totalRefs::[String] with [], ++; +monoid attribute matchesFrame::Boolean with false, ||; -synthesized attribute translation::a; +synthesized attribute partialTranslation::Expr; -- Maybe on a +synthesized attribute totalTranslation::Expr; -- a on a, can raise a runtime error if demanded on partial strategy expression -- Nonterminal-independent algebraic simplifications -- Theoretically these could be applied to the strategy before lifting/propagation, -- but probably not much of an improvement. -strategy attribute genericStep = +partial strategy attribute genericStep = rule on top::StrategyExpr of | sequence(fail(), _) -> fail(location=top.location, genName=top.genName) | sequence(_, fail()) -> fail(location=top.location, genName=top.genName) @@ -32,7 +35,7 @@ strategy attribute genericStep = | sequence(s, id()) -> s | choice(fail(), s) -> s | choice(s, fail()) -> s - | choice(s, _) when s.isSuccess -> s + | choice(s, _) when s.isTotal -> s | allTraversal(id()) -> id(location=top.location, genName=top.genName) | someTraversal(fail()) -> fail(location=top.location, genName=top.genName) | oneTraversal(fail()) -> fail(location=top.location, genName=top.genName) @@ -42,18 +45,21 @@ strategy attribute genericStep = | inlined(_, fail()) -> fail(location=top.location, genName=top.genName) end; -- Nonterminal-dependent, production-independent optimizations -strategy attribute ntStep = +partial strategy attribute ntStep = rule on top::StrategyExpr of - | strategyRef(n) when n.matchesFrame && !containsBy(stringEq, n.attrDcl.fullName, top.inlinedStrategies) && null(n.attrDcl.givenRecVarEnv) -> + -- Only inline references to partial strategies, as inlining total + -- strategies would not permit any additional simplification. + | partialRef(n) when + n.matchesFrame && n.attrDcl.isStrategy && + !containsBy(stringEq, n.attrDcl.fullName, top.inlinedStrategies) && null(n.attrDcl.givenRecVarEnv) -> inlined(n, n.attrDcl.strategyExpr, location=top.location, genName=top.genName) - | strategyRef(n) when !n.matchesFrame -> fail(location=top.location, genName=top.genName) - | functorRef(n) when !n.matchesFrame -> fail(location=top.location, genName=top.genName) + | partialRef(n) when !n.matchesFrame -> fail(location=top.location, genName=top.genName) | inlined(n, _) when !n.matchesFrame -> fail(location=top.location, genName=top.genName) | inlined(n, id()) when n.matchesFrame -> id(location=top.location, genName=top.genName) - | inlined(n1, functorRef(n2)) when n1.matchesFrame -> functorRef(n2, location=top.location, genName=top.genName) + | inlined(n1, totalRef(n2)) when n1.matchesFrame -> totalRef(n2, location=top.location, genName=top.genName) end; -- Production-dependent optimizations -strategy attribute prodStep = +partial strategy attribute prodStep = rule on top::StrategyExpr of | allTraversal(s) when !attrMatchesChild(top.env, fromMaybe(s.genName, s.attrRefName), top.frame) -> id(location=top.location, genName=top.genName) | someTraversal(s) when !attrMatchesChild(top.env, fromMaybe(s.genName, s.attrRefName), top.frame) -> fail(location=top.location, genName=top.genName) @@ -85,43 +91,63 @@ strategy attribute optimize = nonterminal StrategyExpr with config, grammarName, env, location, unparse, errors, frame, compiledGrammars, flowEnv, flowDefs, -- Normal expression stuff - genName, recVarEnv, outerAttr, liftedStrategies, attrRefName, isId, isSuccess, - translation, matchesFrame, freeRecVars, - inlinedStrategies, genericStep, ntStep, prodStep, simplify, optimize; + genName, recVarEnv, outerAttr, liftedStrategies, attrRefName, isId, isTotalInf, isTotal, freeRecVars, totalRefs, -- Frame-independent attrs + partialTranslation, totalTranslation, matchesFrame, -- Frame-dependent attrs + inlinedStrategies, genericStep, ntStep, prodStep, simplify, optimize; -- Optimization stuff nonterminal StrategyExprs with config, grammarName, env, unparse, errors, frame, compiledGrammars, flowEnv, flowDefs, -- Normal expression stuff - recVarEnv, givenInputElements, liftedStrategies, attrRefNames, - containsFail, allId, freeRecVars, - inlinedStrategies, simplify; + recVarEnv, givenInputElements, liftedStrategies, attrRefNames, containsFail, allId, freeRecVars, totalRefs, -- Frame-independent attrs + inlinedStrategies, simplify; -- Optimization stuff flowtype StrategyExpr = decorate {grammarName, config, recVarEnv, outerAttr}, -- NOT frame or env + -- Normal expression stuff unparse {}, errors {decorate, frame, env, compiledGrammars, flowEnv}, flowDefs {decorate, frame, env, compiledGrammars, flowEnv}, - liftedStrategies {decorate}, attrRefName {decorate}, isId {decorate}, isSuccess {decorate, env}, - translation {decorate, frame, env}, matchesFrame {decorate, frame, env}, freeRecVars {decorate, env}; + -- Frame-independent attrs + liftedStrategies {decorate}, attrRefName {decorate}, isId {decorate}, isTotalInf {decorate}, isTotal {decorate, env}, freeRecVars {decorate, env}, totalRefs {decorate, env}, + -- Frame-dependent attrs + partialTranslation {decorate, frame, env}, totalTranslation {decorate, frame, env}, matchesFrame {decorate, frame, env}; flowtype StrategyExprs = decorate {grammarName, config, recVarEnv}, -- NOT frame or env + -- Normal expression stuff unparse {}, errors {decorate, frame, env, givenInputElements, compiledGrammars, flowEnv}, flowDefs {decorate, frame, env, compiledGrammars, flowEnv}, + -- Frame-independent attrs liftedStrategies {decorate}, attrRefNames {decorate, env, givenInputElements}, - containsFail {decorate, env}, allId {decorate, env}, freeRecVars {decorate, env}; + containsFail {decorate, env}, allId {decorate, env}, freeRecVars {decorate, env}, totalRefs {decorate, env}; -propagate errors on StrategyExpr, StrategyExprs excluding strategyRef, functorRef; +propagate errors on StrategyExpr, StrategyExprs excluding partialRef, totalRef; propagate flowDefs on StrategyExpr, StrategyExprs; propagate containsFail, allId on StrategyExprs; propagate freeRecVars on StrategyExpr, StrategyExprs excluding recComb; +propagate totalRefs on StrategyExpr, StrategyExprs; propagate simplify on StrategyExprs; propagate prodStep on MRuleList; propagate genericStep, ntStep, prodStep, simplify, optimize on StrategyExpr; +-- Convert an expression of type a to Maybe +function asPartial +Expr ::= e::Expr +{ return Silver_Expr { core:just($Expr{e}) }; } + +-- Convert an expression of type Maybe to a +function asTotal +Expr ::= e::Expr +{ return Silver_Expr { core:fromMaybe(core:error("Total result demanded when partial strategy failed"), $Expr{e}) }; } + aspect default production top::StrategyExpr ::= { + -- At least 1 of these should be defined for every production: + top.partialTranslation = asPartial(top.totalTranslation); + top.totalTranslation = asTotal(top.partialTranslation); + top.attrRefName = nothing(); top.matchesFrame := true; -- Consulted only when attrRefName is just(...) top.isId = false; - top.isSuccess = false; + top.isTotalInf = false; + top.isTotal = false; } -- Basic combinators @@ -131,8 +157,9 @@ top::StrategyExpr ::= top.unparse = "id"; propagate liftedStrategies; top.isId = true; - top.isSuccess = true; - top.translation = Silver_Expr { core:just($name{top.frame.signature.outputElement.elementName}) }; + top.isTotalInf = true; + top.isTotal = true; + top.totalTranslation = Silver_Expr { $name{top.frame.signature.outputElement.elementName} }; } abstract production fail @@ -140,24 +167,31 @@ top::StrategyExpr ::= { top.unparse = "fail"; propagate liftedStrategies; - top.translation = Silver_Expr { core:nothing() }; + top.partialTranslation = Silver_Expr { core:nothing() }; } abstract production sequence top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr { top.unparse = s"(${s1.unparse} <* ${s2.unparse})"; + + local s2Name::String = fromMaybe(top.genName ++ "_fst", s2.attrRefName); top.liftedStrategies := s1.liftedStrategies ++ if s2.attrRefName.isJust then [] - else [pair(s2.genName, s2)]; - top.isSuccess = s1.isSuccess && s2.isSuccess; + else [pair(s2Name, s2)]; + top.isTotalInf = s1.isTotalInf && s2.isTotalInf; + top.isTotal = + s1.isTotal && + -- If s2 is lifted, then we must determine totality without the env + if s2.attrRefName.isJust + then s2.isTotal + else s2.isTotalInf; s1.outerAttr = nothing(); s2.outerAttr = nothing(); - local s2Name::String = fromMaybe(s2.genName, s2.attrRefName); -- Equations for all inh attributes on the nt that we know about. -- This is safe because the MWDA requires that all inh dependencies of a syn attribute -- be exported by the syn occurence anyway. @@ -177,39 +211,40 @@ top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr flatMap( getAttrDcl(_, top.env), map((.attrOccurring), getAttrsOn(top.frame.lhsNtName, top.env)))))); - top.translation = - if !s1.matchesFrame || !s2.matchesFrame - then Silver_Expr { core:nothing() } - else - -- Optimizations when one or both of these is a functor, in this case a - -- monadic bind may not be required. - case s1, s2 of - | functorRef(attr1), functorRef(attr2) -> - Silver_Expr { - core:just( - decorate $name{top.frame.signature.outputElement.elementName}.$QNameAttrOccur{attr1} - with { $ExprInhs{allInhs} }.$QNameAttrOccur{attr2}) - } - | functorRef(attr1), _ -> - Silver_Expr { - decorate $name{top.frame.signature.outputElement.elementName}.$QNameAttrOccur{attr1} - with { $ExprInhs{allInhs} }.$name{s2Name} - } - | _, functorRef(attr2) -> - Silver_Expr { - core:mapMaybe( - \ res::$TypeExpr{typerepTypeExpr(top.frame.signature.outputElement.typerep, location=top.location)} -> - decorate res with { $ExprInhs{allInhs} }.$QNameAttrOccur{attr2}, - $Expr{s1.translation}) - } - | _, _ -> - Silver_Expr { - core:monad:bindMaybe( - $Expr{s1.translation}, - \ res::$TypeExpr{typerepTypeExpr(top.frame.signature.outputElement.typerep, location=top.location)} -> - decorate res with { $ExprInhs{allInhs} }.$name{s2Name}) - } - end; + top.partialTranslation = + -- Optimizations when one or both of these is total, in this case a + -- monadic bind may not be required. + case s1.isTotal, s2.isTotal of + | true, true -> + Silver_Expr { + core:just(decorate $Expr{s1.totalTranslation} with { $ExprInhs{allInhs} }.$name{s2Name}) + } + | true, false -> + Silver_Expr { + decorate $Expr{s1.totalTranslation} with { $ExprInhs{allInhs} }.$name{s2Name} + } + | false, true -> + Silver_Expr { + core:mapMaybe( + \ res::$TypeExpr{typerepTypeExpr(top.frame.signature.outputElement.typerep, location=top.location)} -> + decorate res with { $ExprInhs{allInhs} }.$name{s2Name}, + $Expr{s1.partialTranslation}) + } + | false, false -> + Silver_Expr { + core:monad:bindMaybe( + $Expr{s1.partialTranslation}, + \ res::$TypeExpr{typerepTypeExpr(top.frame.signature.outputElement.typerep, location=top.location)} -> + decorate res with { $ExprInhs{allInhs} }.$name{s2Name}) + } + end; + top.totalTranslation = + if s1.isTotal && s2.isTotal + then + Silver_Expr { + decorate $Expr{s1.totalTranslation} with { $ExprInhs{allInhs} }.$name{s2Name} + } + else asTotal(top.partialTranslation); } abstract production choice @@ -217,12 +252,25 @@ top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr { top.unparse = s"(${s1.unparse} <+ ${s2.unparse})"; propagate liftedStrategies; - top.isSuccess = s1.isSuccess || s2.isSuccess; + top.isTotalInf = s1.isTotalInf || s2.isTotalInf; + top.isTotal = s1.isTotal || s2.isTotal; s1.outerAttr = nothing(); s2.outerAttr = nothing(); - top.translation = Silver_Expr { core:orElse($Expr{s1.translation}, $Expr{s2.translation}) }; + top.partialTranslation = + Silver_Expr { + core:orElse($Expr{s1.partialTranslation}, $Expr{s2.partialTranslation}) + }; + top.totalTranslation = + case s1.isTotal, s2.isTotal of + | true, _ -> s1.totalTranslation + | false, true -> + Silver_Expr { + core:fromMaybe($Expr{s2.totalTranslation}, $Expr{s1.partialTranslation}) + } + | false, false -> asTotal(top.partialTranslation) + end; } -- Traversals @@ -231,15 +279,20 @@ top::StrategyExpr ::= s::StrategyExpr { top.unparse = s"all(${s.unparse})"; + local sName::String = fromMaybe(top.genName ++ "_all_arg", s.attrRefName); top.liftedStrategies := if s.attrRefName.isJust then [] - else [pair(s.genName, s)]; - top.isSuccess = s.isSuccess; + else [pair(sName, s)]; + top.isTotalInf = s.isTotalInf; + top.isTotal = + -- If s is lifted, then we must determine totality without the env + if s.attrRefName.isJust + then s.isTotal + else s.isTotalInf; s.outerAttr = nothing(); - local sName::String = fromMaybe(s.genName, s.attrRefName); local sBaseName::String = last(explode(":", sName)); -- pair(child name, attr occurs on child) local childAccesses::[Pair] = @@ -247,28 +300,10 @@ top::StrategyExpr ::= s::StrategyExpr \ e::NamedSignatureElement -> pair(e.elementName, attrMatchesFrame(top.env, sName, e.typerep)), top.frame.signature.inputElements); - top.translation = - case s of - | functorRef(attr) -> - {- When s is a functor, optimized translation of all(s) for prod::(Foo ::= a::Foo b::Integer c::Bar): - just(prod(a.s, b, c.s)) -} - Silver_Expr { - core:just( - $Expr{ - mkFullFunctionInvocation( - top.location, - baseExpr(qName(top.location, top.frame.fullName), location=top.location), - map( - \ a::Pair -> - if a.snd - then Silver_Expr { $name{a.fst}.$QNameAttrOccur{attr} } - else Silver_Expr { $name{a.fst} }, - childAccesses), - map( - makeAnnoArg(top.location, top.frame.signature.outputElement.elementName, _), - top.frame.signature.namedInputElements))}) - } - | _ -> + top.partialTranslation = + if s.isTotal + then asPartial(top.totalTranslation) + else {- Translation of all(s) for prod::(Foo ::= a::Foo b::Integer c::Bar): case a.s, c.s of | just(a_s), just(c_s) -> just(prod(a_s, b, c_s)) @@ -309,8 +344,25 @@ top::StrategyExpr ::= s::StrategyExpr location=top.location)], Silver_Expr { core:nothing() }, nonterminalType("core:Maybe", [top.frame.signature.outputElement.typerep]), - location=top.location) - end; + location=top.location); + top.totalTranslation = + if s.isTotal + then + {- When s is total, optimized translation of all(s) for prod::(Foo ::= a::Foo b::Integer c::Bar): + prod(a.s, b, c.s) -} + mkFullFunctionInvocation( + top.location, + baseExpr(qName(top.location, top.frame.fullName), location=top.location), + map( + \ a::Pair -> + if a.snd + then Silver_Expr { $name{a.fst}.$name{sName} } + else Silver_Expr { $name{a.fst} }, + childAccesses), + map( + makeAnnoArg(top.location, top.frame.signature.outputElement.elementName, _), + top.frame.signature.namedInputElements)) + else asTotal(top.partialTranslation); } abstract production someTraversal @@ -318,42 +370,28 @@ top::StrategyExpr ::= s::StrategyExpr { top.unparse = s"some(${s.unparse})"; + local sName::String = fromMaybe(top.genName ++ "_some_arg", s.attrRefName); top.liftedStrategies := if s.attrRefName.isJust then [] - else [pair(s.genName, s)]; + else [pair(sName, s)]; s.outerAttr = nothing(); - local sName::String = fromMaybe(s.genName, s.attrRefName); -- pair(child name, attr occurs on child) local childAccesses::[Pair] = map( \ e::NamedSignatureElement -> pair(e.elementName, attrMatchesFrame(top.env, sName, e.typerep)), top.frame.signature.inputElements); - top.translation = - case s of - | functorRef(attr) -> - {- When s is a functor, optimized translation of all(s) for prod::(Foo ::= a::Foo b::Integer c::Bar): - just(prod(a.s, b, c.s)) -} - Silver_Expr { - core:just( - $Expr{ - mkFullFunctionInvocation( - top.location, - baseExpr(qName(top.location, top.frame.fullName), location=top.location), - map( - \ a::Pair -> - if a.snd - then Silver_Expr { $name{a.fst}.$QNameAttrOccur{attr} } - else Silver_Expr { $name{a.fst} }, - childAccesses), - map( - makeAnnoArg(top.location, top.frame.signature.outputElement.elementName, _), - top.frame.signature.namedInputElements))}) - } - | _ -> + local matchingChildren::[String] = map(fst, filter(snd, childAccesses)); + top.partialTranslation = + if s.isTotal + then + if !null(matchingChildren) + then asPartial(top.totalTranslation) + else Silver_Expr { core:nothing() } + else {- Translation of some(s) for prod::(Foo ::= a::Foo b::Integer c::Bar): if a.s.isJust || c.s.isJust then just(prod(fromMaybe(a, a.s), b, fromMaybe(c, c.s))) @@ -366,7 +404,7 @@ top::StrategyExpr ::= s::StrategyExpr falseConst('false', location=top.location), map( \ a::String -> Silver_Expr { $name{a}.$name{sName}.isJust }, - map(fst, filter(snd, childAccesses))))} + matchingChildren))} then core:just( $Expr{ @@ -383,22 +421,39 @@ top::StrategyExpr ::= s::StrategyExpr makeAnnoArg(top.location, top.frame.signature.outputElement.elementName, _), top.frame.signature.namedInputElements))}) else core:nothing() - } - end; + }; + top.totalTranslation = + if s.isTotal && !null(matchingChildren) + then + {- When s is total, optimized translation of all(s) for prod::(Foo ::= a::Foo b::Integer c::Bar): + prod(a.s, b, c.s) -} + mkFullFunctionInvocation( + top.location, + baseExpr(qName(top.location, top.frame.fullName), location=top.location), + map( + \ a::Pair -> + if a.snd + then Silver_Expr { $name{a.fst}.$name{sName} } + else Silver_Expr { $name{a.fst} }, + childAccesses), + map( + makeAnnoArg(top.location, top.frame.signature.outputElement.elementName, _), + top.frame.signature.namedInputElements)) + else asTotal(top.partialTranslation); } abstract production oneTraversal top::StrategyExpr ::= s::StrategyExpr { top.unparse = s"one(${s.unparse})"; + local sName::String = fromMaybe(top.genName ++ "_one_arg", s.attrRefName); top.liftedStrategies := if s.attrRefName.isJust then [] - else [pair(s.genName, s)]; + else [pair(sName, s)]; s.outerAttr = nothing(); - local sName::String = fromMaybe(s.genName, s.attrRefName); local sBaseName::String = last(explode(":", sName)); -- pair(child name, attr occurs on child) local childAccesses::[Pair] = @@ -407,29 +462,13 @@ top::StrategyExpr ::= s::StrategyExpr pair(e.elementName, attrMatchesFrame(top.env, sName, e.typerep)), top.frame.signature.inputElements); local matchingChildren::[String] = map(fst, filter(snd, childAccesses)); - top.translation = - case s of - | functorRef(attr) when !null(matchingChildren) -> - {- When s is a functor, optimized translation of all(s) for prod::(Foo ::= a::Foo b::Integer c::Bar): - just(prod(a.s, b, c)) -} - Silver_Expr { - core:just( - $Expr{ - mkFullFunctionInvocation( - top.location, - baseExpr(qName(top.location, top.frame.fullName), location=top.location), - map( - \ a::Pair -> - if a.fst == head(matchingChildren) - then Silver_Expr { $name{a.fst}.$QNameAttrOccur{attr} } - else Silver_Expr { $name{a.fst} }, - childAccesses), - map( - makeAnnoArg(top.location, top.frame.signature.outputElement.elementName, _), - top.frame.signature.namedInputElements))}) - } - | functorRef(_) -> Silver_Expr { core:nothing() } - | _ -> + top.partialTranslation = + if s.isTotal + then + if !null(matchingChildren) + then asPartial(top.totalTranslation) + else Silver_Expr { core:nothing() } + else {- Translation of one(s) for prod::(Foo ::= a::Foo b::Integer c::Bar): case a.s, c.s of | just(a_s), _ -> just(prod(a_s, b, c)) @@ -478,8 +517,25 @@ top::StrategyExpr ::= s::StrategyExpr range(0, length(matchingChildren))), Silver_Expr { core:nothing() }, nonterminalType("core:Maybe", [top.frame.signature.outputElement.typerep]), - location=top.location) - end; + location=top.location); + top.totalTranslation = + if s.isTotal && !null(matchingChildren) + then + {- When s is total, optimized translation of one(s) for prod::(Foo ::= a::Foo b::Integer c::Bar): + prod(a.s, b, c) -} + mkFullFunctionInvocation( + top.location, + baseExpr(qName(top.location, top.frame.fullName), location=top.location), + map( + \ a::Pair -> + if a.fst == head(matchingChildren) + then Silver_Expr { $name{a.fst}.$name{sName} } + else Silver_Expr { $name{a.fst} }, + childAccesses), + map( + makeAnnoArg(top.location, top.frame.signature.outputElement.elementName, _), + top.frame.signature.namedInputElements)) + else asTotal(top.partialTranslation); } abstract production prodTraversal @@ -501,11 +557,11 @@ top::StrategyExpr ::= prod::QName s::StrategyExprs -- pair(child name, if attr occurs on child then just(attr name) else nothing()) local childAccesses::[Pair>>] = zipWith(pair, top.frame.signature.inputNames, s.attrRefNames); - top.translation = + top.partialTranslation = -- This is never total if prod.lookupValue.fullName == top.frame.fullName then {- Translation of prod(s1, s2, s3, s4) for prod::(Foo ::= a::Foo b::Integer c::Bar d::Baz) - where s4 is a functor: + where s4 is total: case a.s1, c.s3 of | just(a_s1), just(c_s3) -> just(prod(a_s1, b, c_s3, d.s4)) | _, _ -> nothing() @@ -562,19 +618,20 @@ top::StrategyExprs ::= h::StrategyExpr t::StrategyExprs top.liftedStrategies := -- Slight hack: when h is id (common case for prod traversals), there is no need for a new attribute. - -- However this can't be eliminated during the optumization phase. + -- However this can't be avoided during the optimization phase, which happens after lifting. -- So, just don't lift the strategy, and we won't find the occurence of the non-existant attribute -- during translation - which means we will treat it as id anyway! (if h.attrRefName.isJust || h.isId then [] else [pair(h.genName, h)]) ++ t.liftedStrategies; + local hType::Type = head(top.givenInputElements).typerep; local attr::String = fromMaybe(h.genName, h.attrRefName); local attrMatch::Boolean = attrMatchesFrame(top.env, attr, hType); top.attrRefNames = (if attrMatch && !h.isId - then just(pair(case h of functorRef(_) -> true | _ -> false end, attr)) + then just(pair(case h of totalRef(_) -> true | _ -> false end, attr)) else nothing()) :: t.attrRefNames; top.errors <- if !null(top.givenInputElements) && !attrMatch && !h.isId @@ -606,16 +663,31 @@ top::StrategyExpr ::= n::Name s::StrategyExpr top.liftedStrategies := if top.outerAttr.isJust then s.liftedStrategies - else [pair(s.genName, s)]; + else [pair(top.genName, s)]; top.freeRecVars := removeBy(stringEq, n.name, s.freeRecVars); + top.isTotalInf = s.isTotalInf; + top.isTotal = + -- If s is lifted, then we must determine totality without the env + if top.outerAttr.isJust + then s.isTotal + else s.isTotalInf; - s.recVarEnv = pair(n.name, fromMaybe(s.genName, top.outerAttr)) :: top.recVarEnv; + s.recVarEnv = + pair(n.name, fromMaybe(pair(s.isTotalInf, s.genName), top.outerAttr)) :: top.recVarEnv; s.outerAttr = top.outerAttr; - top.translation = + top.partialTranslation = + if top.outerAttr.isJust + then s.partialTranslation + else if s.isTotal + then asPartial(top.totalTranslation) + else Silver_Expr { $name{top.frame.signature.outputElement.elementName}.$name{top.genName} }; + top.totalTranslation = if top.outerAttr.isJust - then s.translation - else Silver_Expr { $name{top.frame.signature.outputElement.elementName}.$name{s.genName} }; + then s.totalTranslation + else if s.isTotal + then Silver_Expr { $name{top.frame.signature.outputElement.elementName}.$name{top.genName} } + else asTotal(top.partialTranslation); } -- Rules @@ -663,7 +735,7 @@ top::StrategyExpr ::= id::Name ty::TypeExpr ml::MRuleList Silver_Expr { core:nothing() }, nonterminalType("core:Maybe", [ty.typerep]), location=top.location); - top.translation = + top.partialTranslation = if unify(ty.typerep, top.frame.signature.outputElement.typerep).failure then Silver_Expr { core:nothing() } else if top.frame.signature.outputElement.elementName == id.name @@ -686,6 +758,7 @@ top::Expr ::= t::Type attribute matchesFrame occurs on MRuleList, MatchRule, PatternList, Pattern; propagate matchesFrame on MRuleList, MatchRule, PatternList; +synthesized attribute translation::a; attribute translation<[AbstractMatchRule]> occurs on MRuleList; aspect production mRuleList_one @@ -740,8 +813,9 @@ top::StrategyExpr ::= id::QName -- Forwarding depends on env here, these must be computed without env propagate liftedStrategies; - top.attrRefName = just(fromMaybe(id.name, lookupBy(stringEq, id.name, top.recVarEnv))); + top.attrRefName = just(fromMaybe(id.name, mapMaybe(snd, lookupBy(stringEq, id.name, top.recVarEnv)))); top.isId = false; + top.isTotalInf = false; -- Conservative assumption without env local attrDcl::DclInfo = id.lookupAttribute.dcl; attrDcl.givenNonterminalType = error("Not actually needed"); -- Ugh environment needs refactoring @@ -751,8 +825,8 @@ top::StrategyExpr ::= id::QName else if !null(id.lookupAttribute.errors) then errorRef(id.lookupAttribute.errors, id, genName=top.genName, location=top.location) else case decorate id.lookupAttribute.dcl with { givenNonterminalType = error("Not actually needed"); }.typerep of -- Ugh environment needs refactoring - | nonterminalType("core:Maybe", _) -> strategyRef(qNameAttrOccur(id, location=top.location), genName=top.genName, location=top.location) - | _ -> functorRef(qNameAttrOccur(id, location=top.location), genName=top.genName, location=top.location) + | nonterminalType("core:Maybe", _) -> partialRef(qNameAttrOccur(id, location=top.location), genName=top.genName, location=top.location) + | _ -> totalRef(qNameAttrOccur(id, location=top.location), genName=top.genName, location=top.location) end; } abstract production errorRef @@ -764,7 +838,7 @@ top::StrategyExpr ::= msg::[Message] id::Decorated QName top.attrRefName = just(id.name); top.errors <- msg; - top.translation = Silver_Expr { core:nothing() }; + top.partialTranslation = Silver_Expr { core:nothing() }; } abstract production recVarRef top::StrategyExpr ::= id::Decorated QName @@ -772,12 +846,21 @@ top::StrategyExpr ::= id::Decorated QName top.unparse = id.unparse; propagate liftedStrategies; - top.attrRefName = lookupBy(stringEq, id.name, top.recVarEnv); + top.attrRefName = mapMaybe(snd, lookupBy(stringEq, id.name, top.recVarEnv)); + top.isTotalInf = false; + top.isTotal = lookupBy(stringEq, id.name, top.recVarEnv).fromJust.fst; top.freeRecVars <- [id.name]; - top.translation = Silver_Expr { $name{top.frame.signature.outputElement.elementName}.$qName{top.attrRefName.fromJust} }; + top.partialTranslation = + if top.isTotalInf + then asPartial(top.totalTranslation) + else Silver_Expr { $name{top.frame.signature.outputElement.elementName}.$qName{top.attrRefName.fromJust} }; + top.totalTranslation = + if top.isTotalInf + then Silver_Expr { $name{top.frame.signature.outputElement.elementName}.$qName{top.attrRefName.fromJust} } + else asTotal(top.partialTranslation); } -abstract production strategyRef +abstract production partialRef top::StrategyExpr ::= attr::QNameAttrOccur { top.unparse = attr.unparse; @@ -789,26 +872,27 @@ top::StrategyExpr ::= attr::QNameAttrOccur case attrDcl.typerep, attrDcl.dclBoundVars of | nonterminalType("core:Maybe", [varType(a1)]), [a2] when tyVarEqual(a1, a2) -> [] | nonterminalType("core:Maybe", [nonterminalType(nt, _)]), _ -> - case getOccursDcl(attrDcl.fullName, nt, top.env) of - | [] -> [wrn(attr.location, s"Attribute ${attr.name} cannot be used as a strategy, because it doesn't occur on its own nonterminal type ${nt}")] - | _ -> [] - end + if null(getOccursDcl(attrDcl.fullName, nt, top.env)) + then [wrn(attr.location, s"Attribute ${attr.name} cannot be used as a partial strategy, because it doesn't occur on its own nonterminal type ${nt}")] + else [] | errorType(), _ -> [] - | _, _ -> [err(attr.location, s"Attribute ${attr.name} cannot be used as a strategy")] + | _, _ -> [err(attr.location, s"Attribute ${attr.name} cannot be used as a partial strategy")] end; propagate liftedStrategies; top.attrRefName = just(attr.name); top.matchesFrame := attr.matchesFrame; + top.isTotalInf = false; + top.isTotal = false; attr.attrFor = top.frame.signature.outputElement.typerep; - top.translation = + top.partialTranslation = if attr.matchesFrame then Silver_Expr { $name{top.frame.signature.outputElement.elementName}.$QNameAttrOccur{attr} } else Silver_Expr { core:nothing() }; } -abstract production functorRef +abstract production totalRef top::StrategyExpr ::= attr::QNameAttrOccur { top.unparse = attr.unparse; @@ -820,25 +904,23 @@ top::StrategyExpr ::= attr::QNameAttrOccur case attrDcl.typerep, attrDcl.dclBoundVars of | varType(a1), [a2] when tyVarEqual(a1, a2) -> [] | nonterminalType(nt, _), _ -> - case getOccursDcl(attrDcl.fullName, nt, top.env) of - | [] -> [wrn(attr.location, s"Attribute ${attr.name} cannot be used as a functor, because it doesn't occur on its own nonterminal type ${nt}")] - | _ -> [] - end + if null(getOccursDcl(attrDcl.fullName, nt, top.env)) + then [wrn(attr.location, s"Attribute ${attr.name} cannot be used as total strategy, because it doesn't occur on its own nonterminal type ${nt}")] + else [] | errorType(), _ -> [] - | _, _ -> [err(attr.location, s"Attribute ${attr.name} cannot be used as a functor")] + | _, _ -> [err(attr.location, s"Attribute ${attr.name} cannot be used as total strategy")] end; propagate liftedStrategies; top.attrRefName = just(attr.name); top.matchesFrame := attr.matchesFrame; - top.isSuccess = true; + top.isTotalInf = true; + top.isTotal = true; + top.totalRefs <- [case attr of qNameAttrOccur(a) -> a.lookupAttribute.dcl.fullName end]; attr.attrFor = top.frame.signature.outputElement.typerep; - top.translation = - if attr.matchesFrame - then Silver_Expr { core:just($name{top.frame.signature.outputElement.elementName}.$QNameAttrOccur{attr}) } - else Silver_Expr { core:nothing() }; + top.totalTranslation = Silver_Expr { $name{top.frame.signature.outputElement.elementName}.$QNameAttrOccur{attr} }; } -- The result of performing an inlining optimization @@ -848,11 +930,13 @@ top::StrategyExpr ::= attr::Decorated QNameAttrOccur s::StrategyExpr top.unparse = s"(${s.unparse} aka ${attr.unparse})"; propagate liftedStrategies; top.attrRefName = just(attr.attrDcl.fullName); - top.isSuccess = s.isSuccess; - top.translation = + top.isTotalInf = s.isTotalInf; + top.isTotal = s.isTotal; + top.partialTranslation = if attr.matchesFrame - then s.translation + then s.partialTranslation else Silver_Expr { core:nothing() }; + top.totalTranslation = s.totalTranslation; s.outerAttr = top.outerAttr; s.inlinedStrategies = attr.attrDcl.fullName :: top.inlinedStrategies; diff --git a/grammars/silver/extension/strategyattr/StrategyUtils.sv b/grammars/silver/extension/strategyattr/StrategyUtils.sv index 63fbdd93e..71a893237 100644 --- a/grammars/silver/extension/strategyattr/StrategyUtils.sv +++ b/grammars/silver/extension/strategyattr/StrategyUtils.sv @@ -10,10 +10,11 @@ top::StrategyExpr ::= top.unparse = s"printTerm"; propagate liftedStrategies; - top.translation = + top.isTotal = true; + top.totalTranslation = Silver_Expr { core:unsafeTrace( - core:just($name{top.frame.signature.outputElement.elementName}), + $name{top.frame.signature.outputElement.elementName}, core:print( hackUnparse($name{top.frame.signature.outputElement.elementName}) ++ "\n\n", core:unsafeIO())) diff --git a/grammars/silver/extension/strategyattr/Terminals.sv b/grammars/silver/extension/strategyattr/Terminals.sv index 6483e45eb..86ebabb37 100644 --- a/grammars/silver/extension/strategyattr/Terminals.sv +++ b/grammars/silver/extension/strategyattr/Terminals.sv @@ -1,6 +1,7 @@ grammar silver:extension:strategyattr; terminal Strategy_kwd 'strategy' lexer classes {KEYWORD, RESERVED}; +terminal Partial_kwd 'partial' lexer classes {KEYWORD, RESERVED}; terminal Sequence_t '<*' precedence = 12, association = left; -- Same as * terminal Choice_t '<+' precedence = 11, association = left; -- Same as + diff --git a/grammars/silver/extension/strategyattr/convenience/Convenience.sv b/grammars/silver/extension/strategyattr/convenience/Convenience.sv index b91106b0e..a31847dad 100644 --- a/grammars/silver/extension/strategyattr/convenience/Convenience.sv +++ b/grammars/silver/extension/strategyattr/convenience/Convenience.sv @@ -8,13 +8,24 @@ import silver:definition:type:syntax; import silver:definition:type; import silver:definition:env; -concrete production strategyAttributeDclMultiple +concrete production partialStrategyAttributeDclMultiple +top::AGDcl ::= 'partial' 'strategy' 'attribute' a::Name '=' e::StrategyExpr_c 'occurs' 'on' qs::QNames ';' +{ + top.unparse = "partial strategy attribute " ++ a.name ++ " occurs on " ++ qs.unparse ++ ";"; + forwards to + appendAGDcl( + partialStrategyAttributeDcl($1, $2, $3, a, $5, e, $10, location=a.location), + makeOccursDclsHelp($1.location, qNameWithTL(qNameId(a, location=a.location), botlNone(location=top.location)), qs.qnames), + location=top.location); +} + +concrete production totalStrategyAttributeDclMultiple top::AGDcl ::= 'strategy' 'attribute' a::Name '=' e::StrategyExpr_c 'occurs' 'on' qs::QNames ';' { top.unparse = "strategy attribute " ++ a.name ++ " occurs on " ++ qs.unparse ++ ";"; forwards to appendAGDcl( - strategyAttributeDcl_c($1, $2, a, $4, e, $9, location=a.location), + totalStrategyAttributeDcl($1, $2, a, $4, e, $9, location=a.location), makeOccursDclsHelp($1.location, qNameWithTL(qNameId(a, location=a.location), botlNone(location=top.location)), qs.qnames), location=top.location); } diff --git a/test/silver_features/Strategy.sv b/test/silver_features/Strategy.sv index b94255b63..ab590e37a 100644 --- a/test/silver_features/Strategy.sv +++ b/test/silver_features/Strategy.sv @@ -37,12 +37,12 @@ top::SStmt ::= n::String e::SExpr equalityTest( hackUnparse(addSExpr(constSExpr(42), constSExpr(0)).elimPlusZero), - "core:just(silver_features:constSExpr(42))", + "silver_features:constSExpr(42)", String, silver_tests); equalityTest( hackUnparse(addSExpr(addSExpr(constSExpr(42), constSExpr(0)), constSExpr(0)).elimPlusZero), - "core:just(silver_features:constSExpr(42))", + "silver_features:constSExpr(42)", String, silver_tests); equalityTest( @@ -50,10 +50,10 @@ equalityTest( seqSStmt( assignSStmt("a", addSExpr(constSExpr(42), constSExpr(0))), assignSStmt("b", addSExpr(addSExpr(idSExpr("a"), constSExpr(0)), constSExpr(0)))).elimPlusZero), - "core:just(silver_features:seqSStmt(silver_features:assignSStmt(\"a\", silver_features:constSExpr(42)), silver_features:assignSStmt(\"b\", silver_features:idSExpr(\"a\"))))", + "silver_features:seqSStmt(silver_features:assignSStmt(\"a\", silver_features:constSExpr(42)), silver_features:assignSStmt(\"b\", silver_features:idSExpr(\"a\")))", String, silver_tests); -strategy attribute removeLastStmt = +partial strategy attribute removeLastStmt = rule on SStmt of | seqSStmt(s, assignSStmt(_, _)) -> s end <+ @@ -82,20 +82,27 @@ equalityTest( String, silver_tests); -functor attribute incConsts occurs on SStmt, SExpr; -propagate incConsts on SStmt, SExpr excluding constSExpr; +functor attribute incConstsF occurs on SStmt, SExpr; +propagate incConstsF on SStmt, SExpr excluding constSExpr; aspect production constSExpr top::SExpr ::= i::Integer -{ top.incConsts = constSExpr(i + 1); } +{ top.incConstsF = constSExpr(i + 1); } -strategy attribute incTwice = incConsts <* incConsts +strategy attribute incConsts = + allTopDown( + rule on SExpr of + | constSExpr(i) -> constSExpr(i + 1) + end) occurs on SStmt, SExpr; +propagate incConsts on SStmt, SExpr; + +strategy attribute incTwice = incConstsF <* incConsts occurs on SStmt, SExpr; propagate incTwice on SStmt, SExpr; equalityTest( hackUnparse( assignSStmt("a", addSExpr(constSExpr(42), constSExpr(0))).incTwice), - "core:just(silver_features:assignSStmt(\"a\", silver_features:addSExpr(silver_features:constSExpr(44), silver_features:constSExpr(2))))", + "silver_features:assignSStmt(\"a\", silver_features:addSExpr(silver_features:constSExpr(44), silver_features:constSExpr(2)))", String, silver_tests); @@ -115,7 +122,7 @@ equalityTest( assignSStmt("a", addSExpr(constSExpr(42), constSExpr(0))), assignSStmt("b", addSExpr(addSExpr(idSExpr("a"), constSExpr(2)), constSExpr(17)))) with {target = "b";}.incTargetConsts), - "core:just(silver_features:seqSStmt(silver_features:assignSStmt(\"a\", silver_features:addSExpr(silver_features:constSExpr(42), silver_features:constSExpr(0))), silver_features:assignSStmt(\"b\", silver_features:addSExpr(silver_features:addSExpr(silver_features:idSExpr(\"a\"), silver_features:constSExpr(3)), silver_features:constSExpr(18)))))", + "silver_features:seqSStmt(silver_features:assignSStmt(\"a\", silver_features:addSExpr(silver_features:constSExpr(42), silver_features:constSExpr(0))), silver_features:assignSStmt(\"b\", silver_features:addSExpr(silver_features:addSExpr(silver_features:idSExpr(\"a\"), silver_features:constSExpr(3)), silver_features:constSExpr(18))))", String, silver_tests); strategy attribute incThenElim = incConsts <* elimPlusZero @@ -125,14 +132,14 @@ propagate incThenElim on SStmt, SExpr; equalityTest( hackUnparse( assignSStmt("a", addSExpr(constSExpr(42), constSExpr(-1))).incThenElim), - "core:just(silver_features:assignSStmt(\"a\", silver_features:constSExpr(43)))", + "silver_features:assignSStmt(\"a\", silver_features:constSExpr(43))", String, silver_tests); strategy attribute incAll = all(incConsts) occurs on SStmt, SExpr; -strategy attribute incSome = some(incConsts) occurs on SStmt, SExpr; -strategy attribute incOne = one(incConsts) occurs on SStmt, SExpr; -strategy attribute incFstElimSnd = seqSStmt(incConsts, elimPlusZero) occurs on SStmt, SExpr; +partial strategy attribute incSome = some(incConsts) occurs on SStmt, SExpr; +partial strategy attribute incOne = one(incConsts) occurs on SStmt, SExpr; +partial strategy attribute incFstElimSnd = seqSStmt(incConsts, elimPlusZero) occurs on SStmt, SExpr; propagate incAll, incSome, incOne, incFstElimSnd on SStmt, SExpr; equalityTest( @@ -140,7 +147,7 @@ equalityTest( seqSStmt( assignSStmt("a", constSExpr(1)), assignSStmt("b", constSExpr(2))).incAll), - "core:just(silver_features:seqSStmt(silver_features:assignSStmt(\"a\", silver_features:constSExpr(2)), silver_features:assignSStmt(\"b\", silver_features:constSExpr(3))))", + "silver_features:seqSStmt(silver_features:assignSStmt(\"a\", silver_features:constSExpr(2)), silver_features:assignSStmt(\"b\", silver_features:constSExpr(3)))", String, silver_tests); equalityTest( hackUnparse( @@ -163,3 +170,9 @@ equalityTest( assignSStmt("b", addSExpr(constSExpr(2), constSExpr(0)))).incFstElimSnd), "core:just(silver_features:seqSStmt(silver_features:assignSStmt(\"a\", silver_features:addSExpr(silver_features:constSExpr(2), silver_features:constSExpr(1))), silver_features:assignSStmt(\"b\", silver_features:constSExpr(2))))", String, silver_tests); + +-- Negative tests +inherited attribute badInh::a; +wrongCode "cannot be used as total strategy" { + strategy attribute badInhS = badInh; +} diff --git a/test/silver_features/rewrite/expreval/AbstractSyntax.sv b/test/silver_features/rewrite/expreval/AbstractSyntax.sv index 0c31c94e1..65445df60 100644 --- a/test/silver_features/rewrite/expreval/AbstractSyntax.sv +++ b/test/silver_features/rewrite/expreval/AbstractSyntax.sv @@ -126,15 +126,15 @@ global eval::Strategy = innermost(evalStep <+ simplifyConstIdent <+ simplifyFrac -- Strategy attributes autocopy attribute substName::String; autocopy attribute substExpr::Expr; -strategy attribute substRes = -- This would actually be simpler as a functor, but this is a test... - bottomUp(try( +strategy attribute substRes = + allTopDown( rule on top::Expr of | var(n1) when top.substName == n1 -> top.substExpr - end)); + end); attribute substName, substExpr, substRes occurs on Expr; propagate substRes on Expr; -strategy attribute evalStep = +partial strategy attribute evalStep = rule on Expr of | add(const(a), const(b)) -> const(a + b) | sub(const(a), const(b)) -> const(a - b) @@ -144,10 +144,10 @@ strategy attribute evalStep = let g::Integer = gcd(a, b) in div(const(a / g), const(b / g)) end -- This rule does not respect lexical shadowing; -- it is assumed that the overall rewrite will be done in an innermost order. - | letE(n, e1, e2) -> decorate e2 with {substName = n; substExpr = e1;}.substRes.fromJust + | letE(n, e1, e2) -> decorate e2 with {substName = n; substExpr = e1;}.substRes end; -strategy attribute simplifyConstIdent = +partial strategy attribute simplifyConstIdent = rule on Expr of | add(a, const(0)) -> a | add(const(0), a) -> a @@ -163,7 +163,7 @@ strategy attribute simplifyConstIdent = | div(a, const(1)) -> a end; -strategy attribute simplifyFrac = +partial strategy attribute simplifyFrac = rule on Expr of | add(div(a, b), c) -> div(add(a, mul(b, c)), b) | sub(div(a, b), c) -> div(sub(a, mul(b, c)), b) diff --git a/test/silver_features/rewrite/expreval/Tests.sv b/test/silver_features/rewrite/expreval/Tests.sv index 3d5794e9e..214867832 100644 --- a/test/silver_features/rewrite/expreval/Tests.sv +++ b/test/silver_features/rewrite/expreval/Tests.sv @@ -8,46 +8,40 @@ global test1::Expr = parseExpr("1 + (2 * 3)"); global result1a::Maybe = rewriteWith(eval, test1); equalityTest(result1a.isJust, true, Boolean, silver_tests); equalityTest(showExpr(fromMaybe(const(12345), result1a)), "7", String, silver_tests); -global result1b::Maybe = test1.eval; -equalityTest(result1b.isJust, true, Boolean, silver_tests); -equalityTest(showExpr(fromMaybe(const(12345), result1b)), "7", String, silver_tests); +global result1b::Expr = test1.eval; +equalityTest(showExpr(result1b), "7", String, silver_tests); global test2::Expr = parseExpr("7 + 4 - ((1 + 1) / 0)"); global result2a::Maybe = rewriteWith(eval, test2); equalityTest(result2a.isJust, true, Boolean, silver_tests); equalityTest(showExpr(fromMaybe(const(12345), result2a)), "-2 / 0", String, silver_tests); -global result2b::Maybe = test2.eval; -equalityTest(result2b.isJust, true, Boolean, silver_tests); -equalityTest(showExpr(fromMaybe(const(12345), result2b)), "-2 / 0", String, silver_tests); +global result2b::Expr = test2.eval; +equalityTest(showExpr(result2b), "-2 / 0", String, silver_tests); global test3::Expr = parseExpr("(2 + 2) / 6"); global result3a::Maybe = rewriteWith(eval, test3); equalityTest(result3a.isJust, true, Boolean, silver_tests); equalityTest(showExpr(fromMaybe(const(12345), result3a)), "2 / 3", String, silver_tests); -global result3b::Maybe = test3.eval; -equalityTest(result3b.isJust, true, Boolean, silver_tests); -equalityTest(showExpr(fromMaybe(const(12345), result3b)), "2 / 3", String, silver_tests); +global result3b::Expr = test3.eval; +equalityTest(showExpr(result3b), "2 / 3", String, silver_tests); global test4::Expr = parseExpr("1 + 1 / (1 + 1 / (1 + 1 / (1 + 1 / (1 + 1 / (1 + 1 / (1 + 1))))))"); global result4a::Maybe = rewriteWith(eval, test4); equalityTest(result4a.isJust, true, Boolean, silver_tests); equalityTest(showExpr(fromMaybe(const(12345), result4a)), "34 / 21", String, silver_tests); -global result4b::Maybe = test4.eval; -equalityTest(result4b.isJust, true, Boolean, silver_tests); -equalityTest(showExpr(fromMaybe(const(12345), result4b)), "34 / 21", String, silver_tests); +global result4b::Expr = test4.eval; +equalityTest(showExpr(result4b), "34 / 21", String, silver_tests); global test5::Expr = parseExpr("let a = 1 / 2 in let b = a * 2 in a + b"); global result5a::Maybe = rewriteWith(eval, test5); equalityTest(result5a.isJust, true, Boolean, silver_tests); equalityTest(showExpr(fromMaybe(const(12345), result5a)), "3 / 2", String, silver_tests); -global result5b::Maybe = test5.eval; -equalityTest(result5b.isJust, true, Boolean, silver_tests); -equalityTest(showExpr(fromMaybe(const(12345), result5b)), "3 / 2", String, silver_tests); +global result5b::Expr = test5.eval; +equalityTest(showExpr(result5b), "3 / 2", String, silver_tests); global test6::Expr = parseExpr("0 + 1 * a - 2 / b"); global result6a::Maybe = rewriteWith(eval, test6); equalityTest(result6a.isJust, true, Boolean, silver_tests); equalityTest(showExpr(fromMaybe(const(12345), result6a)), "((a * b) - 2) / b", String, silver_tests); -global result6b::Maybe = test6.eval; -equalityTest(result6b.isJust, true, Boolean, silver_tests); -equalityTest(showExpr(fromMaybe(const(12345), result6b)), "((a * b) - 2) / b", String, silver_tests); +global result6b::Expr = test6.eval; +equalityTest(showExpr(result6b), "((a * b) - 2) / b", String, silver_tests); From 4fe4720669093c7384190693af4f25d307c8d193 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Thu, 7 May 2020 14:00:38 -0500 Subject: [PATCH 56/78] Fixes and improvments to totality checking --- .../silver/extension/strategyattr/Strategy.sv | 3 + .../extension/strategyattr/StrategyExpr.sv | 68 +++++++++---------- 2 files changed, 36 insertions(+), 35 deletions(-) diff --git a/grammars/silver/extension/strategyattr/Strategy.sv b/grammars/silver/extension/strategyattr/Strategy.sv index 2ca9a940e..67004b6f9 100644 --- a/grammars/silver/extension/strategyattr/Strategy.sv +++ b/grammars/silver/extension/strategyattr/Strategy.sv @@ -38,6 +38,7 @@ top::AGDcl ::= isTotal::Boolean a::Name recVarEnv::[Pair> -> v.snd.fst, recVarEnv)); e.outerAttr = just(pair(isTotal, a.name)); local fwrd::AGDcl = @@ -120,6 +121,7 @@ top::ProductionStmt ::= attr::Decorated QName e.frame = top.frame; e.env = top.env; e.recVarEnv = attr.lookupAttribute.dcl.givenRecVarEnv; + e.outerTotalRecVars = map(fst, filter(\ v::Pair> -> v.snd.fst, e.recVarEnv)); e.outerAttr = just(pair(isTotal, attr.lookupAttribute.fullName)); e.inlinedStrategies = [attr.lookupAttribute.fullName]; -- Don't unfold the top-level strategy within itself @@ -129,6 +131,7 @@ top::ProductionStmt ::= attr::Decorated QName e2.frame = e.frame; e2.env = e.env; e2.recVarEnv = e.recVarEnv; + e2.outerTotalRecVars = e.outerTotalRecVars; e2.outerAttr = e.outerAttr; e2.inlinedStrategies = e.inlinedStrategies; diff --git a/grammars/silver/extension/strategyattr/StrategyExpr.sv b/grammars/silver/extension/strategyattr/StrategyExpr.sv index 9484b3db0..cdd497f59 100644 --- a/grammars/silver/extension/strategyattr/StrategyExpr.sv +++ b/grammars/silver/extension/strategyattr/StrategyExpr.sv @@ -6,6 +6,7 @@ import core:monad; annotation genName::String; -- Used to generate the names of lifted strategy attributes autocopy attribute recVarEnv::[Pair>]; -- name, (isTotal, genName) +autocopy attribute outerTotalRecVars::[String]; inherited attribute outerAttr::Maybe>; -- isTotal, genName autocopy attribute inlinedStrategies::[String]; monoid attribute liftedStrategies::[Pair] with [], ++; @@ -91,17 +92,17 @@ strategy attribute optimize = nonterminal StrategyExpr with config, grammarName, env, location, unparse, errors, frame, compiledGrammars, flowEnv, flowDefs, -- Normal expression stuff - genName, recVarEnv, outerAttr, liftedStrategies, attrRefName, isId, isTotalInf, isTotal, freeRecVars, totalRefs, -- Frame-independent attrs + genName, outerAttr, recVarEnv, outerTotalRecVars, liftedStrategies, attrRefName, isId, isTotalInf, isTotal, freeRecVars, totalRefs, -- Frame-independent attrs partialTranslation, totalTranslation, matchesFrame, -- Frame-dependent attrs inlinedStrategies, genericStep, ntStep, prodStep, simplify, optimize; -- Optimization stuff nonterminal StrategyExprs with config, grammarName, env, unparse, errors, frame, compiledGrammars, flowEnv, flowDefs, -- Normal expression stuff - recVarEnv, givenInputElements, liftedStrategies, attrRefNames, containsFail, allId, freeRecVars, totalRefs, -- Frame-independent attrs + recVarEnv, outerTotalRecVars, givenInputElements, liftedStrategies, attrRefNames, containsFail, allId, freeRecVars, totalRefs, -- Frame-independent attrs inlinedStrategies, simplify; -- Optimization stuff flowtype StrategyExpr = - decorate {grammarName, config, recVarEnv, outerAttr}, -- NOT frame or env + decorate {grammarName, config, recVarEnv, outerTotalRecVars, outerAttr}, -- NOT frame or env -- Normal expression stuff unparse {}, errors {decorate, frame, env, compiledGrammars, flowEnv}, flowDefs {decorate, frame, env, compiledGrammars, flowEnv}, -- Frame-independent attrs @@ -110,7 +111,7 @@ flowtype StrategyExpr = partialTranslation {decorate, frame, env}, totalTranslation {decorate, frame, env}, matchesFrame {decorate, frame, env}; flowtype StrategyExprs = - decorate {grammarName, config, recVarEnv}, -- NOT frame or env + decorate {grammarName, config, recVarEnv, outerTotalRecVars}, -- NOT frame or env -- Normal expression stuff unparse {}, errors {decorate, frame, env, givenInputElements, compiledGrammars, flowEnv}, flowDefs {decorate, frame, env, compiledGrammars, flowEnv}, -- Frame-independent attrs @@ -175,19 +176,15 @@ top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr { top.unparse = s"(${s1.unparse} <* ${s2.unparse})"; - local s2Name::String = fromMaybe(top.genName ++ "_fst", s2.attrRefName); + local s2Name::String = fromMaybe(top.genName ++ "_snd", s2.attrRefName); + local s2Total::Boolean = if s2.attrRefName.isJust then s2.isTotal else s2.isTotalInf; top.liftedStrategies := s1.liftedStrategies ++ if s2.attrRefName.isJust then [] else [pair(s2Name, s2)]; top.isTotalInf = s1.isTotalInf && s2.isTotalInf; - top.isTotal = - s1.isTotal && - -- If s2 is lifted, then we must determine totality without the env - if s2.attrRefName.isJust - then s2.isTotal - else s2.isTotalInf; + top.isTotal = s1.isTotal && s2.isTotal; s1.outerAttr = nothing(); s2.outerAttr = nothing(); @@ -214,7 +211,7 @@ top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr top.partialTranslation = -- Optimizations when one or both of these is total, in this case a -- monadic bind may not be required. - case s1.isTotal, s2.isTotal of + case s1.isTotal, s2Total of | true, true -> Silver_Expr { core:just(decorate $Expr{s1.totalTranslation} with { $ExprInhs{allInhs} }.$name{s2Name}) @@ -239,7 +236,7 @@ top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr } end; top.totalTranslation = - if s1.isTotal && s2.isTotal + if s1.isTotal && s2Total then Silver_Expr { decorate $Expr{s1.totalTranslation} with { $ExprInhs{allInhs} }.$name{s2Name} @@ -280,16 +277,13 @@ top::StrategyExpr ::= s::StrategyExpr top.unparse = s"all(${s.unparse})"; local sName::String = fromMaybe(top.genName ++ "_all_arg", s.attrRefName); + local sTotal::Boolean = if s.attrRefName.isJust then s.isTotal else s.isTotalInf; top.liftedStrategies := if s.attrRefName.isJust then [] else [pair(sName, s)]; top.isTotalInf = s.isTotalInf; - top.isTotal = - -- If s is lifted, then we must determine totality without the env - if s.attrRefName.isJust - then s.isTotal - else s.isTotalInf; + top.isTotal = s.isTotal; s.outerAttr = nothing(); @@ -301,7 +295,7 @@ top::StrategyExpr ::= s::StrategyExpr pair(e.elementName, attrMatchesFrame(top.env, sName, e.typerep)), top.frame.signature.inputElements); top.partialTranslation = - if s.isTotal + if sTotal then asPartial(top.totalTranslation) else {- Translation of all(s) for prod::(Foo ::= a::Foo b::Integer c::Bar): @@ -346,7 +340,7 @@ top::StrategyExpr ::= s::StrategyExpr nonterminalType("core:Maybe", [top.frame.signature.outputElement.typerep]), location=top.location); top.totalTranslation = - if s.isTotal + if sTotal then {- When s is total, optimized translation of all(s) for prod::(Foo ::= a::Foo b::Integer c::Bar): prod(a.s, b, c.s) -} @@ -371,6 +365,7 @@ top::StrategyExpr ::= s::StrategyExpr top.unparse = s"some(${s.unparse})"; local sName::String = fromMaybe(top.genName ++ "_some_arg", s.attrRefName); + local sTotal::Boolean = if s.attrRefName.isJust then s.isTotal else s.isTotalInf; top.liftedStrategies := if s.attrRefName.isJust then [] @@ -386,7 +381,7 @@ top::StrategyExpr ::= s::StrategyExpr top.frame.signature.inputElements); local matchingChildren::[String] = map(fst, filter(snd, childAccesses)); top.partialTranslation = - if s.isTotal + if sTotal then if !null(matchingChildren) then asPartial(top.totalTranslation) @@ -423,7 +418,7 @@ top::StrategyExpr ::= s::StrategyExpr else core:nothing() }; top.totalTranslation = - if s.isTotal && !null(matchingChildren) + if sTotal && !null(matchingChildren) then {- When s is total, optimized translation of all(s) for prod::(Foo ::= a::Foo b::Integer c::Bar): prod(a.s, b, c.s) -} @@ -447,6 +442,7 @@ top::StrategyExpr ::= s::StrategyExpr top.unparse = s"one(${s.unparse})"; local sName::String = fromMaybe(top.genName ++ "_one_arg", s.attrRefName); + local sTotal::Boolean = if s.attrRefName.isJust then s.isTotal else s.isTotalInf; top.liftedStrategies := if s.attrRefName.isJust then [] @@ -463,7 +459,7 @@ top::StrategyExpr ::= s::StrategyExpr top.frame.signature.inputElements); local matchingChildren::[String] = map(fst, filter(snd, childAccesses)); top.partialTranslation = - if s.isTotal + if sTotal then if !null(matchingChildren) then asPartial(top.totalTranslation) @@ -519,7 +515,7 @@ top::StrategyExpr ::= s::StrategyExpr nonterminalType("core:Maybe", [top.frame.signature.outputElement.typerep]), location=top.location); top.totalTranslation = - if s.isTotal && !null(matchingChildren) + if sTotal && !null(matchingChildren) then {- When s is total, optimized translation of one(s) for prod::(Foo ::= a::Foo b::Integer c::Bar): prod(a.s, b, c) -} @@ -631,8 +627,8 @@ top::StrategyExprs ::= h::StrategyExpr t::StrategyExprs local attrMatch::Boolean = attrMatchesFrame(top.env, attr, hType); top.attrRefNames = (if attrMatch && !h.isId - then just(pair(case h of totalRef(_) -> true | _ -> false end, attr)) - else nothing()) :: t.attrRefNames; + then just(pair(if h.attrRefName.isJust then h.isTotal else h.isTotalInf, attr)) + else nothing()) :: t.attrRefNames; top.errors <- if !null(top.givenInputElements) && !attrMatch && !h.isId then [wrn(h.location, s"This (non-identity) strategy attribute does not occur on ${prettyType(hType)} and will be treated as identity")] @@ -666,26 +662,28 @@ top::StrategyExpr ::= n::Name s::StrategyExpr else [pair(top.genName, s)]; top.freeRecVars := removeBy(stringEq, n.name, s.freeRecVars); top.isTotalInf = s.isTotalInf; - top.isTotal = - -- If s is lifted, then we must determine totality without the env - if top.outerAttr.isJust - then s.isTotal - else s.isTotalInf; + top.isTotal = s.isTotal; s.recVarEnv = pair(n.name, fromMaybe(pair(s.isTotalInf, s.genName), top.outerAttr)) :: top.recVarEnv; + s.outerTotalRecVars = + case top.outerAttr of + | just(pair(true, _)) -> [n.name] + | _ -> [] + end ++ top.outerTotalRecVars; s.outerAttr = top.outerAttr; + local sTotal::Boolean = if top.outerAttr.isJust then s.isTotal else s.isTotalInf; top.partialTranslation = if top.outerAttr.isJust then s.partialTranslation - else if s.isTotal + else if sTotal then asPartial(top.totalTranslation) else Silver_Expr { $name{top.frame.signature.outputElement.elementName}.$name{top.genName} }; top.totalTranslation = if top.outerAttr.isJust then s.totalTranslation - else if s.isTotal + else if sTotal then Silver_Expr { $name{top.frame.signature.outputElement.elementName}.$name{top.genName} } else asTotal(top.partialTranslation); } @@ -815,7 +813,7 @@ top::StrategyExpr ::= id::QName propagate liftedStrategies; top.attrRefName = just(fromMaybe(id.name, mapMaybe(snd, lookupBy(stringEq, id.name, top.recVarEnv)))); top.isId = false; - top.isTotalInf = false; -- Conservative assumption without env + top.isTotalInf = containsBy(stringEq, id.name, top.outerTotalRecVars); -- Conservative assumption without env local attrDcl::DclInfo = id.lookupAttribute.dcl; attrDcl.givenNonterminalType = error("Not actually needed"); -- Ugh environment needs refactoring @@ -847,7 +845,7 @@ top::StrategyExpr ::= id::Decorated QName propagate liftedStrategies; top.attrRefName = mapMaybe(snd, lookupBy(stringEq, id.name, top.recVarEnv)); - top.isTotalInf = false; + top.isTotalInf = containsBy(stringEq, id.name, top.outerTotalRecVars); top.isTotal = lookupBy(stringEq, id.name, top.recVarEnv).fromJust.fst; top.freeRecVars <- [id.name]; From 83c4cf8a389857a3250252b138c79824adc3b8be Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Fri, 8 May 2020 14:27:37 -0500 Subject: [PATCH 57/78] Fix to error checking --- .../silver/extension/strategyattr/StrategyExpr.sv | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/grammars/silver/extension/strategyattr/StrategyExpr.sv b/grammars/silver/extension/strategyattr/StrategyExpr.sv index cdd497f59..8f7b9afdb 100644 --- a/grammars/silver/extension/strategyattr/StrategyExpr.sv +++ b/grammars/silver/extension/strategyattr/StrategyExpr.sv @@ -539,16 +539,21 @@ top::StrategyExpr ::= prod::QName s::StrategyExprs { top.unparse = s"${prod.unparse}(${s.unparse})"; + top.errors <- prod.lookupValue.errors; + local numParams::Integer = length(s.givenInputElements); local numArgs::Integer = length(s.attrRefNames); top.errors <- - if numArgs != numParams + if prod.lookupValue.found && numArgs != numParams then [err(top.location, s"Wrong number of arguments to ${prod.name}: expected ${toString(numParams)}, got ${toString(numArgs)}")] else []; propagate liftedStrategies; - s.givenInputElements = prod.lookupValue.dcl.namedSignature.inputElements; + s.givenInputElements = + if prod.lookupValue.found + then prod.lookupValue.dcl.namedSignature.inputElements + else []; -- pair(child name, if attr occurs on child then just(attr name) else nothing()) local childAccesses::[Pair>>] = @@ -626,7 +631,7 @@ top::StrategyExprs ::= h::StrategyExpr t::StrategyExprs local attr::String = fromMaybe(h.genName, h.attrRefName); local attrMatch::Boolean = attrMatchesFrame(top.env, attr, hType); top.attrRefNames = - (if attrMatch && !h.isId + (if !null(top.givenInputElements) && attrMatch && !h.isId then just(pair(if h.attrRefName.isJust then h.isTotal else h.isTotalInf, attr)) else nothing()) :: t.attrRefNames; top.errors <- From 5dc31e25c340d2a31747fa1fd0e58c3629115916 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Fri, 8 May 2020 15:35:48 -0500 Subject: [PATCH 58/78] Add regex example to Jenkins downstream --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index c4c337697..82a6456d8 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -94,7 +94,7 @@ melt.trynode('silver') { stage("Integration") { // 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/ableJ14", "/melt-umn/meta-ocaml-lite", "/melt-umn/rewriting-lambda-calculus", + def github_projects = ["/melt-umn/ableC", "/melt-umn/Oberon0", "/melt-umn/ableJ14", "/melt-umn/meta-ocaml-lite", "/melt-umn/rewriting-lambda-calculus", "/melt-umn/rewriting-regex-matching", "/internal/ring"] // Specific other jobs to build def specific_jobs = ["/internal/matlab/master", "/internal/metaII/master", "/internal/simple/master"] From 6f83f3be5cf14d5c25b5754008df6e3a17b530d8 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Tue, 12 May 2020 12:26:58 -0500 Subject: [PATCH 59/78] Slight simplifications to translation --- .../extension/strategyattr/StrategyExpr.sv | 22 ++++++++----------- test/silver_features/Strategy.sv | 4 ++++ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/grammars/silver/extension/strategyattr/StrategyExpr.sv b/grammars/silver/extension/strategyattr/StrategyExpr.sv index 8f7b9afdb..062adea0b 100644 --- a/grammars/silver/extension/strategyattr/StrategyExpr.sv +++ b/grammars/silver/extension/strategyattr/StrategyExpr.sv @@ -235,13 +235,11 @@ top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr decorate res with { $ExprInhs{allInhs} }.$name{s2Name}) } end; - top.totalTranslation = - if s1.isTotal && s2Total - then - Silver_Expr { - decorate $Expr{s1.totalTranslation} with { $ExprInhs{allInhs} }.$name{s2Name} - } - else asTotal(top.partialTranslation); + local totalTrans::Expr = + Silver_Expr { + decorate $Expr{s1.totalTranslation} with { $ExprInhs{allInhs} }.$name{s2Name} + }; + top.totalTranslation = if s2Total then totalTrans else asTotal(totalTrans); } abstract production choice @@ -260,14 +258,12 @@ top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr core:orElse($Expr{s1.partialTranslation}, $Expr{s2.partialTranslation}) }; top.totalTranslation = - case s1.isTotal, s2.isTotal of - | true, _ -> s1.totalTranslation - | false, true -> + if s1.isTotal + then s1.totalTranslation + else Silver_Expr { core:fromMaybe($Expr{s2.totalTranslation}, $Expr{s1.partialTranslation}) - } - | false, false -> asTotal(top.partialTranslation) - end; + }; } -- Traversals diff --git a/test/silver_features/Strategy.sv b/test/silver_features/Strategy.sv index ab590e37a..9f83825a5 100644 --- a/test/silver_features/Strategy.sv +++ b/test/silver_features/Strategy.sv @@ -176,3 +176,7 @@ inherited attribute badInh::a; wrongCode "cannot be used as total strategy" { strategy attribute badInhS = badInh; } + +wrongCode "is not total" { + strategy attribute notTotal = rule on SExpr of constSExpr(i) -> constSExpr(i + 1) end; +} From 5330f6588edea8b5ce9e3befe47631f6595aa16a Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Wed, 13 May 2020 16:45:00 -0500 Subject: [PATCH 60/78] Refactoring, simplification and improvments to totality inference process --- .../extension/strategyattr/ConcreteSyntax.sv | 4 +- .../silver/extension/strategyattr/DclInfo.sv | 11 +- .../silver/extension/strategyattr/Strategy.sv | 29 +++-- .../extension/strategyattr/StrategyExpr.sv | 109 ++++++++++-------- test/silver_features/Strategy.sv | 9 +- 5 files changed, 90 insertions(+), 72 deletions(-) diff --git a/grammars/silver/extension/strategyattr/ConcreteSyntax.sv b/grammars/silver/extension/strategyattr/ConcreteSyntax.sv index 60ce9cebb..eae5b0ab4 100644 --- a/grammars/silver/extension/strategyattr/ConcreteSyntax.sv +++ b/grammars/silver/extension/strategyattr/ConcreteSyntax.sv @@ -7,7 +7,7 @@ top::AGDcl ::= 'partial' 'strategy' 'attribute' a::Name '=' e::StrategyExpr_c '; { top.unparse = "strategy attribute " ++ a.unparse ++ "=" ++ e.unparse ++ ";"; e.givenGenName = a.name; - forwards to strategyAttributeDcl(false, a, [], e.ast, location=top.location); + forwards to strategyAttributeDcl(false, a, [], [], e.ast, location=top.location); } concrete production totalStrategyAttributeDcl @@ -15,7 +15,7 @@ top::AGDcl ::= 'strategy' 'attribute' a::Name '=' e::StrategyExpr_c ';' { top.unparse = "strategy attribute " ++ a.unparse ++ "=" ++ e.unparse ++ ";"; e.givenGenName = a.name; - forwards to strategyAttributeDcl(true, a, [], e.ast, location=top.location); + forwards to strategyAttributeDcl(true, a, [], [], e.ast, location=top.location); } closed nonterminal StrategyExpr_c with location, givenGenName, unparse, ast; diff --git a/grammars/silver/extension/strategyattr/DclInfo.sv b/grammars/silver/extension/strategyattr/DclInfo.sv index f68ea7ed3..be6d92bba 100644 --- a/grammars/silver/extension/strategyattr/DclInfo.sv +++ b/grammars/silver/extension/strategyattr/DclInfo.sv @@ -4,7 +4,8 @@ synthesized attribute isStrategy::Boolean occurs on DclInfo; attribute isTotal occurs on DclInfo; synthesized attribute containsErrors::Boolean occurs on DclInfo; synthesized attribute liftedStrategyNames::[String] occurs on DclInfo; -synthesized attribute givenRecVarEnv::[Pair>] occurs on DclInfo; +synthesized attribute givenRecVarNameEnv::[Pair] occurs on DclInfo; +synthesized attribute givenRecVarTotalEnv::[Pair] occurs on DclInfo; attribute totalRefs occurs on DclInfo; synthesized attribute strategyExpr :: StrategyExpr occurs on DclInfo; @@ -15,7 +16,8 @@ top::DclInfo ::= top.isTotal = true; top.containsErrors = false; top.liftedStrategyNames = []; - top.givenRecVarEnv = []; + top.givenRecVarNameEnv = []; + top.givenRecVarTotalEnv = []; top.totalRefs := []; top.strategyExpr = error("Internal compiler error: must be defined for all strategy attribute declarations"); } @@ -23,7 +25,7 @@ top::DclInfo ::= abstract production strategyDcl top::DclInfo ::= sg::String sl::Location fn::String isTotal::Boolean tyVar::TyVar - containsErrors::Boolean liftedStrategyNames::[String] givenRecVarEnv::[Pair>] totalRefs::[String] + containsErrors::Boolean liftedStrategyNames::[String] givenRecVarNameEnv::[Pair] givenRecVarTotalEnv::[Pair] totalRefs::[String] e::StrategyExpr { top.sourceGrammar = sg; @@ -47,7 +49,8 @@ top::DclInfo ::= top.isTotal = isTotal; top.containsErrors = containsErrors; top.liftedStrategyNames = liftedStrategyNames; - top.givenRecVarEnv = givenRecVarEnv; + top.givenRecVarNameEnv = givenRecVarNameEnv; + top.givenRecVarTotalEnv = givenRecVarTotalEnv; top.totalRefs := totalRefs; top.strategyExpr = e; } diff --git a/grammars/silver/extension/strategyattr/Strategy.sv b/grammars/silver/extension/strategyattr/Strategy.sv index 67004b6f9..ee31e445e 100644 --- a/grammars/silver/extension/strategyattr/Strategy.sv +++ b/grammars/silver/extension/strategyattr/Strategy.sv @@ -4,7 +4,7 @@ import silver:definition:flow:driver only ProductionGraph, FlowType, constructAn import silver:driver:util; abstract production strategyAttributeDcl -top::AGDcl ::= isTotal::Boolean a::Name recVarEnv::[Pair>] e::StrategyExpr +top::AGDcl ::= isTotal::Boolean a::Name recVarNameEnv::[Pair] recVarTotalEnv::[Pair] e::StrategyExpr { top.unparse = (if isTotal then "" else "partial ") ++ "strategy attribute " ++ a.unparse ++ "=" ++ e.unparse ++ ";"; @@ -37,9 +37,9 @@ top::AGDcl ::= isTotal::Boolean a::Name recVarEnv::[Pair> -> v.snd.fst, recVarEnv)); - e.outerAttr = just(pair(isTotal, a.name)); + e.recVarNameEnv = recVarNameEnv; + e.recVarTotalEnv = recVarTotalEnv; + e.outerAttr = just(a.name); local fwrd::AGDcl = foldr( @@ -49,12 +49,17 @@ top::AGDcl ::= isTotal::Boolean a::Name recVarEnv::[Pair -> - strategyAttributeDcl(d.snd.isTotalInf, name(d.fst, top.location), d.snd.recVarEnv, new(d.snd), location=top.location), - e.liftedStrategies)); + strategyAttributeDcl( + d.snd.isTotalInf, name(d.fst, top.location), d.snd.recVarNameEnv, d.snd.recVarTotalEnv, new(d.snd), + location=top.location), + decorate e with { + env = emptyEnv(); -- Forward (and thus lifting) cannot depend on top.env to avoid circular dependency + config = e.config; grammarName = e.grammarName; recVarNameEnv = recVarNameEnv; recVarTotalEnv = recVarTotalEnv; outerAttr = e.outerAttr; + }.liftedStrategies)); --forwards to unsafeTrace(fwrd, print(a.name ++ " = " ++ e.unparse ++ "; lifted " ++ implode(", ", map(fst, e.liftedStrategies)) ++ "\n\n", unsafeIO())); forwards to fwrd; @@ -120,9 +125,9 @@ top::ProductionStmt ::= attr::Decorated QName e.config = top.config; e.frame = top.frame; e.env = top.env; - e.recVarEnv = attr.lookupAttribute.dcl.givenRecVarEnv; - e.outerTotalRecVars = map(fst, filter(\ v::Pair> -> v.snd.fst, e.recVarEnv)); - e.outerAttr = just(pair(isTotal, attr.lookupAttribute.fullName)); + e.recVarNameEnv = attr.lookupAttribute.dcl.givenRecVarNameEnv; + e.recVarTotalEnv = attr.lookupAttribute.dcl.givenRecVarTotalEnv; + e.outerAttr = just(attr.lookupAttribute.fullName); e.inlinedStrategies = [attr.lookupAttribute.fullName]; -- Don't unfold the top-level strategy within itself production e2::StrategyExpr = e.optimize; @@ -130,8 +135,8 @@ top::ProductionStmt ::= attr::Decorated QName e2.config = e.config; e2.frame = e.frame; e2.env = e.env; - e2.recVarEnv = e.recVarEnv; - e2.outerTotalRecVars = e.outerTotalRecVars; + e2.recVarNameEnv = e.recVarNameEnv; + e2.recVarTotalEnv = e.recVarTotalEnv; e2.outerAttr = e.outerAttr; e2.inlinedStrategies = e.inlinedStrategies; diff --git a/grammars/silver/extension/strategyattr/StrategyExpr.sv b/grammars/silver/extension/strategyattr/StrategyExpr.sv index 062adea0b..cc93c8c11 100644 --- a/grammars/silver/extension/strategyattr/StrategyExpr.sv +++ b/grammars/silver/extension/strategyattr/StrategyExpr.sv @@ -5,17 +5,17 @@ import core:monad; annotation genName::String; -- Used to generate the names of lifted strategy attributes -autocopy attribute recVarEnv::[Pair>]; -- name, (isTotal, genName) -autocopy attribute outerTotalRecVars::[String]; -inherited attribute outerAttr::Maybe>; -- isTotal, genName +autocopy attribute recVarNameEnv::[Pair]; -- name, (isTotal, genName) +autocopy attribute recVarTotalEnv::[Pair]; -- name, (isTotal, genName) +inherited attribute outerAttr::Maybe; autocopy attribute inlinedStrategies::[String]; monoid attribute liftedStrategies::[Pair] with [], ++; synthesized attribute attrRefName::Maybe; synthesized attribute isId::Boolean; -synthesized attribute isTotalInf::Boolean; -- Env-independant, used for inference -synthesized attribute isTotal::Boolean; -- Env-dependant, used for translation / optimization +synthesized attribute isTotalInf::Boolean; -- Is total assuming all rec vars are total +synthesized attribute isTotal::Boolean; -- Is total given rec var env inherited attribute givenInputElements::[NamedSignatureElement]; -synthesized attribute attrRefNames::[Maybe>]; +synthesized attribute attrRefNames::[Maybe]; monoid attribute containsFail::Boolean with false, ||; monoid attribute allId::Boolean with true, &&; monoid attribute freeRecVars::[String] with [], ++; @@ -52,7 +52,8 @@ partial strategy attribute ntStep = -- strategies would not permit any additional simplification. | partialRef(n) when n.matchesFrame && n.attrDcl.isStrategy && - !containsBy(stringEq, n.attrDcl.fullName, top.inlinedStrategies) && null(n.attrDcl.givenRecVarEnv) -> + !containsBy(stringEq, n.attrDcl.fullName, top.inlinedStrategies) && + null(n.attrDcl.givenRecVarNameEnv) -> inlined(n, n.attrDcl.strategyExpr, location=top.location, genName=top.genName) | partialRef(n) when !n.matchesFrame -> fail(location=top.location, genName=top.genName) | inlined(n, _) when !n.matchesFrame -> fail(location=top.location, genName=top.genName) @@ -92,31 +93,31 @@ strategy attribute optimize = nonterminal StrategyExpr with config, grammarName, env, location, unparse, errors, frame, compiledGrammars, flowEnv, flowDefs, -- Normal expression stuff - genName, outerAttr, recVarEnv, outerTotalRecVars, liftedStrategies, attrRefName, isId, isTotalInf, isTotal, freeRecVars, totalRefs, -- Frame-independent attrs + genName, outerAttr, recVarNameEnv, recVarTotalEnv, liftedStrategies, attrRefName, isId, isTotalInf, isTotal, freeRecVars, totalRefs, -- Frame-independent attrs partialTranslation, totalTranslation, matchesFrame, -- Frame-dependent attrs inlinedStrategies, genericStep, ntStep, prodStep, simplify, optimize; -- Optimization stuff nonterminal StrategyExprs with config, grammarName, env, unparse, errors, frame, compiledGrammars, flowEnv, flowDefs, -- Normal expression stuff - recVarEnv, outerTotalRecVars, givenInputElements, liftedStrategies, attrRefNames, containsFail, allId, freeRecVars, totalRefs, -- Frame-independent attrs + recVarNameEnv, recVarTotalEnv, givenInputElements, liftedStrategies, attrRefNames, containsFail, allId, freeRecVars, totalRefs, -- Frame-independent attrs inlinedStrategies, simplify; -- Optimization stuff flowtype StrategyExpr = - decorate {grammarName, config, recVarEnv, outerTotalRecVars, outerAttr}, -- NOT frame or env + decorate {env, grammarName, config, recVarNameEnv, recVarTotalEnv, outerAttr}, -- NOT frame -- Normal expression stuff - unparse {}, errors {decorate, frame, env, compiledGrammars, flowEnv}, flowDefs {decorate, frame, env, compiledGrammars, flowEnv}, + unparse {}, errors {decorate, frame, compiledGrammars, flowEnv}, flowDefs {decorate, frame, compiledGrammars, flowEnv}, -- Frame-independent attrs - liftedStrategies {decorate}, attrRefName {decorate}, isId {decorate}, isTotalInf {decorate}, isTotal {decorate, env}, freeRecVars {decorate, env}, totalRefs {decorate, env}, + liftedStrategies {decorate}, attrRefName {decorate}, isId {decorate}, isTotalInf {grammarName, config, env, recVarNameEnv, outerAttr}, isTotal {decorate}, freeRecVars {decorate}, totalRefs {decorate}, -- Frame-dependent attrs - partialTranslation {decorate, frame, env}, totalTranslation {decorate, frame, env}, matchesFrame {decorate, frame, env}; + partialTranslation {decorate, frame}, totalTranslation {decorate, frame}, matchesFrame {decorate, frame}; flowtype StrategyExprs = - decorate {grammarName, config, recVarEnv, outerTotalRecVars}, -- NOT frame or env + decorate {env, grammarName, config, recVarNameEnv, recVarTotalEnv}, -- NOT frame -- Normal expression stuff - unparse {}, errors {decorate, frame, env, givenInputElements, compiledGrammars, flowEnv}, flowDefs {decorate, frame, env, compiledGrammars, flowEnv}, + unparse {}, errors {decorate, frame, givenInputElements, compiledGrammars, flowEnv}, flowDefs {decorate, frame, compiledGrammars, flowEnv}, -- Frame-independent attrs - liftedStrategies {decorate}, attrRefNames {decorate, env, givenInputElements}, - containsFail {decorate, env}, allId {decorate, env}, freeRecVars {decorate, env}, totalRefs {decorate, env}; + liftedStrategies {decorate}, attrRefNames {decorate, givenInputElements}, + containsFail {decorate}, allId {decorate}, freeRecVars {decorate}, totalRefs {decorate}; propagate errors on StrategyExpr, StrategyExprs excluding partialRef, totalRef; propagate flowDefs on StrategyExpr, StrategyExprs; @@ -177,7 +178,7 @@ top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr top.unparse = s"(${s1.unparse} <* ${s2.unparse})"; local s2Name::String = fromMaybe(top.genName ++ "_snd", s2.attrRefName); - local s2Total::Boolean = if s2.attrRefName.isJust then s2.isTotal else s2.isTotalInf; + local s2Total::Boolean = attrIsTotal(top.env, s2Name); -- Can differ from s2.isTotal because we lift without env top.liftedStrategies := s1.liftedStrategies ++ if s2.attrRefName.isJust @@ -273,7 +274,7 @@ top::StrategyExpr ::= s::StrategyExpr top.unparse = s"all(${s.unparse})"; local sName::String = fromMaybe(top.genName ++ "_all_arg", s.attrRefName); - local sTotal::Boolean = if s.attrRefName.isJust then s.isTotal else s.isTotalInf; + local sTotal::Boolean = attrIsTotal(top.env, sName); -- Can differ from s.isTotal because we lift without env top.liftedStrategies := if s.attrRefName.isJust then [] @@ -361,7 +362,7 @@ top::StrategyExpr ::= s::StrategyExpr top.unparse = s"some(${s.unparse})"; local sName::String = fromMaybe(top.genName ++ "_some_arg", s.attrRefName); - local sTotal::Boolean = if s.attrRefName.isJust then s.isTotal else s.isTotalInf; + local sTotal::Boolean = attrIsTotal(top.env, sName); -- Can differ from s.isTotal because we lift without env top.liftedStrategies := if s.attrRefName.isJust then [] @@ -438,7 +439,7 @@ top::StrategyExpr ::= s::StrategyExpr top.unparse = s"one(${s.unparse})"; local sName::String = fromMaybe(top.genName ++ "_one_arg", s.attrRefName); - local sTotal::Boolean = if s.attrRefName.isJust then s.isTotal else s.isTotalInf; + local sTotal::Boolean = attrIsTotal(top.env, sName); -- Can differ from s.isTotal because we lift without env top.liftedStrategies := if s.attrRefName.isJust then [] @@ -552,7 +553,7 @@ top::StrategyExpr ::= prod::QName s::StrategyExprs else []; -- pair(child name, if attr occurs on child then just(attr name) else nothing()) - local childAccesses::[Pair>>] = + local childAccesses::[Pair>] = zipWith(pair, top.frame.signature.inputNames, s.attrRefNames); top.partialTranslation = -- This is never total if prod.lookupValue.fullName == top.frame.fullName @@ -566,17 +567,17 @@ top::StrategyExpr ::= prod::QName s::StrategyExprs Could also be implemented as chained monadic binds. Maybe more efficient this way? -} caseExpr( flatMap( - \ a::Pair>> -> + \ a::Pair> -> case a.snd of - | just(pair(false, attr)) -> [Silver_Expr { $name{a.fst}.$name{attr} }] + | just(attr) when !attrIsTotal(top.env, attr) -> [Silver_Expr { $name{a.fst}.$name{attr} }] | _ -> [] end, childAccesses), [matchRule( flatMap( - \ a::Pair>> -> + \ a::Pair> -> case a.snd of - | just(pair(false, attr)) -> + | just(attr) when !attrIsTotal(top.env, attr) -> [decorate Silver_Pattern { core:just($name{a.fst ++ "_" ++ last(explode(":", attr))}) } with { config = top.config; env = top.env; frame = top.frame; patternVarEnv = []; }] | _ -> [] @@ -590,10 +591,10 @@ top::StrategyExpr ::= prod::QName s::StrategyExprs top.location, baseExpr(qName(top.location, top.frame.fullName), location=top.location), map( - \ a::Pair>> -> + \ a::Pair> -> case a.snd of - | just(pair(true, attr)) -> Silver_Expr { $name{a.fst}.$name{attr} } - | just(pair(false, attr)) -> Silver_Expr { $name{a.fst ++ "_" ++ last(explode(":", attr))} } + | just(attr) when attrIsTotal(top.env, attr) -> Silver_Expr { $name{a.fst}.$name{attr} } + | just(attr) -> Silver_Expr { $name{a.fst ++ "_" ++ last(explode(":", attr))} } | nothing() -> Silver_Expr { $name{a.fst} } end, childAccesses), @@ -628,7 +629,7 @@ top::StrategyExprs ::= h::StrategyExpr t::StrategyExprs local attrMatch::Boolean = attrMatchesFrame(top.env, attr, hType); top.attrRefNames = (if !null(top.givenInputElements) && attrMatch && !h.isId - then just(pair(if h.attrRefName.isJust then h.isTotal else h.isTotalInf, attr)) + then just(attr) else nothing()) :: t.attrRefNames; top.errors <- if !null(top.givenInputElements) && !attrMatch && !h.isId @@ -663,15 +664,10 @@ top::StrategyExpr ::= n::Name s::StrategyExpr else [pair(top.genName, s)]; top.freeRecVars := removeBy(stringEq, n.name, s.freeRecVars); top.isTotalInf = s.isTotalInf; - top.isTotal = s.isTotal; + top.isTotal = s.isTotal; -- Invariant: should be same as isTotalInf - s.recVarEnv = - pair(n.name, fromMaybe(pair(s.isTotalInf, s.genName), top.outerAttr)) :: top.recVarEnv; - s.outerTotalRecVars = - case top.outerAttr of - | just(pair(true, _)) -> [n.name] - | _ -> [] - end ++ top.outerTotalRecVars; + s.recVarNameEnv = pair(n.name, fromMaybe(s.genName, top.outerAttr)) :: top.recVarNameEnv; + s.recVarTotalEnv = pair(n.name, s.isTotalInf) :: top.recVarTotalEnv; s.outerAttr = top.outerAttr; local sTotal::Boolean = if top.outerAttr.isJust then s.isTotal else s.isTotalInf; @@ -812,21 +808,19 @@ top::StrategyExpr ::= id::QName -- Forwarding depends on env here, these must be computed without env propagate liftedStrategies; - top.attrRefName = just(fromMaybe(id.name, mapMaybe(snd, lookupBy(stringEq, id.name, top.recVarEnv)))); + top.attrRefName = just(fromMaybe(id.name, lookupBy(stringEq, id.name, top.recVarNameEnv))); top.isId = false; - top.isTotalInf = containsBy(stringEq, id.name, top.outerTotalRecVars); -- Conservative assumption without env local attrDcl::DclInfo = id.lookupAttribute.dcl; attrDcl.givenNonterminalType = error("Not actually needed"); -- Ugh environment needs refactoring forwards to - if lookupBy(stringEq, id.name, top.recVarEnv).isJust + if lookupBy(stringEq, id.name, top.recVarNameEnv).isJust then recVarRef(id, genName=top.genName, location=top.location) else if !null(id.lookupAttribute.errors) then errorRef(id.lookupAttribute.errors, id, genName=top.genName, location=top.location) - else case decorate id.lookupAttribute.dcl with { givenNonterminalType = error("Not actually needed"); }.typerep of -- Ugh environment needs refactoring - | nonterminalType("core:Maybe", _) -> partialRef(qNameAttrOccur(id, location=top.location), genName=top.genName, location=top.location) - | _ -> totalRef(qNameAttrOccur(id, location=top.location), genName=top.genName, location=top.location) - end; + else if attrIsTotal(top.env, id.name) + then totalRef(qNameAttrOccur(id, location=top.location), genName=top.genName, location=top.location) + else partialRef(qNameAttrOccur(id, location=top.location), genName=top.genName, location=top.location); } abstract production errorRef top::StrategyExpr ::= msg::[Message] id::Decorated QName @@ -845,17 +839,17 @@ top::StrategyExpr ::= id::Decorated QName top.unparse = id.unparse; propagate liftedStrategies; - top.attrRefName = mapMaybe(snd, lookupBy(stringEq, id.name, top.recVarEnv)); - top.isTotalInf = containsBy(stringEq, id.name, top.outerTotalRecVars); - top.isTotal = lookupBy(stringEq, id.name, top.recVarEnv).fromJust.fst; + top.attrRefName = lookupBy(stringEq, id.name, top.recVarNameEnv); + top.isTotalInf = true; + top.isTotal = lookupBy(stringEq, id.name, top.recVarTotalEnv).fromJust; top.freeRecVars <- [id.name]; top.partialTranslation = - if top.isTotalInf + if attrIsTotal(top.env, top.attrRefName.fromJust) then asPartial(top.totalTranslation) else Silver_Expr { $name{top.frame.signature.outputElement.elementName}.$qName{top.attrRefName.fromJust} }; top.totalTranslation = - if top.isTotalInf + if attrIsTotal(top.env, top.attrRefName.fromJust) then Silver_Expr { $name{top.frame.signature.outputElement.elementName}.$qName{top.attrRefName.fromJust} } else asTotal(top.partialTranslation); } @@ -953,6 +947,21 @@ top::QNameAttrOccur ::= at::QName end; } +function attrIsTotal +Boolean ::= env::Decorated Env attrName::String +{ + local dcls::[DclInfo] = getAttrDcl(attrName, env); + return + case dcls of + | [] -> false + | d :: _ -> + case decorate d with { givenNonterminalType = error("Not actually needed"); }.typerep of -- Ugh environment needs refactoring + | nonterminalType("core:Maybe", _) -> false + | _ -> true + end + end; +} + function attrMatchesFrame Boolean ::= env::Decorated Env attrName::String attrFor::Type { diff --git a/test/silver_features/Strategy.sv b/test/silver_features/Strategy.sv index 9f83825a5..bf1e5bea6 100644 --- a/test/silver_features/Strategy.sv +++ b/test/silver_features/Strategy.sv @@ -89,10 +89,11 @@ top::SExpr ::= i::Integer { top.incConstsF = constSExpr(i + 1); } strategy attribute incConsts = - allTopDown( - rule on SExpr of - | constSExpr(i) -> constSExpr(i + 1) - end) occurs on SStmt, SExpr; + (fail <+ id <+ fail) <* + allTopDown( + rule on SExpr of + | constSExpr(i) -> constSExpr(i + 1) + end) occurs on SStmt, SExpr; propagate incConsts on SStmt, SExpr; strategy attribute incTwice = incConstsF <* incConsts From debcb81a5a494b7a74d0bc82423ba19d9a4def54 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Wed, 13 May 2020 18:06:02 -0500 Subject: [PATCH 61/78] Further fix to totality checking, get rid of isTotalInf --- .../silver/extension/strategyattr/Strategy.sv | 2 +- .../extension/strategyattr/StrategyExpr.sv | 32 ++++++++----------- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/grammars/silver/extension/strategyattr/Strategy.sv b/grammars/silver/extension/strategyattr/Strategy.sv index ee31e445e..945b458be 100644 --- a/grammars/silver/extension/strategyattr/Strategy.sv +++ b/grammars/silver/extension/strategyattr/Strategy.sv @@ -54,7 +54,7 @@ top::AGDcl ::= isTotal::Boolean a::Name recVarNameEnv::[Pair] rec map( \ d::Pair -> strategyAttributeDcl( - d.snd.isTotalInf, name(d.fst, top.location), d.snd.recVarNameEnv, d.snd.recVarTotalEnv, new(d.snd), + d.snd.isTotal, name(d.fst, top.location), d.snd.recVarNameEnv, d.snd.recVarTotalEnv, new(d.snd), location=top.location), decorate e with { env = emptyEnv(); -- Forward (and thus lifting) cannot depend on top.env to avoid circular dependency diff --git a/grammars/silver/extension/strategyattr/StrategyExpr.sv b/grammars/silver/extension/strategyattr/StrategyExpr.sv index cc93c8c11..1b73ee065 100644 --- a/grammars/silver/extension/strategyattr/StrategyExpr.sv +++ b/grammars/silver/extension/strategyattr/StrategyExpr.sv @@ -12,8 +12,7 @@ autocopy attribute inlinedStrategies::[String]; monoid attribute liftedStrategies::[Pair] with [], ++; synthesized attribute attrRefName::Maybe; synthesized attribute isId::Boolean; -synthesized attribute isTotalInf::Boolean; -- Is total assuming all rec vars are total -synthesized attribute isTotal::Boolean; -- Is total given rec var env +synthesized attribute isTotal::Boolean; inherited attribute givenInputElements::[NamedSignatureElement]; synthesized attribute attrRefNames::[Maybe]; monoid attribute containsFail::Boolean with false, ||; @@ -93,7 +92,7 @@ strategy attribute optimize = nonterminal StrategyExpr with config, grammarName, env, location, unparse, errors, frame, compiledGrammars, flowEnv, flowDefs, -- Normal expression stuff - genName, outerAttr, recVarNameEnv, recVarTotalEnv, liftedStrategies, attrRefName, isId, isTotalInf, isTotal, freeRecVars, totalRefs, -- Frame-independent attrs + genName, outerAttr, recVarNameEnv, recVarTotalEnv, liftedStrategies, attrRefName, isId, isTotal, freeRecVars, totalRefs, -- Frame-independent attrs partialTranslation, totalTranslation, matchesFrame, -- Frame-dependent attrs inlinedStrategies, genericStep, ntStep, prodStep, simplify, optimize; -- Optimization stuff @@ -107,7 +106,7 @@ flowtype StrategyExpr = -- Normal expression stuff unparse {}, errors {decorate, frame, compiledGrammars, flowEnv}, flowDefs {decorate, frame, compiledGrammars, flowEnv}, -- Frame-independent attrs - liftedStrategies {decorate}, attrRefName {decorate}, isId {decorate}, isTotalInf {grammarName, config, env, recVarNameEnv, outerAttr}, isTotal {decorate}, freeRecVars {decorate}, totalRefs {decorate}, + liftedStrategies {decorate}, attrRefName {decorate}, isId {decorate}, isTotal {decorate}, freeRecVars {decorate}, totalRefs {decorate}, -- Frame-dependent attrs partialTranslation {decorate, frame}, totalTranslation {decorate, frame}, matchesFrame {decorate, frame}; @@ -148,7 +147,6 @@ top::StrategyExpr ::= top.attrRefName = nothing(); top.matchesFrame := true; -- Consulted only when attrRefName is just(...) top.isId = false; - top.isTotalInf = false; top.isTotal = false; } @@ -159,7 +157,6 @@ top::StrategyExpr ::= top.unparse = "id"; propagate liftedStrategies; top.isId = true; - top.isTotalInf = true; top.isTotal = true; top.totalTranslation = Silver_Expr { $name{top.frame.signature.outputElement.elementName} }; } @@ -184,7 +181,6 @@ top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr if s2.attrRefName.isJust then [] else [pair(s2Name, s2)]; - top.isTotalInf = s1.isTotalInf && s2.isTotalInf; top.isTotal = s1.isTotal && s2.isTotal; s1.outerAttr = nothing(); @@ -248,7 +244,6 @@ top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr { top.unparse = s"(${s1.unparse} <+ ${s2.unparse})"; propagate liftedStrategies; - top.isTotalInf = s1.isTotalInf || s2.isTotalInf; top.isTotal = s1.isTotal || s2.isTotal; s1.outerAttr = nothing(); @@ -279,7 +274,6 @@ top::StrategyExpr ::= s::StrategyExpr if s.attrRefName.isJust then [] else [pair(sName, s)]; - top.isTotalInf = s.isTotalInf; top.isTotal = s.isTotal; s.outerAttr = nothing(); @@ -663,14 +657,18 @@ top::StrategyExpr ::= n::Name s::StrategyExpr then s.liftedStrategies else [pair(top.genName, s)]; top.freeRecVars := removeBy(stringEq, n.name, s.freeRecVars); - top.isTotalInf = s.isTotalInf; - top.isTotal = s.isTotal; -- Invariant: should be same as isTotalInf - - s.recVarNameEnv = pair(n.name, fromMaybe(s.genName, top.outerAttr)) :: top.recVarNameEnv; - s.recVarTotalEnv = pair(n.name, s.isTotalInf) :: top.recVarTotalEnv; + top.isTotal = + decorate s with { + recVarTotalEnv = pair(n.name, true) :: s.recVarTotalEnv; + env = s.env; config = s.config; grammarName = s.grammarName; recVarNameEnv = s.recVarNameEnv; outerAttr = s.outerAttr; + }.isTotal; + + local sName::String = fromMaybe(s.genName, top.outerAttr); + s.recVarNameEnv = pair(n.name, sName) :: top.recVarNameEnv; + s.recVarTotalEnv = pair(n.name, top.isTotal) :: top.recVarTotalEnv; s.outerAttr = top.outerAttr; - local sTotal::Boolean = if top.outerAttr.isJust then s.isTotal else s.isTotalInf; + local sTotal::Boolean = attrIsTotal(top.env, sName); top.partialTranslation = if top.outerAttr.isJust then s.partialTranslation @@ -840,7 +838,6 @@ top::StrategyExpr ::= id::Decorated QName propagate liftedStrategies; top.attrRefName = lookupBy(stringEq, id.name, top.recVarNameEnv); - top.isTotalInf = true; top.isTotal = lookupBy(stringEq, id.name, top.recVarTotalEnv).fromJust; top.freeRecVars <- [id.name]; @@ -875,7 +872,6 @@ top::StrategyExpr ::= attr::QNameAttrOccur propagate liftedStrategies; top.attrRefName = just(attr.name); top.matchesFrame := attr.matchesFrame; - top.isTotalInf = false; top.isTotal = false; attr.attrFor = top.frame.signature.outputElement.typerep; @@ -907,7 +903,6 @@ top::StrategyExpr ::= attr::QNameAttrOccur propagate liftedStrategies; top.attrRefName = just(attr.name); top.matchesFrame := attr.matchesFrame; - top.isTotalInf = true; top.isTotal = true; top.totalRefs <- [case attr of qNameAttrOccur(a) -> a.lookupAttribute.dcl.fullName end]; @@ -923,7 +918,6 @@ top::StrategyExpr ::= attr::Decorated QNameAttrOccur s::StrategyExpr top.unparse = s"(${s.unparse} aka ${attr.unparse})"; propagate liftedStrategies; top.attrRefName = just(attr.attrDcl.fullName); - top.isTotalInf = s.isTotalInf; top.isTotal = s.isTotal; top.partialTranslation = if attr.matchesFrame From 256745e67712a9832794d3d0a59df2cda7c2fdf9 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Sat, 30 May 2020 20:40:41 -0500 Subject: [PATCH 62/78] Add comments --- grammars/silver/extension/strategyattr/Strategy.sv | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/grammars/silver/extension/strategyattr/Strategy.sv b/grammars/silver/extension/strategyattr/Strategy.sv index 945b458be..ec0cec9c4 100644 --- a/grammars/silver/extension/strategyattr/Strategy.sv +++ b/grammars/silver/extension/strategyattr/Strategy.sv @@ -60,8 +60,13 @@ top::AGDcl ::= isTotal::Boolean a::Name recVarNameEnv::[Pair] rec env = emptyEnv(); -- Forward (and thus lifting) cannot depend on top.env to avoid circular dependency config = e.config; grammarName = e.grammarName; recVarNameEnv = recVarNameEnv; recVarTotalEnv = recVarTotalEnv; outerAttr = e.outerAttr; }.liftedStrategies)); - + + -- Uncomment for debugging --forwards to unsafeTrace(fwrd, print(a.name ++ " = " ++ e.unparse ++ "; lifted " ++ implode(", ", map(fst, e.liftedStrategies)) ++ "\n\n", unsafeIO())); + + -- Flow errors here due to exceeding the allowable host forward flow type. + -- I'm not actually sure where we depend on flowEnv, config or compiledGrammars. + -- This could be fixed by seeding the host flow type or tracking down those dependencies and substituting dummy values. forwards to fwrd; } @@ -165,6 +170,7 @@ top::ProductionStmt ::= attr::Decorated QName \ n::String -> propagateOneAttr(qName(top.location, n), location=top.location), attr.lookupAttribute.dcl.liftedStrategyNames)); + -- Uncomment for debugging --forwards to unsafeTrace(fwrd, print(attr.name ++ " on " ++ top.frame.fullName ++ " = " ++ (if isTotal then e2.totalTranslation else e2.partialTranslation).unparse ++ ";\n\n", unsafeIO())); forwards to fwrd; } From e77a5b4227f5efa1d59f7ce0c3639efd20296877 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Sat, 30 May 2020 20:41:29 -0500 Subject: [PATCH 63/78] Bug fixes with rec translation --- .../silver/extension/strategyattr/StrategyExpr.sv | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/grammars/silver/extension/strategyattr/StrategyExpr.sv b/grammars/silver/extension/strategyattr/StrategyExpr.sv index 1b73ee065..95885cd97 100644 --- a/grammars/silver/extension/strategyattr/StrategyExpr.sv +++ b/grammars/silver/extension/strategyattr/StrategyExpr.sv @@ -39,8 +39,8 @@ partial strategy attribute genericStep = | allTraversal(id()) -> id(location=top.location, genName=top.genName) | someTraversal(fail()) -> fail(location=top.location, genName=top.genName) | oneTraversal(fail()) -> fail(location=top.location, genName=top.genName) - | prodTraversal(_, s) when s.containsFail -> fail(location=top.location, genName=top.genName) - | prodTraversal(_, s) when s.allId -> id(location=top.location, genName=top.genName) + | prodTraversal(_, ss) when ss.containsFail -> fail(location=top.location, genName=top.genName) + | prodTraversal(_, ss) when ss.allId -> id(location=top.location, genName=top.genName) | recComb(n, s) when !containsBy(stringEq, n.name, s.freeRecVars) -> s | inlined(_, fail()) -> fail(location=top.location, genName=top.genName) end; @@ -652,10 +652,11 @@ top::StrategyExpr ::= n::Name s::StrategyExpr { top.unparse = s"rec ${n.name} -> (${s.unparse})"; + local sName::String = fromMaybe(top.genName ++ "_rec_body", top.outerAttr); top.liftedStrategies := if top.outerAttr.isJust then s.liftedStrategies - else [pair(top.genName, s)]; + else [pair(sName, s)]; top.freeRecVars := removeBy(stringEq, n.name, s.freeRecVars); top.isTotal = decorate s with { @@ -663,7 +664,6 @@ top::StrategyExpr ::= n::Name s::StrategyExpr env = s.env; config = s.config; grammarName = s.grammarName; recVarNameEnv = s.recVarNameEnv; outerAttr = s.outerAttr; }.isTotal; - local sName::String = fromMaybe(s.genName, top.outerAttr); s.recVarNameEnv = pair(n.name, sName) :: top.recVarNameEnv; s.recVarTotalEnv = pair(n.name, top.isTotal) :: top.recVarTotalEnv; s.outerAttr = top.outerAttr; @@ -674,12 +674,12 @@ top::StrategyExpr ::= n::Name s::StrategyExpr then s.partialTranslation else if sTotal then asPartial(top.totalTranslation) - else Silver_Expr { $name{top.frame.signature.outputElement.elementName}.$name{top.genName} }; + else Silver_Expr { $name{top.frame.signature.outputElement.elementName}.$name{sName} }; top.totalTranslation = if top.outerAttr.isJust then s.totalTranslation else if sTotal - then Silver_Expr { $name{top.frame.signature.outputElement.elementName}.$name{top.genName} } + then Silver_Expr { $name{top.frame.signature.outputElement.elementName}.$name{sName} } else asTotal(top.partialTranslation); } From 5124a87ac6bc662ab5409daaec1eeb67ff2e3255 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Fri, 3 Jul 2020 14:52:26 -0500 Subject: [PATCH 64/78] Bug fix: report propagate errors when occurence is missing --- grammars/silver/extension/strategyattr/Strategy.sv | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/grammars/silver/extension/strategyattr/Strategy.sv b/grammars/silver/extension/strategyattr/Strategy.sv index ec0cec9c4..c9321f533 100644 --- a/grammars/silver/extension/strategyattr/Strategy.sv +++ b/grammars/silver/extension/strategyattr/Strategy.sv @@ -151,7 +151,8 @@ top::ProductionStmt ::= attr::Decorated QName if attr.lookupAttribute.dcl.containsErrors || -- Check for total strategy ref occurs errors that would already be reported on the occurence - any(map(null, map(getOccursDcl(_, top.frame.signature.outputElement.typerep.typeName, top.env), attr.lookupAttribute.dcl.totalRefs))) + (!null(getOccursDcl(attr.lookupAttribute.fullName, top.frame.signature.outputElement.typerep.typeName, top.env)) && + any(map(null, map(getOccursDcl(_, top.frame.signature.outputElement.typerep.typeName, top.env), attr.lookupAttribute.dcl.totalRefs)))) then [] else forward.errors; From cca26a6e2c8dc2cc5fa5d9394301906b20d31a43 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Sat, 25 Jul 2020 15:05:48 -0500 Subject: [PATCH 65/78] Fix type error in translation when casting partial -> total --- .../extension/strategyattr/StrategyExpr.sv | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/grammars/silver/extension/strategyattr/StrategyExpr.sv b/grammars/silver/extension/strategyattr/StrategyExpr.sv index 95885cd97..e925c5319 100644 --- a/grammars/silver/extension/strategyattr/StrategyExpr.sv +++ b/grammars/silver/extension/strategyattr/StrategyExpr.sv @@ -134,15 +134,23 @@ Expr ::= e::Expr -- Convert an expression of type Maybe to a function asTotal -Expr ::= e::Expr -{ return Silver_Expr { core:fromMaybe(core:error("Total result demanded when partial strategy failed"), $Expr{e}) }; } +Expr ::= t::Type e::Expr +{ + return + Silver_Expr { + let res::$TypeExpr{typerepTypeExpr(t, location=e.location)} = + core:error("Total result demanded when partial strategy failed") + in core:fromMaybe(res, $Expr{e}) + end + }; +} aspect default production top::StrategyExpr ::= { -- At least 1 of these should be defined for every production: top.partialTranslation = asPartial(top.totalTranslation); - top.totalTranslation = asTotal(top.partialTranslation); + top.totalTranslation = asTotal(top.frame.signature.outputElement.typerep, top.partialTranslation); top.attrRefName = nothing(); top.matchesFrame := true; -- Consulted only when attrRefName is just(...) @@ -236,7 +244,7 @@ top::StrategyExpr ::= s1::StrategyExpr s2::StrategyExpr Silver_Expr { decorate $Expr{s1.totalTranslation} with { $ExprInhs{allInhs} }.$name{s2Name} }; - top.totalTranslation = if s2Total then totalTrans else asTotal(totalTrans); + top.totalTranslation = if s2Total then totalTrans else asTotal(top.frame.signature.outputElement.typerep, totalTrans); } abstract production choice @@ -347,7 +355,7 @@ top::StrategyExpr ::= s::StrategyExpr map( makeAnnoArg(top.location, top.frame.signature.outputElement.elementName, _), top.frame.signature.namedInputElements)) - else asTotal(top.partialTranslation); + else asTotal(top.frame.signature.outputElement.typerep, top.partialTranslation); } abstract production someTraversal @@ -425,7 +433,7 @@ top::StrategyExpr ::= s::StrategyExpr map( makeAnnoArg(top.location, top.frame.signature.outputElement.elementName, _), top.frame.signature.namedInputElements)) - else asTotal(top.partialTranslation); + else asTotal(top.frame.signature.outputElement.typerep, top.partialTranslation); } abstract production oneTraversal top::StrategyExpr ::= s::StrategyExpr @@ -522,7 +530,7 @@ top::StrategyExpr ::= s::StrategyExpr map( makeAnnoArg(top.location, top.frame.signature.outputElement.elementName, _), top.frame.signature.namedInputElements)) - else asTotal(top.partialTranslation); + else asTotal(top.frame.signature.outputElement.typerep, top.partialTranslation); } abstract production prodTraversal @@ -680,7 +688,7 @@ top::StrategyExpr ::= n::Name s::StrategyExpr then s.totalTranslation else if sTotal then Silver_Expr { $name{top.frame.signature.outputElement.elementName}.$name{sName} } - else asTotal(top.partialTranslation); + else asTotal(top.frame.signature.outputElement.typerep, top.partialTranslation); } -- Rules @@ -848,7 +856,7 @@ top::StrategyExpr ::= id::Decorated QName top.totalTranslation = if attrIsTotal(top.env, top.attrRefName.fromJust) then Silver_Expr { $name{top.frame.signature.outputElement.elementName}.$qName{top.attrRefName.fromJust} } - else asTotal(top.partialTranslation); + else asTotal(top.frame.signature.outputElement.typerep, top.partialTranslation); } abstract production partialRef top::StrategyExpr ::= attr::QNameAttrOccur From 91205c5adb5f2b934bf7376e875bb1f5cdbf528c Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Sat, 25 Jul 2020 15:06:08 -0500 Subject: [PATCH 66/78] Fix bug with implementation of outermost in both versions of rewriting --- grammars/silver/extension/strategyattr/StrategyUtils.sv | 3 +-- grammars/silver/rewrite/Strategy.sv | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/grammars/silver/extension/strategyattr/StrategyUtils.sv b/grammars/silver/extension/strategyattr/StrategyUtils.sv index 71a893237..9a0648965 100644 --- a/grammars/silver/extension/strategyattr/StrategyUtils.sv +++ b/grammars/silver/extension/strategyattr/StrategyUtils.sv @@ -184,9 +184,8 @@ top::StrategyExpr ::= s::StrategyExpr abstract production outermost top::StrategyExpr ::= s::StrategyExpr { - local recVarName::String = "outermost_" ++ toString(genInt()); forwards to Silver_StrategyExpr (top.genName) { - rec $name{recVarName} -> topDown(try($StrategyExpr{s} <* $strategyQName{recVarName})) + repeat(onceTopDown($StrategyExpr{s})) }; } diff --git a/grammars/silver/rewrite/Strategy.sv b/grammars/silver/rewrite/Strategy.sv index 3514ddd27..7f1d4bade 100644 --- a/grammars/silver/rewrite/Strategy.sv +++ b/grammars/silver/rewrite/Strategy.sv @@ -265,5 +265,5 @@ top::Strategy ::= s::Strategy abstract production outermost top::Strategy ::= s::Strategy { - forwards to topDown(try(s <* outermost(s))); + forwards to repeat(onceTopDown(s)); } From 69a543d742a4a86cb4cb5e730503db7e31ebf030 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Sat, 15 Aug 2020 15:37:41 -0500 Subject: [PATCH 67/78] Fix to antiquotePattern --- grammars/silver/extension/silverconstruction/Syntax.sv | 2 +- grammars/silver/extension/silverconstruction/Translation.sv | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/grammars/silver/extension/silverconstruction/Syntax.sv b/grammars/silver/extension/silverconstruction/Syntax.sv index 929270130..e7021dc71 100644 --- a/grammars/silver/extension/silverconstruction/Syntax.sv +++ b/grammars/silver/extension/silverconstruction/Syntax.sv @@ -72,7 +72,7 @@ top::TypeExpr ::= '$TypeExpr' '{' e::Expr '}' } concrete production antiquotePattern -top::Pattern ::= '$Pattern' '{' e::Pattern '}' +top::Pattern ::= '$Pattern' '{' e::Expr '}' { top.unparse = s"$$Pattern{${e.unparse}}"; forwards to diff --git a/grammars/silver/extension/silverconstruction/Translation.sv b/grammars/silver/extension/silverconstruction/Translation.sv index fc79e4528..a82b53598 100644 --- a/grammars/silver/extension/silverconstruction/Translation.sv +++ b/grammars/silver/extension/silverconstruction/Translation.sv @@ -10,6 +10,7 @@ top::AST ::= prodName::String children::ASTs annotations::NamedASTs ["silver:extension:silverconstruction:antiquoteExpr", "silver:extension:silverconstruction:antiquoteExprInhs", "silver:extension:silverconstruction:antiquoteTypeExpr", + "silver:extension:silverconstruction:antiquotePattern", "silver:extension:silverconstruction:antiquoteQName", "silver:extension:silverconstruction:antiquoteQNameAttrOccur", "silver:extension:silverconstruction:antiquoteName"]; From 671760fd7ce301a341cb5824e733162f69680556 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Thu, 10 Sep 2020 14:55:03 -0500 Subject: [PATCH 68/78] Allow 'production' as shorthand for 'abstract production' (fixes #372) --- grammars/silver/extension/convenience/Productions.sv | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/grammars/silver/extension/convenience/Productions.sv b/grammars/silver/extension/convenience/Productions.sv index ff52288ef..a8e677067 100644 --- a/grammars/silver/extension/convenience/Productions.sv +++ b/grammars/silver/extension/convenience/Productions.sv @@ -2,6 +2,14 @@ grammar silver:extension:convenience; import silver:modification:copper; +-- "production" short for "abstract production" +concrete production productionDclImplicitAbs +top::AGDcl ::= 'production' id::Name ns::ProductionSignature body::ProductionBody +{ + forwards to productionDcl('abstract', $1, id, ns, body, location=top.location); +} + +-- "concrete productions" syntax nonterminal ProductionDclStmts with unparse, location, proddcls, lhsdcl, grammarName; nonterminal ProductionDclStmt with unparse, location, proddcls, lhsdcl, grammarName; From 0cc914eb2945e7a554677c7cc61dd403fea5cc26 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Thu, 10 Sep 2020 18:30:17 -0500 Subject: [PATCH 69/78] Implement 'when ... matches ...' pattern guard syntax (fix #373) --- .../silver/extension/patternmatching/Case.sv | 61 ++++++++++++++----- .../silver/extension/rewriting/Pattern.sv | 32 +++++++++- .../extension/strategyattr/StrategyExpr.sv | 11 +++- 3 files changed, 87 insertions(+), 17 deletions(-) diff --git a/grammars/silver/extension/patternmatching/Case.sv b/grammars/silver/extension/patternmatching/Case.sv index 21ed9da3c..ac8a70c48 100644 --- a/grammars/silver/extension/patternmatching/Case.sv +++ b/grammars/silver/extension/patternmatching/Case.sv @@ -14,6 +14,7 @@ terminal Arrow_kwd '->' lexer classes {SPECOP}; terminal Vbar_kwd '|' lexer classes {SPECOP}; terminal Opt_Vbar_t /\|?/ lexer classes {SPECOP}; -- optional Coq-style vbar. terminal When_kwd 'when' lexer classes {KEYWORD,RESERVED}; +terminal Matches_kwd 'matches' lexer classes {KEYWORD}; -- MR | ... nonterminal MRuleList with location, config, unparse, env, frame, errors, matchRuleList, matchRulePatternSize; @@ -202,15 +203,35 @@ top::MatchRule ::= pt::PatternList 'when' cond::Expr '->' e::Expr pt.patternVarEnv = []; - top.matchRuleList = [matchRule(pt.patternList, just(cond), e, location=top.location)]; + top.matchRuleList = [matchRule(pt.patternList, just(pair(cond, nothing())), e, location=top.location)]; +} + +concrete production matchRuleWhenMatches_c +top::MatchRule ::= pt::PatternList 'when' cond::Expr 'matches' p::Pattern '->' e::Expr +{ + top.unparse = pt.unparse ++ " when " ++ cond.unparse ++ " matches " ++ p.unparse ++ " -> " ++ e.unparse; + top.errors := pt.errors; -- e.errors is examined later, after transformation, as is cond.errors + + top.errors <- + if length(pt.patternList) == top.matchRulePatternSize then [] + else [err(pt.location, "case expression matching against " ++ toString(top.matchRulePatternSize) ++ " values, but this rule has " ++ toString(length(pt.patternList)) ++ " patterns")]; + + pt.patternVarEnv = []; + p.patternVarEnv = pt.patternVars; + + top.matchRuleList = [matchRule(pt.patternList, just(pair(cond, just(p))), e, location=top.location)]; } abstract production matchRule -top::AbstractMatchRule ::= pl::[Decorated Pattern] cond::Maybe e::Expr +top::AbstractMatchRule ::= pl::[Decorated Pattern] cond::Maybe>> e::Expr { top.unparse = implode(", ", map((.unparse), pl)) ++ - (if cond.isJust then " when " ++ cond.fromJust.unparse else "") ++ + case cond of + | just(pair(c, just(p))) -> " when " ++ c.unparse ++ " matches " ++ p.unparse + | just(pair(c, nothing())) -> " when " ++ c.unparse + | nothing() -> "" + end ++ " -> " ++ e.unparse; top.headPattern = head(pl); -- If pl is null, and we're consulted, then we're missing patterns, pretend they're _ @@ -383,15 +404,18 @@ AbstractMatchRule ::= headExpr::Expr headType::Type absRule::AbstractMatchRule -- If it's '_' we do nothing, otherwise, bind away! return case absRule of | matchRule(headPat :: restPat, cond, e) -> - matchRule(restPat, - case headPat.patternVariableName, cond of - | just(pvn), just(c) -> just(makeLet(absRule.location, pvn, headType, headExpr, c)) - | _, _ -> cond + case headPat.patternVariableName of + | just(pvn) -> + matchRule( + restPat, + case cond of + | just(pair(c, p)) -> just(pair(makeLet(absRule.location, pvn, headType, headExpr, c), p)) + | nothing() -> nothing() end, - case headPat.patternVariableName of - | just(pvn) -> makeLet(absRule.location, pvn, headType, headExpr, e) - | nothing() -> e - end, location=absRule.location) + makeLet(absRule.location, pvn, headType, headExpr, e), + location=absRule.location) + | nothing() -> matchRule(restPat, cond, e, location=absRule.location) + end end; } @@ -446,11 +470,18 @@ Expr ::= ml::[AbstractMatchRule] failExpr::Expr { return case ml of - | matchRule(_, just(c), e) :: tl -> + | matchRule(_, just(pair(c, nothing())), e) :: tl -> + Silver_Expr { + if $Expr{c} + then $Expr{e} + else $Expr{buildMatchWhenConditionals(tl, failExpr)} + } + | matchRule(_, just(pair(c, just(p))), e) :: tl -> Silver_Expr { - if $Expr {c} - then $Expr {e} - else $Expr {buildMatchWhenConditionals(tl, failExpr)} + case $Expr{c} of + | $Pattern{p} -> $Expr{e} + | _ -> $Expr{buildMatchWhenConditionals(tl, failExpr)} + end } | matchRule(_, nothing(), e) :: tl -> e | [] -> failExpr diff --git a/grammars/silver/extension/rewriting/Pattern.sv b/grammars/silver/extension/rewriting/Pattern.sv index ee752f15b..cd8274dfb 100644 --- a/grammars/silver/extension/rewriting/Pattern.sv +++ b/grammars/silver/extension/rewriting/Pattern.sv @@ -105,7 +105,37 @@ top::MatchRule ::= pt::PatternList 'when' cond::Expr _ e::Expr top.wrappedMatchRuleList = [matchRule( pt.patternList, - just(hackWrapKey(toString(top.ruleIndex) ++ "_cond", cond, location=e.location)), + just(pair(hackWrapKey(toString(top.ruleIndex) ++ "_cond", cond, location=e.location), nothing())), + hackWrapKey(toString(top.ruleIndex), e, location=e.location), + location=top.location)]; +} + +aspect production matchRuleWhenMatches_c +top::MatchRule ::= pt::PatternList 'when' cond::Expr 'matches' p::Pattern _ e::Expr +{ + top.transform = + require( + pt.firstTransform, + matchASTExpr( + case lookupBy(stringEq, toString(top.ruleIndex) ++ "_cond", top.decRuleExprsIn) of + | just(e) -> e.transform + | nothing() -> error("Failed to find decorated RHS " ++ toString(top.ruleIndex) ++ "_cond") + end, + p.transform, booleanASTExpr(true), booleanASTExpr(false))) <* + rewriteRule( + pt.firstTransform, + case lookupBy(stringEq, toString(top.ruleIndex), top.decRuleExprsIn) of + | just(e) -> e.transform + | nothing() -> error("Failed to find decorated RHS " ++ toString(top.ruleIndex)) + end); + + top.isPolymorphic = head(pt.patternList).patternIsVariable || pt.isPolymorphic; + pt.typesHaveUniversalVars = [true]; + + top.wrappedMatchRuleList = + [matchRule( + pt.patternList, + just(pair(hackWrapKey(toString(top.ruleIndex) ++ "_cond", cond, location=e.location), just(p))), hackWrapKey(toString(top.ruleIndex), e, location=e.location), location=top.location)]; } diff --git a/grammars/silver/extension/strategyattr/StrategyExpr.sv b/grammars/silver/extension/strategyattr/StrategyExpr.sv index e925c5319..f58c3ad77 100644 --- a/grammars/silver/extension/strategyattr/StrategyExpr.sv +++ b/grammars/silver/extension/strategyattr/StrategyExpr.sv @@ -790,7 +790,16 @@ top::MatchRule ::= pt::PatternList 'when' cond::Expr _ e::Expr { top.translation = matchRule( - pt.patternList, just(cond), Silver_Expr { core:just($Expr{e}) }, + pt.patternList, just(pair(cond, nothing())), Silver_Expr { core:just($Expr{e}) }, + location=top.location); +} + +aspect production matchRuleWhenMatches_c +top::MatchRule ::= pt::PatternList 'when' cond::Expr 'matches' p::Pattern _ e::Expr +{ + top.translation = + matchRule( + pt.patternList, just(pair(cond, just(p))), Silver_Expr { core:just($Expr{e}) }, location=top.location); } From f1776e96193e759942ac2b829f739e998a85fafb Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Thu, 10 Sep 2020 19:19:10 -0500 Subject: [PATCH 70/78] Bug fixes to error checking --- .../silver/extension/strategyattr/DclInfo.sv | 6 ++++-- .../silver/extension/strategyattr/Strategy.sv | 6 ++++-- .../extension/strategyattr/StrategyExpr.sv | 17 ++++++++++------- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/grammars/silver/extension/strategyattr/DclInfo.sv b/grammars/silver/extension/strategyattr/DclInfo.sv index be6d92bba..5113958e7 100644 --- a/grammars/silver/extension/strategyattr/DclInfo.sv +++ b/grammars/silver/extension/strategyattr/DclInfo.sv @@ -6,7 +6,7 @@ synthesized attribute containsErrors::Boolean occurs on DclInfo; synthesized attribute liftedStrategyNames::[String] occurs on DclInfo; synthesized attribute givenRecVarNameEnv::[Pair] occurs on DclInfo; synthesized attribute givenRecVarTotalEnv::[Pair] occurs on DclInfo; -attribute totalRefs occurs on DclInfo; +attribute partialRefs, totalRefs occurs on DclInfo; synthesized attribute strategyExpr :: StrategyExpr occurs on DclInfo; aspect default production @@ -18,6 +18,7 @@ top::DclInfo ::= top.liftedStrategyNames = []; top.givenRecVarNameEnv = []; top.givenRecVarTotalEnv = []; + top.partialRefs := []; top.totalRefs := []; top.strategyExpr = error("Internal compiler error: must be defined for all strategy attribute declarations"); } @@ -25,7 +26,7 @@ top::DclInfo ::= abstract production strategyDcl top::DclInfo ::= sg::String sl::Location fn::String isTotal::Boolean tyVar::TyVar - containsErrors::Boolean liftedStrategyNames::[String] givenRecVarNameEnv::[Pair] givenRecVarTotalEnv::[Pair] totalRefs::[String] + containsErrors::Boolean liftedStrategyNames::[String] givenRecVarNameEnv::[Pair] givenRecVarTotalEnv::[Pair] partialRefs::[String] totalRefs::[String] e::StrategyExpr { top.sourceGrammar = sg; @@ -51,6 +52,7 @@ top::DclInfo ::= top.liftedStrategyNames = liftedStrategyNames; top.givenRecVarNameEnv = givenRecVarNameEnv; top.givenRecVarTotalEnv = givenRecVarTotalEnv; + top.partialRefs := partialRefs; top.totalRefs := totalRefs; top.strategyExpr = e; } diff --git a/grammars/silver/extension/strategyattr/Strategy.sv b/grammars/silver/extension/strategyattr/Strategy.sv index c9321f533..495953e8b 100644 --- a/grammars/silver/extension/strategyattr/Strategy.sv +++ b/grammars/silver/extension/strategyattr/Strategy.sv @@ -49,7 +49,7 @@ top::AGDcl ::= isTotal::Boolean a::Name recVarNameEnv::[Pair] rec defaultEnvItem( strategyDcl( top.grammarName, a.location, fName, isTotal, freshTyVar(), - !null(top.errors), map(fst, e.liftedStrategies), recVarNameEnv, recVarTotalEnv, e.totalRefs, e)))], + !null(top.errors), map(fst, e.liftedStrategies), recVarNameEnv, recVarTotalEnv, e.partialRefs, e.totalRefs, e)))], location=top.location), map( \ d::Pair -> @@ -88,7 +88,7 @@ top::AGDcl ::= at::Decorated QName attl::BracketedOptTypeExprs nt::QName nttl::B if null(getOccursDcl(totalAttr, nt.lookupType.fullName, top.env)) then [err(top.location, s"Total strategy attribute ${totalAttr} referenced by ${at.name} does not occur on ${nt.name}")] else [], - at.lookupAttribute.dcl.totalRefs); + nubBy(stringEq, at.lookupAttribute.dcl.totalRefs)); -- TODO: Check that the type parameters of any rules of type nt match nttl @@ -149,7 +149,9 @@ top::ProductionStmt ::= attr::Decorated QName -- forward -> dcl.containsErrors -> dcl.flowEnv -> forward.flowDefs top.errors := if + -- Check for errors in this or inlined strategy expressions that would be reported on the attribute definition attr.lookupAttribute.dcl.containsErrors || + any(map((.containsErrors), flatMap(getAttrDcl(_, top.env), attr.lookupAttribute.dcl.partialRefs))) || -- Check for total strategy ref occurs errors that would already be reported on the occurence (!null(getOccursDcl(attr.lookupAttribute.fullName, top.frame.signature.outputElement.typerep.typeName, top.env)) && any(map(null, map(getOccursDcl(_, top.frame.signature.outputElement.typerep.typeName, top.env), attr.lookupAttribute.dcl.totalRefs)))) diff --git a/grammars/silver/extension/strategyattr/StrategyExpr.sv b/grammars/silver/extension/strategyattr/StrategyExpr.sv index e925c5319..809d77995 100644 --- a/grammars/silver/extension/strategyattr/StrategyExpr.sv +++ b/grammars/silver/extension/strategyattr/StrategyExpr.sv @@ -18,7 +18,8 @@ synthesized attribute attrRefNames::[Maybe]; monoid attribute containsFail::Boolean with false, ||; monoid attribute allId::Boolean with true, &&; monoid attribute freeRecVars::[String] with [], ++; -monoid attribute totalRefs::[String] with [], ++; +monoid attribute partialRefs::[String] with [], ++; -- Includes transitive references +monoid attribute totalRefs::[String] with [], ++; -- Does not include transitive references monoid attribute matchesFrame::Boolean with false, ||; synthesized attribute partialTranslation::Expr; -- Maybe on a @@ -92,13 +93,13 @@ strategy attribute optimize = nonterminal StrategyExpr with config, grammarName, env, location, unparse, errors, frame, compiledGrammars, flowEnv, flowDefs, -- Normal expression stuff - genName, outerAttr, recVarNameEnv, recVarTotalEnv, liftedStrategies, attrRefName, isId, isTotal, freeRecVars, totalRefs, -- Frame-independent attrs + genName, outerAttr, recVarNameEnv, recVarTotalEnv, liftedStrategies, attrRefName, isId, isTotal, freeRecVars, partialRefs, totalRefs, -- Frame-independent attrs partialTranslation, totalTranslation, matchesFrame, -- Frame-dependent attrs inlinedStrategies, genericStep, ntStep, prodStep, simplify, optimize; -- Optimization stuff nonterminal StrategyExprs with config, grammarName, env, unparse, errors, frame, compiledGrammars, flowEnv, flowDefs, -- Normal expression stuff - recVarNameEnv, recVarTotalEnv, givenInputElements, liftedStrategies, attrRefNames, containsFail, allId, freeRecVars, totalRefs, -- Frame-independent attrs + recVarNameEnv, recVarTotalEnv, givenInputElements, liftedStrategies, attrRefNames, containsFail, allId, freeRecVars, partialRefs, totalRefs, -- Frame-independent attrs inlinedStrategies, simplify; -- Optimization stuff flowtype StrategyExpr = @@ -106,7 +107,7 @@ flowtype StrategyExpr = -- Normal expression stuff unparse {}, errors {decorate, frame, compiledGrammars, flowEnv}, flowDefs {decorate, frame, compiledGrammars, flowEnv}, -- Frame-independent attrs - liftedStrategies {decorate}, attrRefName {decorate}, isId {decorate}, isTotal {decorate}, freeRecVars {decorate}, totalRefs {decorate}, + liftedStrategies {decorate}, attrRefName {decorate}, isId {decorate}, isTotal {decorate}, freeRecVars {decorate}, partialRefs {decorate}, totalRefs {decorate}, -- Frame-dependent attrs partialTranslation {decorate, frame}, totalTranslation {decorate, frame}, matchesFrame {decorate, frame}; @@ -116,13 +117,13 @@ flowtype StrategyExprs = unparse {}, errors {decorate, frame, givenInputElements, compiledGrammars, flowEnv}, flowDefs {decorate, frame, compiledGrammars, flowEnv}, -- Frame-independent attrs liftedStrategies {decorate}, attrRefNames {decorate, givenInputElements}, - containsFail {decorate}, allId {decorate}, freeRecVars {decorate}, totalRefs {decorate}; + containsFail {decorate}, allId {decorate}, freeRecVars {decorate}, partialRefs {decorate}, totalRefs {decorate}; propagate errors on StrategyExpr, StrategyExprs excluding partialRef, totalRef; propagate flowDefs on StrategyExpr, StrategyExprs; propagate containsFail, allId on StrategyExprs; propagate freeRecVars on StrategyExpr, StrategyExprs excluding recComb; -propagate totalRefs on StrategyExpr, StrategyExprs; +propagate partialRefs, totalRefs on StrategyExpr, StrategyExprs; propagate simplify on StrategyExprs; propagate prodStep on MRuleList; propagate genericStep, ntStep, prodStep, simplify, optimize on StrategyExpr; @@ -881,6 +882,8 @@ top::StrategyExpr ::= attr::QNameAttrOccur top.attrRefName = just(attr.name); top.matchesFrame := attr.matchesFrame; top.isTotal = false; + top.partialRefs <- [attrDcl.fullName]; + top.partialRefs <- attrDcl.partialRefs; -- Include refs resulting from potential inlining optimizations attr.attrFor = top.frame.signature.outputElement.typerep; @@ -912,7 +915,7 @@ top::StrategyExpr ::= attr::QNameAttrOccur top.attrRefName = just(attr.name); top.matchesFrame := attr.matchesFrame; top.isTotal = true; - top.totalRefs <- [case attr of qNameAttrOccur(a) -> a.lookupAttribute.dcl.fullName end]; + top.totalRefs <- [attrDcl.fullName]; attr.attrFor = top.frame.signature.outputElement.typerep; From 95b6ecaaf5dfbd1ed73418f13a7eda68c6540679 Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Thu, 10 Sep 2020 21:48:59 -0500 Subject: [PATCH 71/78] Bug fix to bug fixes in last commit --- grammars/silver/extension/strategyattr/StrategyExpr.sv | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/grammars/silver/extension/strategyattr/StrategyExpr.sv b/grammars/silver/extension/strategyattr/StrategyExpr.sv index 809d77995..2a6246f00 100644 --- a/grammars/silver/extension/strategyattr/StrategyExpr.sv +++ b/grammars/silver/extension/strategyattr/StrategyExpr.sv @@ -18,8 +18,8 @@ synthesized attribute attrRefNames::[Maybe]; monoid attribute containsFail::Boolean with false, ||; monoid attribute allId::Boolean with true, &&; monoid attribute freeRecVars::[String] with [], ++; -monoid attribute partialRefs::[String] with [], ++; -- Includes transitive references -monoid attribute totalRefs::[String] with [], ++; -- Does not include transitive references +monoid attribute partialRefs::[String] with [], ++; +monoid attribute totalRefs::[String] with [], ++; monoid attribute matchesFrame::Boolean with false, ||; synthesized attribute partialTranslation::Expr; -- Maybe on a @@ -883,7 +883,6 @@ top::StrategyExpr ::= attr::QNameAttrOccur top.matchesFrame := attr.matchesFrame; top.isTotal = false; top.partialRefs <- [attrDcl.fullName]; - top.partialRefs <- attrDcl.partialRefs; -- Include refs resulting from potential inlining optimizations attr.attrFor = top.frame.signature.outputElement.typerep; From a028e9030a58e5f19f312a0fcbe1927509aa1b2a Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Sun, 13 Sep 2020 19:06:39 -0500 Subject: [PATCH 72/78] Update for compatability with changes to Silver testing extension --- test/silver_features/Strategy.sv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/silver_features/Strategy.sv b/test/silver_features/Strategy.sv index bf1e5bea6..8d41ea92b 100644 --- a/test/silver_features/Strategy.sv +++ b/test/silver_features/Strategy.sv @@ -178,6 +178,6 @@ wrongCode "cannot be used as total strategy" { strategy attribute badInhS = badInh; } -wrongCode "is not total" { +warnCode "is not total" { strategy attribute notTotal = rule on SExpr of constSExpr(i) -> constSExpr(i + 1) end; } From 9c31b57c45ad07d67429a1c97913fa7237446d8e Mon Sep 17 00:00:00 2001 From: Lucas Kramer Date: Sun, 13 Sep 2020 23:51:39 -0500 Subject: [PATCH 73/78] Add rewriting demo to Jenkins downstream --- Jenkinsfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 82a6456d8..3a50777ec 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -94,7 +94,8 @@ melt.trynode('silver') { stage("Integration") { // 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/ableJ14", "/melt-umn/meta-ocaml-lite", "/melt-umn/rewriting-lambda-calculus", "/melt-umn/rewriting-regex-matching", + def github_projects = ["/melt-umn/ableC", "/melt-umn/Oberon0", "/melt-umn/ableJ14", "/melt-umn/meta-ocaml-lite", + "/melt-umn/rewriting-lambda-calculus", "/melt-umn/rewriting-regex-matching", "/melt-umn/rewriting-optimization-demo", "/internal/ring"] // Specific other jobs to build def specific_jobs = ["/internal/matlab/master", "/internal/metaII/master", "/internal/simple/master"] From ed72efa5dadbb915066d03c203b7f90916ee6afb Mon Sep 17 00:00:00 2001 From: ~ Date: Wed, 23 Sep 2020 12:01:29 -0500 Subject: [PATCH 74/78] Changing case expression compilation to respect top-to-bottom ordering of patterns --- .../silver/extension/patternmatching/Case.sv | 54 ++++++++++++++++--- 1 file changed, 46 insertions(+), 8 deletions(-) diff --git a/grammars/silver/extension/patternmatching/Case.sv b/grammars/silver/extension/patternmatching/Case.sv index ac8a70c48..73a2809a6 100644 --- a/grammars/silver/extension/patternmatching/Case.sv +++ b/grammars/silver/extension/patternmatching/Case.sv @@ -147,17 +147,55 @@ top::Expr ::= es::[Expr] ml::[AbstractMatchRule] failExpr::Expr retType::Type -- So don't try that! {-- - - Mixed con/var? Partition, and push the vars into the "fail" branch. - - Use a let for it, to avoid code duplication! + - Mixed con/var? Partition into segments and build nested case expressions + - The whole segment partitioning is done in a function rather than grabbing the initial segment + and forwarding to do the rest of the segments (another workable option) for efficiency -} - local freshFailName :: String = "__fail_" ++ toString(genInt()); - local mixedCase :: Expr = - makeLet(top.location, - freshFailName, retType, caseExpr(es, varRules, failExpr, retType, location=top.location), - caseExpr(es, prodRules, baseExpr(qName(top.location, freshFailName), location=top.location), - retType, location=top.location)); + local mixedCase :: Expr = buildMixedCaseMatches(es, ml, failExpr, retType, top.location); +} + + +--Get the initial segment of the match rules which all have the same +--pattern type (constructor or var) and the rest of the rules +function initialSegmentPatternType +Pair<[AbstractMatchRule] [AbstractMatchRule]> ::= lst::[AbstractMatchRule] +{ + return if null(lst) --this probably shouldn't be called with an empty list, but catch it anyway + then pair([], []) + else if null(tail(lst)) + then pair(lst, []) + else if head(lst).isVarMatchRule == head(tail(lst)).isVarMatchRule + then --both have the same type of pattern + let rest::Pair<[AbstractMatchRule] [AbstractMatchRule]> = initialSegmentPatternType(tail(lst)) + in pair(head(lst)::rest.fst, rest.snd) end + else --the first has a different type of pattern than the second + pair([head(lst)], tail(lst)); } +{- + Build the correct match expression when we are mixing constructor + and variable patterns for the first match. We do this by + partitioning the list into segments of only constructor or variable + patterns in order, then putting each segment into its own match. +-} +function buildMixedCaseMatches +Expr ::= es::[Expr] ml::[AbstractMatchRule] failExpr::Expr retType::Type loc::Location +{ + return if null(ml) + then failExpr + else let segments::Pair<[AbstractMatchRule] [AbstractMatchRule]> = + initialSegmentPatternType(ml) + in + caseExpr(es, segments.fst, + buildMixedCaseMatches(es, segments.snd, failExpr, retType, loc), + retType, location=loc) + end; +} + + + + +--Match Rules concrete production mRuleList_one top::MRuleList ::= m::MatchRule { From a3224fa4a721be6320c5ca79e6c20e73af6be07d Mon Sep 17 00:00:00 2001 From: ~ Date: Wed, 23 Sep 2020 12:51:03 -0500 Subject: [PATCH 75/78] Updating tests to reflect top-to-bottom matching ordering --- test/patt/Basics.sv | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/test/patt/Basics.sv b/test/patt/Basics.sv index 7d88ea2ba..deac25c3a 100644 --- a/test/patt/Basics.sv +++ b/test/patt/Basics.sv @@ -48,8 +48,8 @@ equalityTest ( basic3(nothing(), just("w"), nothing()), "w", String, pat_tests ) equalityTest ( basic3(just("w"), nothing(), nothing()), "w", String, pat_tests ) ; equalityTest ( basic3(nothing(), nothing(), just("w")), "w", String, pat_tests ) ; --- TODO: Well, we do left-to-right preferred above all. Haskell preferrs top-to-bottom above all.... -equalityTest ( basic3(just("g"), just("w"), just("h")), "g", String, pat_tests ) ; +-- test top-to-bottom matching +equalityTest ( basic3(just("g"), just("w"), just("h")), "w", String, pat_tests ) ; function basic4 -- using integers Integer ::= p::Pair> @@ -117,7 +117,7 @@ end; } -- once, this test returned 40, just to clarify what we're testing here. -equalityTest ( basic7(mytriple(1,just(20),just(300))), 21, Integer, pat_tests ) ; +equalityTest ( basic7(mytriple(1,just(20),just(300))), 301, Integer, pat_tests ) ; equalityTest ( basic7(mytriple(1,nothing(),just(300))), 301, Integer, pat_tests ) ; function basic8 -- using mixed name/fullnames @@ -136,3 +136,25 @@ equalityTest ( basic8(pair(1,3)), 2, Integer, pat_tests ); equalityTest ( basic8(pair(2,1)), 3, Integer, pat_tests ); equalityTest ( basic8(pair(3,1)), 4, Integer, pat_tests ); + +-- more testing mixing variable and constructor patterns +function basic9 +Integer ::= a::Maybe b::Maybe c::Maybe +{ +return case a, b, c of +| aa, just(bb), nothing() -> bb +| just(aa), bb, cc -> aa +| aa, just(bb), just(cc) -> bb + cc +| nothing(), bb, cc -> 0 +end; +} + +equalityTest ( basic9(just(1), just(2), just(5)), 1, Integer, pat_tests ) ; +equalityTest ( basic9(just(1), just(2), nothing()), 2, Integer, pat_tests ) ; +equalityTest ( basic9(just(1), nothing(), just(5)), 1, Integer, pat_tests ) ; +equalityTest ( basic9(just(1), nothing(), nothing()), 1, Integer, pat_tests ) ; +equalityTest ( basic9(nothing(), just(2), just(5)), 7, Integer, pat_tests ) ; +equalityTest ( basic9(nothing(), just(2), nothing()), 2, Integer, pat_tests ) ; +equalityTest ( basic9(nothing(), nothing(), just(5)), 0, Integer, pat_tests ) ; +equalityTest ( basic9(nothing(), nothing(), nothing()), 0, Integer, pat_tests ) ; + From 5c586030ca2d96d8c754682e273dde05fae7069c Mon Sep 17 00:00:00 2001 From: ~ Date: Wed, 23 Sep 2020 15:00:07 -0500 Subject: [PATCH 76/78] Changing nested ifs to case as Lucas suggested --- .../silver/extension/patternmatching/Case.sv | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/grammars/silver/extension/patternmatching/Case.sv b/grammars/silver/extension/patternmatching/Case.sv index 73a2809a6..1884b15f2 100644 --- a/grammars/silver/extension/patternmatching/Case.sv +++ b/grammars/silver/extension/patternmatching/Case.sv @@ -160,16 +160,18 @@ top::Expr ::= es::[Expr] ml::[AbstractMatchRule] failExpr::Expr retType::Type function initialSegmentPatternType Pair<[AbstractMatchRule] [AbstractMatchRule]> ::= lst::[AbstractMatchRule] { - return if null(lst) --this probably shouldn't be called with an empty list, but catch it anyway - then pair([], []) - else if null(tail(lst)) - then pair(lst, []) - else if head(lst).isVarMatchRule == head(tail(lst)).isVarMatchRule - then --both have the same type of pattern - let rest::Pair<[AbstractMatchRule] [AbstractMatchRule]> = initialSegmentPatternType(tail(lst)) - in pair(head(lst)::rest.fst, rest.snd) end - else --the first has a different type of pattern than the second - pair([head(lst)], tail(lst)); + return case lst of + --this probably shouldn't be called with an empty list, but catch it anyway + | [] -> pair([], []) + | [mr] -> pair([mr], []) + | mr1::mr2::rest -> + if mr1.isVarMatchRule == mr2.isVarMatchRule + then --both have the same type of pattern + let sub::Pair<[AbstractMatchRule] [AbstractMatchRule]> = initialSegmentPatternType(mr2::rest) + in pair(mr1::sub.fst, sub.snd) end + else --the first has a different type of pattern than the second + pair([mr1], mr2::rest) + end; } {- From 1d1a6e42c1133fe93ccd4b9426bb61e4ec40cfac Mon Sep 17 00:00:00 2001 From: ~ Date: Fri, 25 Sep 2020 12:27:51 -0500 Subject: [PATCH 77/78] Check if the errors were something circular --- grammars/silver/extension/patternmatching/Case.sv | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/grammars/silver/extension/patternmatching/Case.sv b/grammars/silver/extension/patternmatching/Case.sv index 1884b15f2..7f3612a5f 100644 --- a/grammars/silver/extension/patternmatching/Case.sv +++ b/grammars/silver/extension/patternmatching/Case.sv @@ -160,7 +160,7 @@ top::Expr ::= es::[Expr] ml::[AbstractMatchRule] failExpr::Expr retType::Type function initialSegmentPatternType Pair<[AbstractMatchRule] [AbstractMatchRule]> ::= lst::[AbstractMatchRule] { - return case lst of + {-return case lst of --this probably shouldn't be called with an empty list, but catch it anyway | [] -> pair([], []) | [mr] -> pair([mr], []) @@ -171,7 +171,17 @@ Pair<[AbstractMatchRule] [AbstractMatchRule]> ::= lst::[AbstractMatchRule] in pair(mr1::sub.fst, sub.snd) end else --the first has a different type of pattern than the second pair([mr1], mr2::rest) - end; + end;-} + return if null(lst) --this probably shouldn't be called with an empty list, but catch it anyway + then pair([], []) + else if null(tail(lst)) + then pair(lst, []) + else if head(lst).isVarMatchRule == head(tail(lst)).isVarMatchRule + then --both have the same type of pattern + let rest::Pair<[AbstractMatchRule] [AbstractMatchRule]> = initialSegmentPatternType(tail(lst)) + in pair(head(lst)::rest.fst, rest.snd) end + else --the first has a different type of pattern than the second + pair([head(lst)], tail(lst)); } {- From 27fbc65964ec2088baf889a04bbc8e2bf0000cd3 Mon Sep 17 00:00:00 2001 From: ~ Date: Sat, 26 Sep 2020 10:49:00 -0500 Subject: [PATCH 78/78] Putting the next segment's case in a let to see if that helps --- .../silver/extension/patternmatching/Case.sv | 22 ++++++------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/grammars/silver/extension/patternmatching/Case.sv b/grammars/silver/extension/patternmatching/Case.sv index 7f3612a5f..69401e8c6 100644 --- a/grammars/silver/extension/patternmatching/Case.sv +++ b/grammars/silver/extension/patternmatching/Case.sv @@ -160,7 +160,7 @@ top::Expr ::= es::[Expr] ml::[AbstractMatchRule] failExpr::Expr retType::Type function initialSegmentPatternType Pair<[AbstractMatchRule] [AbstractMatchRule]> ::= lst::[AbstractMatchRule] { - {-return case lst of + return case lst of --this probably shouldn't be called with an empty list, but catch it anyway | [] -> pair([], []) | [mr] -> pair([mr], []) @@ -171,17 +171,7 @@ Pair<[AbstractMatchRule] [AbstractMatchRule]> ::= lst::[AbstractMatchRule] in pair(mr1::sub.fst, sub.snd) end else --the first has a different type of pattern than the second pair([mr1], mr2::rest) - end;-} - return if null(lst) --this probably shouldn't be called with an empty list, but catch it anyway - then pair([], []) - else if null(tail(lst)) - then pair(lst, []) - else if head(lst).isVarMatchRule == head(tail(lst)).isVarMatchRule - then --both have the same type of pattern - let rest::Pair<[AbstractMatchRule] [AbstractMatchRule]> = initialSegmentPatternType(tail(lst)) - in pair(head(lst)::rest.fst, rest.snd) end - else --the first has a different type of pattern than the second - pair([head(lst)], tail(lst)); + end; } {- @@ -193,14 +183,16 @@ Pair<[AbstractMatchRule] [AbstractMatchRule]> ::= lst::[AbstractMatchRule] function buildMixedCaseMatches Expr ::= es::[Expr] ml::[AbstractMatchRule] failExpr::Expr retType::Type loc::Location { + local freshFailName :: String = "__fail_" ++ toString(genInt()); return if null(ml) then failExpr else let segments::Pair<[AbstractMatchRule] [AbstractMatchRule]> = initialSegmentPatternType(ml) in - caseExpr(es, segments.fst, - buildMixedCaseMatches(es, segments.snd, failExpr, retType, loc), - retType, location=loc) + makeLet(loc, freshFailName, retType, + buildMixedCaseMatches(es, segments.snd, failExpr, retType, loc), + caseExpr(es, segments.fst, baseExpr(qName(loc, freshFailName), location=loc), + retType, location=loc)) end; }