/
Functor.sv
129 lines (113 loc) · 4.19 KB
/
Functor.sv
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
grammar silver:compiler:extension:autoattr;
concrete production functorAttributeDcl
top::AGDcl ::= 'functor' 'attribute' a::Name ';'
{
top.unparse = "functor attribute " ++ a.unparse ++ ";";
top.moduleNames := [];
production attribute fName :: String;
fName = top.grammarName ++ ":" ++ a.name;
top.errors <-
if length(getAttrDclAll(fName, top.env)) > 1
then [errFromOrigin(a, "Attribute '" ++ fName ++ "' is already bound.")]
else [];
forwards to
defsAGDcl(
[attrDef(defaultEnvItem(functorDcl(fName, sourceGrammar=top.grammarName, sourceLocation=a.nameLoc)))]);
}
abstract production functorAttributionDcl
top::AGDcl ::= at::Decorated! QName attl::BracketedOptTypeExprs nt::QName nttl::BracketedOptTypeExprs
{
undecorates to attributionDcl('attribute', at, attl, 'occurs', 'on', nt, nttl, ';');
top.unparse = "attribute " ++ at.unparse ++ attl.unparse ++ " occurs on " ++ nt.unparse ++ nttl.unparse ++ ";";
top.moduleNames := [];
propagate grammarName, env, flowEnv;
forwards to
defaultAttributionDcl(
at,
if length(attl.types) > 0
then attl
else
botlSome(
bTypeList(
'<',
typeListSingle(
case nttl of
| botlSome(tl) ->
appTypeExpr(
nominalTypeExpr(nt.qNameType),
tl)
| botlNone() -> nominalTypeExpr(nt.qNameType)
end),
'>')),
nt, nttl);
}
{--
- Propagate a functor attribute on the enclosing production
- @param attr The name of the attribute to propagate
-}
abstract production propagateFunctor
top::ProductionStmt ::= attr::Decorated! QName
{
undecorates to propagateOneAttr(attr);
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 inputs :: [Expr] =
map(makeArg(top.env, attr, _), top.frame.signature.inputElements);
local annotations :: [Pair<String Expr>] =
map(
makeAnnoArg(top.frame.signature.outputElement.elementName, _),
top.frame.signature.namedInputElements);
-- Construct an attribute def and call with the generated arguments
forwards to
attributeDef(
concreteDefLHS(qName(top.frame.signature.outputElement.elementName)),
'.',
qNameAttrOccur(new(attr)),
'=',
mkFullFunctionInvocation(baseExpr(qName(top.frame.fullName)), inputs, annotations),
';');
}
{--
- Generates the expression we should use for an argument
- @param env The environment
- @param attrName The name of the attribute being propagated
- @param input The NamedSignatureElement being propagated
- @return Either this the child, or accessing `attrName` on the child
-}
function makeArg
Expr ::= env::Env attrName::Decorated QName input::NamedSignatureElement
{
local at::QName = qName(input.elementName);
at.env = env;
-- Check if the attribute occurs on the first child
local attrOccursOnHead :: Boolean =
!null(getOccursDcl(attrName.lookupAttribute.dcl.fullName, input.typerep.typeName, env));
local validTypeHead :: Boolean =
(isDecorable(input.typerep, env) || input.typerep.isNonterminal) && !input.typerep.isUniqueDecorated;
return
if validTypeHead && attrOccursOnHead
then access(
baseExpr(at), '.',
qNameAttrOccur(new(attrName)))
else baseExpr(at);
}
{--
- Generates the list of AnnoExprs used in calling the constructor
- @param baseName The name of the parent from the signature
- @param input The NamedSignatureElement for an annotation
- @return A list of AnnoExprs to be used to build the named arguments
-}
function makeAnnoArg
Pair<String Expr> ::= 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.
local annoName :: String = last(explode(":", input.elementName));
return
(annoName,
access(
baseExpr(qName(baseName)), '.',
qNameAttrOccur(qName(annoName))));
}