2
2
3
3
import static nl .utwente .groove .grammar .model .ResourceKind .HOST ;
4
4
import static nl .utwente .groove .grammar .model .ResourceKind .PROPERTIES ;
5
- import static nl .utwente .groove .grammar .model .ResourceKind .TYPE ;
6
5
7
- import java .util .HashMap ;
8
- import java .util .Map ;
6
+ import java .util .ArrayList ;
7
+ import java .util .Collections ;
8
+ import java .util .HashSet ;
9
+ import java .util .List ;
10
+ import java .util .Set ;
9
11
10
12
import org .eclipse .jdt .annotation .NonNull ;
13
+ import org .eclipse .jdt .annotation .NonNullByDefault ;
14
+ import org .eclipse .jdt .annotation .Nullable ;
11
15
12
- import nl .utwente .groove .grammar .QualName ;
13
16
import nl .utwente .groove .grammar .aspect .AspectGraph ;
14
17
import nl .utwente .groove .grammar .host .HostGraph ;
15
- import nl .utwente .groove .util .parse .FormatError ;
18
+ import nl .utwente .groove .grammar .type .TypeLabel ;
19
+ import nl .utwente .groove .util .Factory ;
16
20
import nl .utwente .groove .util .parse .FormatErrorSet ;
17
21
import nl .utwente .groove .util .parse .FormatException ;
18
22
19
- /** Class to store the models that are used to compose the type graph. */
23
+ /** Class compute the composed start graph. */
24
+ @ NonNullByDefault
20
25
public class CompositeHostModel extends ResourceModel <HostGraph > {
21
26
/**
22
27
* Constructs a composite type model
23
28
* @param grammar the underlying graph grammar
24
29
*/
25
- CompositeHostModel (@ NonNull GrammarModel grammar ) {
26
- super (grammar , TYPE );
30
+ CompositeHostModel (GrammarModel grammar ) {
31
+ this (grammar , null );
32
+ }
33
+
34
+ /**
35
+ * Constructs a composite type model from a single aspect graph.
36
+ * @param grammar the underlying graph grammar
37
+ * @param source the explicit source aspect graph; if {@code null}, the source
38
+ * is implicit and derived from the active host graphs of the grammar.
39
+ */
40
+ CompositeHostModel (GrammarModel grammar , @ Nullable AspectGraph source ) {
41
+ super (grammar , HOST );
27
42
setDependencies (PROPERTIES );
43
+ this .implicit = source == null ;
44
+ this .hostModels = this .implicit
45
+ ? null // to be initialised later
46
+ : Collections .<HostModel >singletonList (new HostModel (grammar , source ));
28
47
}
29
48
30
49
@ Override
@@ -34,52 +53,144 @@ public class CompositeHostModel extends ResourceModel<HostGraph> {
34
53
return result ;
35
54
}
36
55
56
+ /** Indicates if this composite model is implicit, i.e., derived from the active host graphs
57
+ * in the grammar.
58
+ */
59
+ public boolean isImplicit () {
60
+ return this .implicit ;
61
+ }
62
+
63
+ private final boolean implicit ;
64
+
37
65
@ Override
38
- public Object getSource () {
39
- return null ;
66
+ public @ Nullable AspectGraph getSource () {
67
+ return this . source . get () ;
40
68
}
41
69
70
+ /** The (lazily created) source aspect graph. */
71
+ private final Factory <@ Nullable AspectGraph > source = Factory .lazy (() -> {
72
+ AspectGraph result = null ;
73
+ var hostModels = getHostModels ();
74
+ if (hostModels .size () == 1 ) {
75
+ result = hostModels .getFirst ().getSource ();
76
+ } else if (hostModels .size () > 1 ) {
77
+ result = AspectGraph .mergeGraphs (getGrammar ().getActiveGraphs (HOST ));
78
+ }
79
+ return result ;
80
+ });
81
+
82
+ /** Returns the set of type labels in the combined source graphs. */
83
+ public Set <TypeLabel > getTypeLabels () {
84
+ return this .typeLabels .get ();
85
+ }
86
+
87
+ /**
88
+ * Returns a mapping from the nodes in the model source to the corresponding
89
+ * nodes in the resource that is constructed from it.
90
+ * This method should only be called if the model contains no errors.
91
+ * @return the mapping from source graph to resource elements
92
+ */
93
+ public HostModelMap getMap () {
94
+ var model = getCombinedModel ();
95
+ assert model != null ;
96
+ return model .getMap ();
97
+ }
98
+
99
+ private final Factory <Set <TypeLabel >> typeLabels = Factory .lazy (() -> {
100
+ var result = new HashSet <TypeLabel >();
101
+ for (var model : getHostModels ()) {
102
+ result .addAll (model .getTypeLabels ());
103
+ }
104
+ return result ;
105
+ });
106
+
42
107
@ Override
43
108
public String getName () {
44
- return "Composite host graph" ;
109
+ var source = getSource ();
110
+ return source == null
111
+ ? ""
112
+ : source .getName ();
45
113
}
46
114
47
- /** Indicates if this model is composed of more than one underlying host model. */
48
- public boolean isMultiple () {
49
- return getGrammar ().getActiveNames (HOST ).size () > 1 ;
115
+ @ Override
116
+ void notifyWillRebuild () {
117
+ super .notifyWillRebuild ();
118
+ if (isImplicit ()) {
119
+ this .hostModels = null ;
120
+ this .combinedModel .reset ();
121
+ this .source .reset ();
122
+ this .typeLabels .reset ();
123
+ }
50
124
}
51
125
52
126
@ Override
53
127
HostGraph compute () throws FormatException {
54
- var hostModelMap = computeHostModelMap ();
55
- if (hostModelMap .isEmpty ()) {
128
+ HostGraph result = null ;
129
+ var hostModels = getHostModels ();
130
+ FormatErrorSet errors = new FormatErrorSet ();
131
+ for (var model : hostModels ) {
132
+ for (var error : model .getErrors ()) {
133
+ errors .add ("Error in graph '%s': %s" , model .getName (), error , model .getSource ());
134
+ }
135
+ }
136
+ errors .throwException ();
137
+ var combinedModel = getCombinedModel ();
138
+ if (combinedModel == null ) {
56
139
throw new FormatException ("No active start graph" );
57
140
} else {
58
- AspectGraph startGraph = AspectGraph .mergeGraphs (getGrammar ().getActiveGraphs (HOST ));
59
- return new HostModel (getGrammar (), startGraph ).compute ();
141
+ try {
142
+ result = combinedModel .toHost ();
143
+ } catch (FormatException exc ) {
144
+ for (var error : exc .getErrors ()) {
145
+ errors .add ("Error in composite host graph: %s" , error );
146
+ }
147
+ errors .throwException ();
148
+ }
60
149
}
150
+ assert result != null ;
151
+ return result ;
61
152
}
62
153
154
+ /** Returns the combined host model.
155
+ * This is either {@code null} of there is no active host model, or the singular host model, or a new
156
+ * host model obtained from the merged sources of the active host models, if there are multiple.
157
+ */
158
+ private @ Nullable HostModel getCombinedModel () {
159
+ return this .combinedModel .get ();
160
+ }
161
+
162
+ /** The combined host model.
163
+ * @see #getCombinedModel()
164
+ */
165
+ private final Factory <@ Nullable HostModel > combinedModel = Factory .lazy (() -> {
166
+ HostModel result = null ;
167
+ var hostModels = getHostModels ();
168
+ if (hostModels .size () == 1 ) {
169
+ result = hostModels .getFirst ();
170
+ } else {
171
+ result = new HostModel (getGrammar (), getSource ());
172
+
173
+ }
174
+ return result ;
175
+ });
176
+
63
177
/**
64
- * Computes the mapping from names to active host models.
65
- * @throws FormatException if there are format errors in the active type models
178
+ * Returns the list of active host models.
66
179
*/
67
- private Map <QualName ,HostModel > computeHostModelMap () throws FormatException {
68
- FormatErrorSet errors = new FormatErrorSet ();
69
- Map <QualName ,HostModel > result = new HashMap <>();
70
- for (var activeHostName : getGrammar ().getActiveNames (HOST )) {
71
- ResourceModel <?> hostModel = getGrammar ().getResource (HOST , activeHostName );
72
- result .put (activeHostName , (HostModel ) hostModel );
73
- for (FormatError error : hostModel .getErrors ()) {
74
- errors
75
- .add ("Error in host graph '%s': %s" , activeHostName , error ,
76
- hostModel .getSource ());
180
+ private List <HostModel > getHostModels () {
181
+ var result = this .hostModels ;
182
+ if (result == null ) {
183
+ result = new ArrayList <>();
184
+ for (var name : getGrammar ().getActiveNames (HOST )) {
185
+ var model = getGrammar ().getResource (HOST , name );
186
+ result .add ((HostModel ) model );
77
187
}
78
188
}
79
- errors .throwException ();
80
189
return result ;
81
190
}
82
191
192
+ private @ Nullable List <HostModel > hostModels ;
193
+
83
194
/** Fixed name for the composite host model. */
84
195
static public final String NAME = "composite-host" ;
85
196
}
0 commit comments