Backend.jadd 74 KB
Newer Older
1
aspect BackendAbstractGrammar {
2

Johannes Mey's avatar
Johannes Mey committed
3
  public static String ASTNode.listClass = "ArrayList";
4
5
  public static String ASTNode.jastAddListType = "List";

6
7
  public static boolean ASTNode.resolverHelper = false;
  public static boolean ASTNode.serializer = false;
8
9
  public static boolean ASTNode.jsonPointer = false;
  public static boolean ASTNode.manualReferences = false;
10
  public static boolean ASTNode.useJastAddNames = false;
Johannes Mey's avatar
Johannes Mey committed
11
12
13
14
15
16
17
18
19
20
21
22
23

  public String Program.generateAbstractGrammar() {
    StringBuilder sb = new StringBuilder();
    generateAbstractGrammar(sb);
    return sb.toString();
  }

  public void Program.generateAbstractGrammar(StringBuilder sb) {
    for (TypeDecl td: getTypeDecls()) {
      td.generateAbstractGrammar(sb);
    }
  }

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
  public void TypeDecl.generateUnresolvedClass(StringBuilder sb) {
    if (getAbstract()) {
      sb.append(ind(1) + "abstract ");
    } else {
      sb.append(ind(1));
    }
    sb.append("class " + "Unresolved$" + getID() + " extends " + getID() + "  implements Unresolved$Node {\n");

    sb.append(ind(2) + "private String unresolved$Token;\n");
    sb.append(ind(2) + "public String getUnresolved$Token() {\n");
    sb.append(ind(3) + "return unresolved$Token;\n");
    sb.append(ind(2) + "}\n");
    sb.append(ind(2) + "void setUnresolved$Token(String token) {\n");
    sb.append(ind(3) + "this.unresolved$Token = token;\n");
    sb.append(ind(2) + "}\n");

    sb.append(ind(2) + "private boolean unresolved$ResolveOpposite;\n");
    sb.append(ind(2) + "public boolean getUnresolved$ResolveOpposite() {\n");
    sb.append(ind(3) + "return unresolved$ResolveOpposite;\n");
    sb.append(ind(2) + "}\n");
    sb.append(ind(2) + "void setUnresolved$ResolveOpposite(boolean resolveOpposite) {\n");
    sb.append(ind(3) + "this.unresolved$ResolveOpposite = resolveOpposite;\n");
    sb.append(ind(2) + "}\n");

    sb.append(ind(1) + "}\n");

    sb.append(ind(1) + "Unresolved$Node " + getID() + ".as$Unresolved() {\n");
    sb.append(ind(2) + "return null;\n");
    sb.append(ind(1) + "}\n");
    sb.append(ind(1) + "Unresolved$Node Unresolved$" + getID() + ".as$Unresolved() {\n");
    sb.append(ind(2) + "return this;\n");
    sb.append(ind(1) + "}\n");

    sb.append(ind(1) + "boolean " + getID() + ".is$Unresolved() {\n");
    sb.append(ind(2) + "return false;\n");
    sb.append(ind(1) + "}\n");
    sb.append(ind(1) + "boolean Unresolved$" + getID() + ".is$Unresolved() {\n");
    sb.append(ind(2) + "return true;\n");
    sb.append(ind(1) + "}\n");
  }

Johannes Mey's avatar
Johannes Mey committed
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
  public void TypeDecl.generateAbstractGrammar(StringBuilder sb) {
    if (getAbstract()) {
      sb.append("abstract ");
    }
    sb.append(getID());
    if (hasSuper()) {
      sb.append(" : " + getSuper());
    }

    if (getNumComponent() > 0 || relationComponents().size() > 0) {
      sb.append(" ::=");
    }
    for (Component c: getComponents()) {
      sb.append(" ");
      sb.append(c.generateAbstractGrammar());
    }
    for (RelationComponent c: relationComponents()) {
      sb.append(" ");
      sb.append(c.generateAbstractGrammar());
    }

    sb.append(";\n");
  }

  public String Component.generateAbstractGrammar() {
    if (getID().equals(getTypeUse().toString())) {
      return getTypeUse().toString();
    } else {
      return getID() + ":" + getTypeUse();
    }
  }
  public String ListComponent.generateAbstractGrammar() {
    return super.generateAbstractGrammar() + "*";
  }
  public String OptComponent.generateAbstractGrammar() {
    return "[" + super.generateAbstractGrammar() + "]";
  }
  public String NTAComponent.generateAbstractGrammar() {
    return "/" + super.generateAbstractGrammar() + "/";
  }
Johannes Mey's avatar
Johannes Mey committed
105
106
107
108
109
110
  public String NTAListComponent.generateAbstractGrammar() {
    return "/" + super.generateAbstractGrammar() + "*/";
  }
  public String NTAOptComponent.generateAbstractGrammar() {
    return "/[" + super.generateAbstractGrammar() + "]/";
  }
Johannes Mey's avatar
Johannes Mey committed
111
112
113
114
115
116
117
118
119
120
121
122
123
124
  public String TokenComponent.generateAbstractGrammar() {
    return "<" + getID() + ":" + getTypeUse() + ">";
  }

  public String RelationComponent.generateAbstractGrammar() {
    return "<" + getImplAttributeName() + ":" + ofTypeDecl() + ">";
  }
  public String ManyRelationComponent.generateAbstractGrammar() {
    return "<" + getImplAttributeName() + ":" + ASTNode.listClass + "<" + ofTypeDecl() + ">>";
  }

  public String RelationComponent.getImplAttributeName() {
    return "_impl_" + getID();
  }
125
126
127
128
129
130
131
132
133
134

  public String RelationComponent.getImplAttributeField() {
    //  tt.bind("TypeInSignature", ASTNode.convTypeNameToSignature(type()));
    return "token" + ofTypeDecl() + "__impl_" + getID();
  }

  public String ManyRelationComponent.getImplAttributeField() {
    //  tt.bind("TypeInSignature", ASTNode.convTypeNameToSignature(type()));
    return "token" + listClass + "_" + ofTypeDecl() + "___impl_" + getID();
  }
135
136
137
}

aspect BackendAspect {
Johannes Mey's avatar
Johannes Mey committed
138
139
140
141
142
143
144
145
146
  public String Program.generateAspect() {
    StringBuilder sb = new StringBuilder();
    generateAspect(sb);
    return sb.toString();
  }

  public void Program.generateAspect(StringBuilder sb) {
    sb.append("import java.util.ArrayList;\n");
    sb.append("import java.util.Collections;\n");
147
148
    sb.append("import java.time.Instant;\n");
    sb.append("import java.time.Period;\n");
Johannes Mey's avatar
Johannes Mey committed
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
    sb.append("aspect RelAstAPI {\n");

    for (TypeDecl td: getTypeDecls()) {
      if (td.needsConstructor()) {
        td.generateConstructor(sb);
      }
    }
    for (Relation r: getRelations()) {
      r.generateAPI(sb);
    }

    generateLowerBoundCheck(sb);

    sb.append(ind(1) + "public static void ASTNode.assertNotNull(Object obj) {\n");
    sb.append(ind(2) + "if (obj == null) {\n");
    sb.append(ind(3) + "throw new NullPointerException();\n");
    sb.append(ind(2) + "}\n");
    sb.append(ind(1) + "}\n");
    sb.append("}\n");
  }

  public void TypeDecl.generateConstructor(StringBuilder sb) {
    sb.append(ind(1) + "public " + getID() + "." + getID() + "(");
    int i = 0;
    for (Component c: componentsTransitive()) {
      sb.append(c.constructorParameter());
      if (++i < componentsTransitive().size()) {
        sb.append(", ");
      }
    }
    sb.append(") {\n");
    for (Component c: componentsTransitive()) {
      sb.append(ind(2) + c.constructorSetMethod() + "(" + c.getID() + ");\n");
    }
    sb.append(ind(1) + "}\n");
  }
  public String Component.constructorParameter() {
    return getTypeUse() + " " + getID();
  }
  public String ListComponent.constructorParameter() {
189
    return ASTNode.jastAddListType + "<" + getTypeUse() + "> " + getID();
Johannes Mey's avatar
Johannes Mey committed
190
191
192
193
194
195
196
197
198
199
200
201
202
  }
  public String OptComponent.constructorParameter() {
    return "Opt<" + getTypeUse() + "> " + getID();
  }
  public String Component.constructorSetMethod() {
    return "set" + getID();
  }
  public String ListComponent.constructorSetMethod() {
    return "set" + getID() + "List";
  }
  public String OptComponent.constructorSetMethod() {
    return "set" + getID() + "Opt";
  }
203
204
205
}

aspect BackendAPI {
Johannes Mey's avatar
Johannes Mey committed
206
207
208
209
210
211
  public void Relation.generateAPI(StringBuilder sb) {
    sb.append(ind(1) + "// " + prettyPrint() + "\n");
    getDirection().generateAPI(sb);
    sb.append("\n");
  }
  public abstract void Direction.generateAPI(StringBuilder sb);
212
213


Johannes Mey's avatar
Johannes Mey committed
214
215
216
  inh Relation Direction.relation();
  eq Relation.getChild().relation() = this;
  eq Program.getChild().relation() = null;
217

Johannes Mey's avatar
Johannes Mey committed
218
219
220
  public String RelationComponent.nameCapitalized() {
    return name().substring(0,1).toUpperCase() + name().substring(1);
  }
221
}
222

223
aspect BackendDirectedAPI {
Johannes Mey's avatar
Johannes Mey committed
224
225
226
  public void RightDirection.generateAPI(StringBuilder sb) {
    relation().getLeft().generateDirectedAPI(sb);
  }
René Schöne's avatar
René Schöne committed
227
228
229
  public void LeftDirection.generateAPI(StringBuilder sb) {
    relation().getRight().generateDirectedAPI(sb);
  }
Johannes Mey's avatar
Johannes Mey committed
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244

  public abstract void RelationComponent.generateDirectedAPI(StringBuilder sb);
  public void OneRelationComponent.generateDirectedAPI(StringBuilder sb) {
    generateDirectedZeroOneAPI(sb, false);
  }
  public void OptionalRelationComponent.generateDirectedAPI(StringBuilder sb) {
    generateDirectedZeroOneAPI(sb, true);

    generateExtraOptAPI(sb);
  }
  public void RelationComponent.generateDirectedZeroOneAPI(StringBuilder sb, boolean optional) {
    // Get
    generateGetOne(sb);

    // Set
245
    sb.append(ind(1) + "public " + getTypeUse().decl() + " " + getTypeUse().decl());
Johannes Mey's avatar
Johannes Mey committed
246
247
248
249
250
    sb.append(".set" + nameCapitalized() + "(" + ofTypeDecl() + " o) {\n");
    if (!optional) {
      sb.append(ind(2) + "assertNotNull(o);\n");
    }
    sb.append(ind(2) + "set" + getImplAttributeName() + "(o);\n");
251
    sb.append(ind(2) + "return this;\n");
Johannes Mey's avatar
Johannes Mey committed
252
253
254
255
256
    sb.append(ind(1) + "}\n");
  }

  public void ManyRelationComponent.generateDirectedAPI(StringBuilder sb) {
    // Get
257
    sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + getTypeUse().decl() + ".");
258
259
260
261
262
    if (useJastAddNames) {
      // getXs
      sb.append("get" + nameCapitalized() + "s() {\n");
      sb.append(ind(2) + "return get" + nameCapitalized() + "List();\n");
      sb.append(ind(1) + "}\n");
263

264
      // getXList
265
      sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + getTypeUse().decl());
266
267
268
269
      sb.append(".get" + nameCapitalized() + "List() {\n");
    } else {
      sb.append(name() + "() {\n");
    }
270
271
    sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> l = get" + getImplAttributeName() + "();\n");
    // resolve the entire list
272
    if (resolverHelper | serializer) {
273
      sb.append(ind(2) + "if (l != null) {\n");
274
        sb.append(ind(3) + "boolean changed = false;\n");
275
276
        sb.append(ind(3) + "for (int i = 0; i < l.size(); i++) {\n");
          sb.append(ind(4) + ofTypeDecl() + " element = l.get(i);\n");
277
          sb.append(ind(4) + "if (element.is$Unresolved()) {\n");
278
            sb.append(ind(5) + "changed = true;\n");
279
            sb.append(ind(5) + ofTypeDecl() + " resolvedElement = resolve" + nameCapitalized() + "ByToken(element.as$Unresolved().getUnresolved$Token(), i);\n");
280
281
282
            sb.append(ind(5) + "l.set(i, resolvedElement);\n");
          sb.append(ind(4) + "}\n");
        sb.append(ind(3) + "}\n");
283
284
285
        sb.append(ind(3) + "if (changed) {\n");
          sb.append(ind(4) + "set" + getImplAttributeName() + "(l);\n");
        sb.append(ind(3) + "}\n");
286
287
288
289
      sb.append(ind(2) + "}\n");
    }
    sb.append(ind(2) + "return l != null ? Collections.unmodifiableList(l) : Collections.emptyList();\n");
    sb.append(ind(1) + "}\n");
Johannes Mey's avatar
Johannes Mey committed
290
291

    // Add
292
    sb.append(ind(1) + "public void " + getTypeUse().decl() + ".add");
293
294
295
    if (!useJastAddNames) {
      sb.append("To");
    }
Johannes Mey's avatar
Johannes Mey committed
296
297
    sb.append(nameCapitalized() + "(" + ofTypeDecl() + " o) {\n");
    sb.append(ind(2) + "assertNotNull(o);\n");
298
    sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n");
Johannes Mey's avatar
Johannes Mey committed
299
300
301
302
303
304
305
    sb.append(ind(2) + "if (list == null) {\n");
    sb.append(ind(3) + "list = new " + ASTNode.listClass + "<>();\n");
    sb.append(ind(2) + "}\n");
    sb.append(ind(2) + "list.add(o);\n");
    sb.append(ind(2) + "set" + getImplAttributeName() + "(list);\n");
    sb.append(ind(1) + "}\n");

306
    // Insert / add at specific position
307
    sb.append(ind(1) + "public void " + getTypeUse().decl() + ".add");
308
309
310
311
    if (!useJastAddNames) {
      sb.append("To");
    }
    sb.append(nameCapitalized() + "(int index, " + ofTypeDecl() + " o) {\n");
312
    sb.append(ind(2) + "assertNotNull(o);\n");
313
    sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n");
314
315
316
317
318
319
320
    sb.append(ind(2) + "if (list == null) {\n");
    sb.append(ind(3) + "list = new " + ASTNode.listClass + "<>();\n");
    sb.append(ind(2) + "}\n");
    sb.append(ind(2) + "list.add(index, o);\n");
    sb.append(ind(2) + "set" + getImplAttributeName() + "(list);\n");
    sb.append(ind(1) + "}\n");

Johannes Mey's avatar
Johannes Mey committed
321
    // Remove
322
    sb.append(ind(1) + "public void " + getTypeUse().decl() + ".remove");
323
324
325
    if (!useJastAddNames) {
      sb.append("From");
    }
Johannes Mey's avatar
Johannes Mey committed
326
327
    sb.append(nameCapitalized() + "(" + ofTypeDecl() + " o) {\n");
    sb.append(ind(2) + "assertNotNull(o);\n");
328
    sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n");
Johannes Mey's avatar
Johannes Mey committed
329
330
331
332
333
334
335
    sb.append(ind(2) + "if (list != null && list.remove(o)) {\n");
    sb.append(ind(3) + "set" + getImplAttributeName() + "(list);\n");
    sb.append(ind(2) + "}\n");
    sb.append(ind(1) + "}\n");
  }

  public void RelationComponent.generateGetOne(StringBuilder sb) {
336
    sb.append(ind(1) + "public " + ofTypeDecl() + " " + getTypeUse().decl() + ".");
337
338
339
340
341
342
    if (useJastAddNames) {
      sb.append("get" + nameCapitalized());
    } else {
      sb.append(name());
    }
    sb.append("() {\n");
343
    if (resolverHelper | serializer) {
344
345
346
      sb.append(ind(2) + "if (" + getImplAttributeField() + " != null && " + getImplAttributeField() + ".is$Unresolved()) {\n");
        sb.append(ind(3) + "if (" + getImplAttributeField() + ".as$Unresolved().getUnresolved$ResolveOpposite()) {\n");
          sb.append(ind(4) + "set" + nameCapitalized() + "(resolve" + nameCapitalized() + "ByToken(" + getImplAttributeField() + ".as$Unresolved().getUnresolved$Token()));\n");
347
        sb.append(ind(3) + "} else {\n");
348
          sb.append(ind(4) + "set" + getImplAttributeName() + "(resolve" + nameCapitalized() + "ByToken(" + getImplAttributeField() + ".as$Unresolved().getUnresolved$Token()));\n");
349
        sb.append(ind(3) + "}\n");
350
351
      sb.append(ind(2) + "}\n");
    }
Johannes Mey's avatar
Johannes Mey committed
352
353
354
355
356
357
    sb.append(ind(2) + "return get" + getImplAttributeName() + "();\n");
    sb.append(ind(1) + "}\n");
  }

  public void RelationComponent.generateExtraOptAPI(StringBuilder sb) {
    // has
358
    sb.append(ind(1) + "public boolean " + getTypeUse().decl());
Johannes Mey's avatar
Johannes Mey committed
359
    sb.append(".has" + nameCapitalized() + "() {\n");
360
361
362
363
364
365
366
    sb.append(ind(2) + "return ");
    if (useJastAddNames) {
      sb.append("get" + nameCapitalized());
    } else {
      sb.append(name());
    }
    sb.append("() != null;\n");
Johannes Mey's avatar
Johannes Mey committed
367
368
369
    sb.append(ind(1) + "}\n");

    // clear
370
    sb.append(ind(1) + "public void " + getTypeUse().decl());
Johannes Mey's avatar
Johannes Mey committed
371
372
373
374
    sb.append(".clear" + nameCapitalized() + "() {\n");
    sb.append(ind(2) + "set" + nameCapitalized() + "(null);\n");
    sb.append(ind(1) + "}\n");
  }
375
}
376

377
aspect BackendBidirectionalAPI {
Johannes Mey's avatar
Johannes Mey committed
378
379
380
381
382
383
384
385
386
387
388
389
390
  public void Bidirectional.generateAPI(StringBuilder sb) {
    RelationComponent l = relation().getLeft();
    RelationComponent r = relation().getRight();

    if (l.multiplicityOne()) {
      if (r.multiplicityOne()) {
        l.generateBiOneOne(sb, false);
        r.generateBiOneOne(sb, false);
      } else if (r.multiplicityOpt()) {
        l.generateBiOneOne(sb, false);
        r.generateBiOneOne(sb, true);
      } else if (r.multiplicityMany()) {
        l.generateBiOneMany(sb, false);
Johannes Mey's avatar
Johannes Mey committed
391
        r.generateBiManyOne(sb, l);
Johannes Mey's avatar
Johannes Mey committed
392
393
394
395
396
397
398
399
400
401
      }
    } else if (l.multiplicityOpt()) {
      if (r.multiplicityOne()) {
        l.generateBiOneOne(sb, true);
        r.generateBiOneOne(sb, false);
      } else if (r.multiplicityOpt()) {
        l.generateBiOneOne(sb, true);
        r.generateBiOneOne(sb, true);
      } else if (r.multiplicityMany()) {
        l.generateBiOneMany(sb, true);
Johannes Mey's avatar
Johannes Mey committed
402
        r.generateBiManyOne(sb, l);
Johannes Mey's avatar
Johannes Mey committed
403
404
405
      }
    } else if (l.multiplicityMany()) {
      if (r.multiplicityOne()) {
Johannes Mey's avatar
Johannes Mey committed
406
        l.generateBiManyOne(sb, r);
Johannes Mey's avatar
Johannes Mey committed
407
408
        r.generateBiOneMany(sb, false);
      } else if (r.multiplicityOpt()) {
Johannes Mey's avatar
Johannes Mey committed
409
        l.generateBiManyOne(sb, r);
Johannes Mey's avatar
Johannes Mey committed
410
411
        r.generateBiOneMany(sb, true);
      } else if (r.multiplicityMany()) {
Johannes Mey's avatar
Johannes Mey committed
412
413
        l.generateBiManyMany(sb, r);
        r.generateBiManyMany(sb, l);
Johannes Mey's avatar
Johannes Mey committed
414
415
416
417
418
419
420
421
422
      }
    }
  }

  public void RelationComponent.generateBiOneOne(StringBuilder sb, boolean isOpt) {
    // Get
    generateGetOne(sb);

    // Set
423
    sb.append(ind(1) + "public " + getTypeUse().decl() + " " + getTypeUse().decl());
Johannes Mey's avatar
Johannes Mey committed
424
425
426
427
    sb.append(".set" + nameCapitalized() + "(" + ofTypeDecl() + " o) {\n");
    if (!isOpt) {
      sb.append(ind(2) + "assertNotNull(o);\n");
    }
428
    // unset the old opposite
429
430
    sb.append(ind(2) + "if (" + getImplAttributeField() + " != null) {\n");
    sb.append(ind(3) + "" + getImplAttributeField() + ".set" + otherSide().getImplAttributeName() + "(null);\n");
Johannes Mey's avatar
Johannes Mey committed
431
    sb.append(ind(2) + "}\n");
432
    if (resolverHelper | serializer) {
433
      sb.append(ind(2) + "if (o != null && !o.is$Unresolved() && o." + otherSide().getImplAttributeField() + " != null) {\n");
434
    } else {
435
      sb.append(ind(2) + "if (o != null && o." + otherSide().getImplAttributeField() + " != null) {\n");
436
    }
437
    sb.append(ind(3) + "o." + otherSide().getImplAttributeField() + ".set" + getImplAttributeName() + "(null);\n");
Johannes Mey's avatar
Johannes Mey committed
438
439
    sb.append(ind(2) + "}\n");
    sb.append(ind(2) + "set" + getImplAttributeName() + "(o);\n");
440
    if (resolverHelper | serializer) {
441
      sb.append(ind(2) + "if (o == null || !o.is$Unresolved()) {\n");
442
443
444
445
446
447
448
      if (isOpt) {
        sb.append(ind(3) + "if (o != null) {\n");
        sb.append(ind(4) + "o.set" + otherSide().getImplAttributeName() + "(this);\n");
        sb.append(ind(3) + "}\n");
      } else {
        sb.append(ind(3) + "o.set" + otherSide().getImplAttributeName() + "(this);\n");
      }
Johannes Mey's avatar
Johannes Mey committed
449
450
      sb.append(ind(2) + "}\n");
    } else {
451
452
453
454
455
456
457
      if (isOpt) {
        sb.append(ind(2) + "if (o != null) {\n");
        sb.append(ind(3) + "o.set" + otherSide().getImplAttributeName() + "(this);\n");
        sb.append(ind(2) + "}\n");
      } else {
        sb.append(ind(2) + "o.set" + otherSide().getImplAttributeName() + "(this);\n");
      }
Johannes Mey's avatar
Johannes Mey committed
458
    }
459

460
    sb.append(ind(2) + "return this;\n");
Johannes Mey's avatar
Johannes Mey committed
461
462
463
464
465
466
467
    sb.append(ind(1) + "}\n");

    if (isOpt) {
      generateExtraOptAPI(sb);
    }
  }

Johannes Mey's avatar
Johannes Mey committed
468
  public void RelationComponent.generateBiManyMany(StringBuilder sb, RelationComponent opposite) {
Johannes Mey's avatar
Johannes Mey committed
469
    // Get
470
    sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + getTypeUse().decl() + ".");
471
472
473
474
475
    if (useJastAddNames) {
      // getXs
      sb.append("get" + nameCapitalized() + "s() {\n");
      sb.append(ind(2) + "return get" + nameCapitalized() + "List();\n");
      sb.append(ind(1) + "}\n");
476

477
      // getXList
478
      sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + getTypeUse().decl());
479
480
481
482
      sb.append(".get" + nameCapitalized() + "List() {\n");
    } else {
      sb.append(name() + "() {\n");
    }
483
484
    sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> l = get" + getImplAttributeName() + "();\n");
    // resolve the entire list
485
    if (resolverHelper | serializer) {
486
      sb.append(ind(2) + "if (l != null) {\n");
487
        sb.append(ind(3) + "boolean changed = false;\n");
488
489
        sb.append(ind(3) + "for (int i = 0; i < l.size(); i++) {\n");
          sb.append(ind(4) + ofTypeDecl() + " element = l.get(i);\n");
490
          sb.append(ind(4) + "if (element.is$Unresolved()) {\n");
491
            sb.append(ind(5) + "changed = true;\n");
492
493
            sb.append(ind(5) + ofTypeDecl() + " resolvedElement = resolve" + nameCapitalized() + "ByToken(element.as$Unresolved().getUnresolved$Token(), i);\n");
            sb.append(ind(5) + "if (resolvedElement != null && element.as$Unresolved().getUnresolved$ResolveOpposite()) {\n");
494
              sb.append(ind(6) + ASTNode.listClass + "<" + getTypeUse().decl() + "> otherList = resolvedElement." + opposite.getImplAttributeField() + ";\n");
495
              sb.append(ind(6) + "if (otherList == null) {\n");
496
                sb.append(ind(7) + "otherList = new " + listClass + "<>();\n");
497
498
              sb.append(ind(6) + "}\n");
              sb.append(ind(6) + "otherList.add(this);\n");
Johannes Mey's avatar
Johannes Mey committed
499
              sb.append(ind(6) + "resolvedElement.set" + opposite.getImplAttributeName() + "(otherList);\n");
500
501
502
503
            sb.append(ind(5) + "}\n");
            sb.append(ind(5) + "l.set(i, resolvedElement);\n");
          sb.append(ind(4) + "}\n");
        sb.append(ind(3) + "}\n");
504
505
506
        sb.append(ind(3) + "if (changed) {\n");
          sb.append(ind(4) + "set" + getImplAttributeName() + "(l);\n");
        sb.append(ind(3) + "}\n");
507
508
509
510
      sb.append(ind(2) + "}\n");
    }
    sb.append(ind(2) + "return l != null ? Collections.unmodifiableList(l) : Collections.emptyList();\n");
    sb.append(ind(1) + "}\n");
Johannes Mey's avatar
Johannes Mey committed
511
512

    // Add
513
    sb.append(ind(1) + "public void " + getTypeUse().decl() + ".add");
514
515
516
    if (!useJastAddNames) {
      sb.append("To");
    }
Johannes Mey's avatar
Johannes Mey committed
517
518
    sb.append(nameCapitalized() + "(" + ofTypeDecl() + " o) {\n");
    sb.append(ind(2) + "assertNotNull(o);\n");
519
    sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n");
Johannes Mey's avatar
Johannes Mey committed
520
521
522
    sb.append(ind(2) + "if (list == null) {\n");
    sb.append(ind(3) + "list = new " + ASTNode.listClass + "<>();\n");
    sb.append(ind(2) + "}\n");
523
    sb.append(ind(2) + ASTNode.listClass + "<" + otherSide().ofTypeDecl() + "> list2 = o." + otherSide().getImplAttributeField() + ";\n");
Johannes Mey's avatar
Johannes Mey committed
524
525
526
527
528
529
530
531
532
    sb.append(ind(2) + "if (list2 == null) {\n");
    sb.append(ind(3) + "list2 = new "+ ASTNode.listClass + "<>();\n");
    sb.append(ind(2) + "}\n");
    sb.append(ind(2) + "list.add(o);\n");
    sb.append(ind(2) + "list2.add(this);\n");
    sb.append(ind(2) + "set" + getImplAttributeName() + "(list);\n");
    sb.append(ind(2) + "o.set" + otherSide().getImplAttributeName() + "(list2);\n");
    sb.append(ind(1) + "}\n");

533
    // Insert / add at specific position
534
    sb.append(ind(1) + "public void " + getTypeUse().decl() + ".add");
535
536
537
538
    if (!useJastAddNames) {
      sb.append("To");
    }
    sb.append(nameCapitalized() + "(int index, " + ofTypeDecl() + " o) {\n");
539
    sb.append(ind(2) + "assertNotNull(o);\n");
540
    sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n");
541
542
543
    sb.append(ind(2) + "if (list == null) {\n");
    sb.append(ind(3) + "list = new " + ASTNode.listClass + "<>();\n");
    sb.append(ind(2) + "}\n");
544
545
    sb.append(ind(2) + ASTNode.listClass + "<" + otherSide().ofTypeDecl() + "> list2 = o."
    + otherSide().getImplAttributeField() + ";\n");
546
547
548
549
550
551
552
553
554
    sb.append(ind(2) + "if (list2 == null) {\n");
    sb.append(ind(3) + "list2 = new "+ ASTNode.listClass + "<>();\n");
    sb.append(ind(2) + "}\n");
    sb.append(ind(2) + "list.add(index, o);\n");
    sb.append(ind(2) + "list2.add(this);\n");
    sb.append(ind(2) + "set" + getImplAttributeName() + "(list);\n");
    sb.append(ind(2) + "o.set" + otherSide().getImplAttributeName() + "(list2);\n");
    sb.append(ind(1) + "}\n");

Johannes Mey's avatar
Johannes Mey committed
555
    // Remove
556
    sb.append(ind(1) + "public void " + getTypeUse().decl() + ".remove");
557
558
559
    if (!useJastAddNames) {
      sb.append("From");
    }
Johannes Mey's avatar
Johannes Mey committed
560
561
    sb.append(nameCapitalized() + "(" + ofTypeDecl() + " o) {\n");
    sb.append(ind(2) + "assertNotNull(o);\n");
562
    sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n");
Johannes Mey's avatar
Johannes Mey committed
563
    sb.append(ind(2) + "if (list != null && list.remove(o)) {\n");
564
565
    sb.append(ind(3) + ASTNode.listClass + "<" + otherSide().ofTypeDecl() + "> list2 = o."
      + otherSide().getImplAttributeField() + ";\n");
Johannes Mey's avatar
Johannes Mey committed
566
567
568
569
570
571
572
573
    sb.append(ind(3) + "if (list2 != null) list2.remove(this);\n");
    sb.append(ind(3) + "set" + getImplAttributeName() + "(list);\n");
    sb.append(ind(3) + "o.set" + otherSide().getImplAttributeName() + "(list2);\n");
    sb.append(ind(2) + "}\n");
    sb.append(ind(1) + "}\n");
  }


Johannes Mey's avatar
Johannes Mey committed
574
  public void RelationComponent.generateBiManyOne(StringBuilder sb, RelationComponent opposite) {
Johannes Mey's avatar
Johannes Mey committed
575
    // Get
576
    sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + getTypeUse().decl() + ".");
577
578
579
580
581
    if (useJastAddNames) {
      // getXs
      sb.append("get" + nameCapitalized() + "s() {\n");
      sb.append(ind(2) + "return get" + nameCapitalized() + "List();\n");
      sb.append(ind(1) + "}\n");
582

583
      // getXList
584
      sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + getTypeUse().decl());
585
586
587
588
      sb.append(".get" + nameCapitalized() + "List() {\n");
    } else {
      sb.append(name() + "() {\n");
    }
589
590
    sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> l = get" + getImplAttributeName() + "();\n");
    // resolve the entire list
591
    if (resolverHelper | serializer) {
592
      sb.append(ind(2) + "if (l != null) {\n");
593
        sb.append(ind(3) + "boolean changed = false;\n");
594
595
        sb.append(ind(3) + "for (int i = 0; i < l.size(); i++) {\n");
          sb.append(ind(4) + ofTypeDecl() + " element = l.get(i);\n");
596
          sb.append(ind(4) + "if (element.is$Unresolved()) {\n");
597
            sb.append(ind(5) + "changed = true;\n");
598
599
            sb.append(ind(5) + ofTypeDecl() + " resolvedElement = resolve" + nameCapitalized() + "ByToken(element.as$Unresolved().getUnresolved$Token(), i);\n");
            sb.append(ind(5) + "if (element.as$Unresolved().getUnresolved$ResolveOpposite()) {\n");
600
              sb.append(ind(6) + getTypeUse().decl() + " oldTarget = resolvedElement." + opposite.getImplAttributeField() + ";\n");
601
              sb.append(ind(6) + "if (oldTarget != null && oldTarget != this) {\n");
602
                sb.append(ind(7) + "oldTarget." + getImplAttributeField() + ".remove(resolvedElement);\n");
603
604
605
606
607
608
609
610
              sb.append(ind(6) + "}\n");
              sb.append(ind(6) + "if (oldTarget == this) {\n");
                sb.append(ind(7) + "l.remove(i);\n");
                sb.append(ind(7) + "i--;\n");
              sb.append(ind(6) + "} else {\n");
                sb.append(ind(7) + "resolvedElement.set" + opposite.getImplAttributeName() + "(this);\n");
                sb.append(ind(7) + "l.set(i, resolvedElement);\n");
              sb.append(ind(6) + "}\n");
611
612
613
614
615
            sb.append(ind(5) + "} else {\n");
              sb.append(ind(6) + "l.set(i, resolvedElement);\n");
            sb.append(ind(5) + "}\n");
          sb.append(ind(4) + "}\n");
        sb.append(ind(3) + "}\n");
616
617
618
        sb.append(ind(3) + "if (changed) {\n");
          sb.append(ind(4) + "set" + getImplAttributeName() + "(l);\n");
        sb.append(ind(3) + "}\n");
619
620
621
622
      sb.append(ind(2) + "}\n");
    }
    sb.append(ind(2) + "return l != null ? Collections.unmodifiableList(l) : Collections.emptyList();\n");
    sb.append(ind(1) + "}\n");
Johannes Mey's avatar
Johannes Mey committed
623
624

    // Add
625
    sb.append(ind(1) + "public void " + getTypeUse().decl() + ".add");
626
627
628
    if (!useJastAddNames) {
      sb.append("To");
    }
Johannes Mey's avatar
Johannes Mey committed
629
630
    sb.append(nameCapitalized() + "(" + ofTypeDecl() + " o) {\n");
    sb.append(ind(2) + "assertNotNull(o);\n");
631
632
633
    sb.append(ind(2) + "if (o != null && o." + otherSide().getImplAttributeField() + " != null) {\n");
    sb.append(ind(3) + ASTNode.listClass + "<" + ofTypeDecl() + "> list2 = o."
      + otherSide().getImplAttributeField() + "." + getImplAttributeField() + ";\n");
Johannes Mey's avatar
Johannes Mey committed
634
    sb.append(ind(3) + "if (list2.remove(o))\n");
635
636
    sb.append(ind(4) + "o." + otherSide().getImplAttributeField()
      + ".set" + getImplAttributeName() + "(list2);\n");
Johannes Mey's avatar
Johannes Mey committed
637
    sb.append(ind(2) + "}\n");
638
    sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n");
Johannes Mey's avatar
Johannes Mey committed
639
640
641
642
643
644
645
646
    sb.append(ind(2) + "if (list == null) {\n");
    sb.append(ind(3) + "list = new " + ASTNode.listClass + "<>();\n");
    sb.append(ind(2) + "}\n");
    sb.append(ind(2) + "list.add(o);\n");
    sb.append(ind(2) + "set" + getImplAttributeName() + "(list);\n");
    sb.append(ind(2) + "o.set" + otherSide().getImplAttributeName() + "(this);\n");
    sb.append(ind(1) + "}\n");

647
    // Insert / add at specific position
648
    sb.append(ind(1) + "public void " + getTypeUse().decl() + ".add");
649
650
651
652
    if (!useJastAddNames) {
      sb.append("To");
    }
    sb.append(nameCapitalized() + "(int index, " + ofTypeDecl() + " o) {\n");
653
      sb.append(ind(2) + "assertNotNull(o);\n");
654
655
      sb.append(ind(2) + "if (o != null && o." + otherSide().getImplAttributeField() + " != null) {\n");
        sb.append(ind(3) + ASTNode.listClass + "<" + ofTypeDecl() + "> list2 = o." + otherSide().getImplAttributeField() + "." + getImplAttributeField() + ";\n");
656
        sb.append(ind(3) + "if (list2.remove(o))\n");
657
          sb.append(ind(4) + "o." + otherSide().getImplAttributeField() + ".set" + getImplAttributeName() + "(list2);\n");
658
      sb.append(ind(2) + "}\n");
659
      sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n");
660
661
662
663
664
665
666
667
      sb.append(ind(2) + "if (list == null) {\n");
        sb.append(ind(3) + "list = new " + ASTNode.listClass + "<>();\n");
      sb.append(ind(2) + "}\n");
      sb.append(ind(2) + "list.add(index, o);\n");
      sb.append(ind(2) + "set" + getImplAttributeName() + "(list);\n");
      sb.append(ind(2) + "o.set" + otherSide().getImplAttributeName() + "(this);\n");
    sb.append(ind(1) + "}\n");

Johannes Mey's avatar
Johannes Mey committed
668
    // Remove
669
    sb.append(ind(1) + "public void " + getTypeUse().decl() + ".remove");
670
671
672
    if (!useJastAddNames) {
      sb.append("From");
    }
Johannes Mey's avatar
Johannes Mey committed
673
674
    sb.append(nameCapitalized() + "(" + ofTypeDecl() + " o) {\n");
    sb.append(ind(2) + "assertNotNull(o);\n");
675
    sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = " + getImplAttributeField() + ";\n");
Johannes Mey's avatar
Johannes Mey committed
676
677
    sb.append(ind(2) + "if (list != null && list.remove(o)) {\n");
    sb.append(ind(3) + "set" + getImplAttributeName() + "(list);\n");
678
    sb.append(ind(3) + "if (o." + otherSide().getImplAttributeField() + " == this) {\n");
Johannes Mey's avatar
Johannes Mey committed
679
680
681
682
683
684
685
686
687
688
689
    sb.append(ind(4) + "o.set" + otherSide().getImplAttributeName() + "(null);\n");
    sb.append(ind(3) + "}\n");
    sb.append(ind(2) + "}\n");
    sb.append(ind(1) + "}\n");
  }

  public void RelationComponent.generateBiOneMany(StringBuilder sb, boolean isOpt) {
    // Get
    generateGetOne(sb);

    // Set
690
    sb.append(ind(1) + "public " + getTypeUse().decl() + " " + getTypeUse().decl() + ".set" + nameCapitalized()
Johannes Mey's avatar
Johannes Mey committed
691
692
693
694
      + "(" + ofTypeDecl() + " o) {\n");
    if (!isOpt) {
      sb.append(ind(2) + "assertNotNull(o);\n");
    }
695
    sb.append(ind(2) + "if (" + getImplAttributeField() + " != null) {\n");
696
    sb.append(ind(3) + ASTNode.listClass + "<" + getTypeUse().decl() + "> list2 = " + getImplAttributeField()
697
      + "." + otherSide().getImplAttributeField() + ";\n");
Johannes Mey's avatar
Johannes Mey committed
698
    sb.append(ind(3) + "list2.remove(this);\n");
699
    sb.append(ind(3) + getImplAttributeField() + "." + "set"
Johannes Mey's avatar
Johannes Mey committed
700
701
702
703
704
705
706
707
      + otherSide().getImplAttributeName() + "(list2);\n");
    sb.append(ind(2) + "}\n");
    sb.append(ind(2) + "set" + getImplAttributeName() + "(o);\n");

    int ind = isOpt ? 3 : 2;
    if (isOpt) {
      sb.append(ind(2) + "if (o != null) {\n");
    }
708
    sb.append(ind(ind) + ASTNode.listClass + "<" + getTypeUse().decl() + "> list = o."
709
      + otherSide().getImplAttributeField() + ";\n");
Johannes Mey's avatar
Johannes Mey committed
710
711
712
713
714
715
716
717
    sb.append(ind(ind) + "if (list == null) {\n");
    sb.append(ind(ind+1) + "list = new " + ASTNode.listClass + "<>();\n");
    sb.append(ind(ind) + "}\n");
    sb.append(ind(ind) + "list.add(this);\n");
    sb.append(ind(ind) + "o.set" + otherSide().getImplAttributeName() + "(list);\n");
    if (isOpt) {
      sb.append(ind(2) + "}\n");
    }
718
    sb.append(ind(2) + "return this;\n");
Johannes Mey's avatar
Johannes Mey committed
719
720
721
722
723
724
    sb.append(ind(1) + "}\n");

    if (isOpt) {
      generateExtraOptAPI(sb);
    }
  }
725
726
}

727
aspect LowerBoundCheck {
Johannes Mey's avatar
Johannes Mey committed
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
  public void Program.generateLowerBoundCheck(StringBuilder sb) {
    sb.append(ind(1) + "public boolean ASTNode.violatesLowerBounds() {\n");
    sb.append(ind(2) + "return !getLowerBoundsViolations().isEmpty();\n");
    sb.append(ind(1) + "}\n");

    sb.append(ind(1) + "public java.util.List<Pair<ASTNode, String>> "
      + "ASTNode.getLowerBoundsViolations() {\n");
    sb.append(ind(2) + "ArrayList<Pair<ASTNode, String>> list = new ArrayList<>();\n");
    sb.append(ind(2) + "computeLowerBoundsViolations(list);\n");
    sb.append(ind(2) + "return list;\n");
    sb.append(ind(1) + "}\n");

    sb.append(ind(1) + "public void ASTNode.computeLowerBoundsViolations("
      + "java.util.List<Pair<ASTNode, String>> list) {\n");
    sb.append(ind(2) + "for (int i = 0; i < getNumChildNoTransform(); i++) {\n");
    sb.append(ind(3) + "getChildNoTransform(i).computeLowerBoundsViolations(list);\n");
    sb.append(ind(2) + "}\n");
    sb.append(ind(1) + "}\n");

    for (TypeDecl td: getTypeDecls()) {
      td.generateLowerBoundCheck(sb);
    }

    generatePairClass(sb);
  }

  public void TypeDecl.generateLowerBoundCheck(StringBuilder sb) {
    if (!oneRelationComponents().isEmpty()) {
      sb.append(ind(1) + "public void " + getID() + ".computeLowerBoundsViolations(" +
        "java.util.List<Pair<ASTNode, String>> list) {\n");
      for (OneRelationComponent o: oneRelationComponents()) {
        o.generateLowerBoundCheck(sb);
      }
      sb.append(ind(2) + "super.computeLowerBoundsViolations(list);\n");
      sb.append(ind(1) + "}\n");
    }
  }

  public void OneRelationComponent.generateLowerBoundCheck(StringBuilder sb) {
767
768
769
770
771
772
773
    sb.append(ind(2) + "if (");
    if (useJastAddNames) {
      sb.append("get" + nameCapitalized());
    } else {
      sb.append(name());
    }
    sb.append("() == null) {\n");
Johannes Mey's avatar
Johannes Mey committed
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
    sb.append(ind(3) + "list.add(new Pair<>(this, \"" + name() + "\"));\n");
    sb.append(ind(2) + "}\n");
  }


  public void Program.generatePairClass(StringBuilder sb) {
    sb.append(ind(1) + "public class Pair<T1, T2> {\n");
    sb.append(ind(2) + "public final T1 _1;\n");
    sb.append(ind(2) + "public final T2 _2;\n");
    // Constructor
    sb.append(ind(2) + "public Pair(T1 _1, T2 _2) {\n");
    sb.append(ind(3) + "ASTNode.assertNotNull(_1);\n");
    sb.append(ind(3) + "ASTNode.assertNotNull(_2);\n");
    sb.append(ind(3) + "this._1 = _1;\n");
    sb.append(ind(3) + "this._2 = _2;\n");
    sb.append(ind(2) + "}\n");
    // equals
    sb.append(ind(2) + "public boolean equals(Object other) {\n");
    sb.append(ind(3) + "if (other instanceof Pair) {\n");
    sb.append(ind(4) + "Pair<?,?> p = (Pair<?,?>) other;\n");
    sb.append(ind(4) + "return _1.equals(p._1) && _2.equals(p._2);\n");
    sb.append(ind(3) + "} else {\n");
    sb.append(ind(4) + "return false;\n");
    sb.append(ind(3) + "}\n");
    sb.append(ind(2) + "}\n");
    // hashCode
    sb.append(ind(2) + "public int hashCode() {\n");
    sb.append(ind(3) + "return 31*_1.hashCode() + _2.hashCode();\n");
    sb.append(ind(2) + "}\n");
    sb.append(ind(1) + "}\n");
  }
805
}
806

807
808
809
810
811
812
813
814
aspect NameResolutionHelper {

  public String Program.generateRewriteToSuperTypeStub() {
    StringBuilder sb = new StringBuilder();
    generateRewriteToSuperTypeStub(sb);
    return sb.toString();
  }

815
816
817
818
819
820
821
  public String Program.generateResolverStubs() {
    StringBuilder sb = new StringBuilder();
    generateResolverStubs(sb);
    return sb.toString();
  }

  public void Program.generateResolverStubs(StringBuilder sb) {
822
823
824
825
826
827
    sb.append("aspect RefResolverStubs {\n\n");

    for (Relation r: getRelations()) {
      r.generateContextDependentNameResolution(sb);
    }

828
    if (resolverHelper || ASTNode.jsonPointer || ASTNode.manualReferences) {
829
830
831
832
      for (TypeDecl decl : getTypeDeclList()) {
        decl.generateContextIndependentNameResolution(sb);
        sb.append("\n");
      }
833
834
    }
    sb.append("}\n\n");
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894

    if (ASTNode.manualReferences) {
      sb.append("aspect RefCreatorStubs {\n\n");

      for (Relation r: getRelations()) {
        r.generateContextDependentRefCreation(sb);
      }

      generateGenericRefCreation(sb);
      sb.append("\n");

      for (TypeDecl decl : getTypeDeclList()) {
        decl.generateContextIndependentRefCreation(sb);
        sb.append("\n");
      }

      sb.append("}\n\n");
    }
  }

  public void Program.generateGenericRefCreation(StringBuilder sb) {
    sb.append(ind(1) + "// generic reference creation\n");
    sb.append(ind(1) + "syn String ASTNode.createReference();\n");
    sb.append(ind(1) + "eq ASTNode.createReference() {\n");
    sb.append(ind(2) + "throw new RuntimeException(\"Generic reference creation not implemented.\");\n");
    sb.append(ind(1) + "}\n");
  }

  public void Relation.generateContextDependentRefCreation(StringBuilder sb) {
    sb.append(ind(1) + "// " + prettyPrint() + "\n");
    getDirection().generateContextDependentRefCreation(sb);
    sb.append("\n");
  }

  public abstract void Direction.generateContextDependentRefCreation(StringBuilder sb);
  public void RightDirection.generateContextDependentRefCreation(StringBuilder sb) {
    relation().getLeft().generateContextDependentRefCreation(sb);
  }
  public void LeftDirection.generateContextDependentRefCreation(StringBuilder sb) {
    relation().getRight().generateContextDependentRefCreation(sb);
  }
  public void Bidirectional.generateContextDependentRefCreation(StringBuilder sb) {
    relation().getLeft().generateContextDependentRefCreation(sb);
    relation().getRight().generateContextDependentRefCreation(sb);
  }

  public void RelationComponent.generateContextDependentRefCreation(StringBuilder sb) {
    sb.append(ind(1) + "// context-dependent reference creation\n");
    sb.append(ind(1) + "syn String " + getTypeUse().decl() + ".createRefTo" + nameCapitalized() + "(" + ofTypeDecl() + " target) {\n");
    sb.append(ind(2) + "// default to context-independent reference creation\n");
    sb.append(ind(2) + "return target.createReference();\n");
    sb.append(ind(1) + "}\n");
  }

  public void TypeDecl.generateContextIndependentRefCreation(StringBuilder sb) {
    sb.append(ind(1) + "// context-independent reference creation\n");
    sb.append(ind(1) + "eq " + getID() + ".createReference() {\n");
    sb.append(ind(2) + "// default to generic reference creation\n");
    sb.append(ind(2) + "return super.createReference();\n");
    sb.append(ind(1) + "}\n");
895
896
897
  }

  public void Program.generateRewriteToSuperTypeStub(StringBuilder sb) {
898
899
900
901

    sb.append("aspect ReferenceCreation {\n\n");

    for (TypeDecl decl : getTypeDeclList()) {
902
      decl.createReferenceCreator(sb);
903
904
905
906
    }

    sb.append("}\n\n");

907
908
909
910
911
    sb.append("aspect ResolverTrigger {\n\n");

    resolveAll(sb);

    for (TypeDecl decl : getTypeDeclList()) {
912
      decl.resolveAll(sb);
913
914
915
916
    }

    sb.append("}\n\n");

917
918
    sb.append("aspect RefResolverHelpers {\n\n");

919
920
921
    sb.append(ind(1) + "interface Unresolved$Node {\n");
    sb.append(ind(2) + "String getUnresolved$Token();\n");
    sb.append(ind(2) + "boolean getUnresolved$ResolveOpposite();\n");
922
923
    sb.append(ind(1) + "}\n\n");

924
925
926
    for (TypeDecl td: getTypeDecls()) {
      if (td.needUnresolvedClass()) {
        td.generateUnresolvedClass(sb);
927
928
929
930
931
932
      }
    }

    sb.append("\n}\n");
  }

933
  public void TypeDecl.createReferenceCreator(StringBuilder sb) {
934

935
936
937
    TypeDecl instantiableSubType = instantiableSubType();
    if (instantiableSubType == null) {
      throw new RuntimeException("unable to find instantiable subtype for " + getID());
938
939
    }

940
941
942
943
    sb.append(ind(1) + "public static " + getID() + " " + getID() + ".createRef(String ref) {\n");
      sb.append(ind(2) + "Unresolved$" + instantiableSubType.getID() + " unresolvedNode = new Unresolved$" + instantiableSubType.getID() + "();\n");
      sb.append(ind(2) + "unresolvedNode.setUnresolved$Token(ref);\n");
      sb.append(ind(2) + "unresolvedNode.setUnresolved$ResolveOpposite(true);\n");
944
945
946
      sb.append(ind(2) + "return unresolvedNode;\n");
    sb.append(ind(1) + "}\n");

947
948
949
950
    sb.append(ind(1) + "public static " + getID() + " " + getID() + ".createRefDirection(String ref) {\n");
      sb.append(ind(2) + "Unresolved$" + instantiableSubType.getID() + " unresolvedNode = new Unresolved$" + instantiableSubType.getID() + "();\n");
      sb.append(ind(2) + "unresolvedNode.setUnresolved$Token(ref);\n");
      sb.append(ind(2) + "unresolvedNode.setUnresolved$ResolveOpposite(false);\n");
951
952
953
954
      sb.append(ind(2) + "return unresolvedNode;\n");
    sb.append(ind(1) + "}\n");
  }

955
  public void TypeDecl.generateContextIndependentNameResolution(StringBuilder sb) {
956
    sb.append(ind(1) + "// context-independent name resolution\n");
957
    sb.append(ind(1) + "uncache ASTNode.globallyResolve" + getID() + "ByToken(String id);\n");
958
    sb.append(ind(1) + "syn " + getID() + " ASTNode.globallyResolve" + getID() + "ByToken(String id) {\n");
959
960
961
962
963
964
    if (serializer && !manualReferences) {
      if (jsonPointer) {
        sb.append(ind(2) + "return (" + getID() + ") resolveJsonPointer(id);\n");
      } else {
        sb.append(ind(2) + "return (" + getID() + ") globallyResolveASTNodeByUID(id);\n");
      }
965
    } else {
966
      sb.append(ind(2) + "// perform context independent name resolution here using the id\n");
967
      sb.append(ind(2) + "throw new RuntimeException(\"Context-independent name resolution for " + getID() + " not implemented.\");\n");
968
    }
969
970
971
972
973
974
975
976
977
978
979
980
981
    sb.append(ind(1) + "}\n");
  }

  public void Relation.generateContextDependentNameResolution(StringBuilder sb) {
    sb.append(ind(1) + "// " + prettyPrint() + "\n");
    getDirection().generateContextDependentNameResolution(sb);
    sb.append("\n");
  }

  public abstract void Direction.generateContextDependentNameResolution(StringBuilder sb);
  public void RightDirection.generateContextDependentNameResolution(StringBuilder sb) {
    relation().getLeft().generateContextDependentNameResolution(sb);
  }
René Schöne's avatar
René Schöne committed
982
983
984
  public void LeftDirection.generateContextDependentNameResolution(StringBuilder sb) {
    relation().getRight().generateContextDependentNameResolution(sb);
  }
985
  public void Bidirectional.generateContextDependentNameResolution(StringBuilder sb) {
986
987
    relation().getLeft().generateContextDependentNameResolution(sb);
    relation().getRight().generateContextDependentNameResolution(sb);
988
989
990
991
992
993
994
  }

  public abstract void RelationComponent.generateContextDependentNameResolution(StringBuilder sb);
  public void OneRelationComponent.generateContextDependentNameResolution(StringBuilder sb) {
    generateDirectedContextDependentNameResolution(sb);
  }
  public void OptionalRelationComponent.generateContextDependentNameResolution(StringBuilder sb) {
995
996
997
    // optional relations are resolved in the same way as mandatory relations
    // TODO maybe, there should be a check if the id to be solved is empty or null
    generateDirectedContextDependentNameResolution(sb);
998
999
  }
  public void ManyRelationComponent.generateContextDependentNameResolution(StringBuilder sb) {
1000