Analysis.jrag 8.8 KB
Newer Older
Johannes Mey's avatar
Johannes Mey committed
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
import java.util.*;


aspect TypeAnalysis {
  public abstract TypeUse Component.getTypeUse();

  //--- lookupType ---
  syn TypeDecl TypeUse.decl() = lookupType(getID());
  inh TypeDecl TypeUse.lookupType(String name);
  inh TypeDecl TypeDecl.lookupType(String name);
  eq Program.getChild().lookupType(String name) {
    for (TypeDecl td : getTypeDecls()) {
      if (td.getID().equals(name)) {
        return td;
      }
    }
    return null;
  }

  //--- isAlreadyDeclared ---
  syn boolean TypeDecl.isAlreadyDeclared() = lookupType(getID()) != this;
}

aspect ComponentAnalysis {
  //--- isTargetOfDirectedRelation ---
  inh boolean Component.isTargetOfDirectedRelation();
  eq Relation.getRight().isTargetOfDirectedRelation() = getDirection() instanceof RightDirection;
  eq Program.getChild().isTargetOfDirectedRelation() = false;

  //--- name ---
  syn String Component.name() = getID();

  //--- enclosingTypeDecl ---
  inh TypeDecl Component.enclosingTypeDecl();
  eq TypeDecl.getChild().enclosingTypeDecl() = this;
  eq Program.getChild().enclosingTypeDecl() = null;

  //--- otherSide ---
  inh RelationComponent RelationComponent.opposite();
  eq Relation.getLeft().opposite() = getRight();
  eq Relation.getRight().opposite() = getLeft();
  eq Program.getChild().opposite() = null;

  //--- ofTypeDecl ---
  syn TypeDecl RelationComponent.ofTypeDecl() = opposite().getTypeUse().decl();

  //--- isAlreadyDeclared ---
  /**
   * Check, if role with the same name is already declared on the same nonterminal
   */
  syn boolean RelationComponent.isAlreadyDeclared()
    = !isTargetOfDirectedRelation()                     /* if unnamed in relation, there is no role name, so no error */
      && getTypeUse().decl() != null                           /* nonterminal type of role is defined */
      && findComponent(getTypeUse().decl(), name()) != this;   /* there is another role defined previously with the same name */

  //--- findComponent ---
  /** Search for either a component on the RHS of the given type with the given name,
   *   or a relation part for the given type and a role with the given name */
  inh Component Component.findComponent(TypeDecl td, String name);
  eq Program.getChild().findComponent(TypeDecl td, String name)
    = findComponentSyn(td, name);
  syn Component Program.findComponentSyn(TypeDecl td, String name) {
    for (Component c: td.getComponents()) {
      if (c.name().equals(name)) {
        return c;
      }
    }

    for (Relation r : getRelations()) {
      if (r.getLeft().matches(td, name))
        return r.getLeft();
      if (r.getRight().matches(td, name))
        return r.getRight();
    }

    return null;
  }

  //--- isInvalidRedefinition ---
  /**
   * Check, if a component with the same name is already declared in some supertype
   */
  syn boolean Component.isInvalidRedefinition() = invalidRedefinition() != null;

  /**
   * Check, if a component with the same name is already declared in some supertype, and return it, if any
   */
  syn Component Component.invalidRedefinition() = null;
  eq TokenComponent.invalidRedefinition() = invalidRedefinitionOn(enclosingTypeDecl());
  eq RelationComponent.invalidRedefinition() = invalidRedefinitionOn(getTypeUse().decl());

  syn Component Component.invalidRedefinitionOn(TypeDecl td) {
    if (td == null) return null;

    while (td.hasSuper() && td.getSuper().decl() != null) {
      td = td.getSuper().decl();
      // find a matching component on the RHS of the (current) super type
      Component c = findComponent(td, getID());

      if (c != null && !this.isEqual(c)) return c;
    }
    return null;
  }

  //--- isEqual ---
  syn boolean Component.isEqual(Component c) = this.getClass() == c.getClass() && getTypeUse().isEqual(c.getTypeUse());

  /**
   * TokenComponents may be specialized by NTATokenComponents and vice versa
   */
  eq TokenComponent.isEqual(Component c) = (c instanceof TokenComponent) && getTypeUse().isEqual(c.getTypeUse());

  syn boolean TypeUse.isEqual(TypeUse u);
  eq SimpleTypeUse.isEqual(TypeUse u) = u instanceof SimpleTypeUse && getID().equals(u.getID());
  eq ParameterizedTypeUse.isEqual(TypeUse u) {
    if (!getID().equals(u.getID())) return false;
    if (!(u instanceof ParameterizedTypeUse)) return false;
    ParameterizedTypeUse pu = (ParameterizedTypeUse) u;
    if (getNumTypeUse() != pu.getNumTypeUse()) return false;
    for (int i = 0; i < getNumTypeUse(); i++) {
      if (!getTypeUse(i).isEqual(pu.getTypeUse(i))) return false;
    }
    return true;
  }

  //--- matches ---
  /**
   * @return true, if the component has both type and role, its type matches the given typeDecl and its name matches the given name
   */
  syn boolean RelationComponent.matches(TypeDecl td, String name)
    = !isTargetOfDirectedRelation() && getTypeUse().decl() == td && name().equals(name);

  //--- relationComponents ---
  coll Set<RelationComponent> TypeDecl.relationComponents()
    [new HashSet<RelationComponent>()]
    root Program;
  RelationComponent contributes this
    when !isTargetOfDirectedRelation() && getTypeUse().decl() != null
    to TypeDecl.relationComponents()
    for getTypeUse().decl();

  //--- relationComponentsTransitive ---
  syn Collection<RelationComponent> TypeDecl.relationComponentsTransitive() {
    Collection<RelationComponent> list = new ArrayList<>();
    if (hasSuper() && getSuper().decl() != null) {
      list.addAll(getSuper().decl().relationComponentsTransitive());
    }
    list.addAll(relationComponents());
    return list;
  }

  //--- oneRelationComponents ---
  syn Set<OneRelationComponent> TypeDecl.oneRelationComponents() {
    Set<OneRelationComponent> set = new HashSet<>();
    for (RelationComponent rc: relationComponents()) {
      if (rc instanceof OneRelationComponent) {
        set.add((OneRelationComponent) rc);
      }
    }
    return set;
  }

  //--- needUnresolvedClass ---
  syn boolean TypeDecl.needUnresolvedClass() {
    // a TypeDecl needs an unresolved class, if it can appear in a relation
    // TODO
    return true;
  }

  //--- isList ---
  syn boolean Component.isList() = false;
  eq ListComponent.isList() = true;
  eq NTAListComponent.isList() = true;
  eq ManyRelationComponent.isList() = true;

  //--- isOpt ---
  syn boolean Component.isOpt() = false;
  eq OptComponent.isOpt() = true;
  eq NTAOptComponent.isOpt() = true;
  eq OptionalRelationComponent.isOpt() = true;

  //--- isNullable ---
  syn boolean Component.isNullable() = false;
  eq TokenComponent.isNullable() = !"float double int short long char byte boolean".contains(getTypeUse().getID());
}

aspect InstanceSupplier {

  //--- program ---
  inh Program TypeDecl.program();
  eq Program.getTypeDecl(int i).program() = this;

  //--- subTypeDecls ---
  syn Collection<TypeDecl> TypeDecl.subTypeDecls() {
    Collection<TypeDecl> subDecls = new ArrayList();
    for (TypeDecl decl : program().getTypeDeclList()) {
      if (decl.hasSuper() && decl.getSuper().getID().equals(getID())) {
        subDecls.add(decl);
      }
    }
    return subDecls;
  }

  //--- instantiableSubType ---
  syn TypeDecl TypeDecl.instantiableSubType() {
    if (getAbstract() == false) {
      return this;
    } else {
      for (TypeDecl sub : subTypeDecls()) {
        if (sub.getAbstract() == false) {
          return sub;
        } else {
          TypeDecl subInstance = sub.instantiableSubType();
          if (subInstance != null) {
            return subInstance;
          }
        }
      }
    }
    return null;
  }
}

aspect Constructors {
  //--- componentsTransitive ---
  syn Collection<Component> TypeDecl.componentsTransitive() {
    ArrayList<Component> list = new ArrayList<>();
    if (hasSuper() && getSuper().decl() != null) {
      list.addAll(getSuper().decl().componentsTransitive());
    }
    for (Component c: getComponents()) {
      if (c.inConstructor()) {
        list.add(c);
      }
    }
    return list;
  }

  //--- needsConstructor ---
  syn boolean TypeDecl.needsConstructor() = !componentsTransitive().isEmpty() && !relationComponentsTransitive().isEmpty();

  //--- inConstructor ---
  /**
   * @return true, if the component should be added to the constructor (i.e., is not an NTA)
   */
  syn boolean Component.inConstructor() = true;
  eq NTAComponent.inConstructor() = false;
  eq NTAOptComponent.inConstructor() = false;
  eq NTAListComponent.inConstructor() = false;
  eq NTATokenComponent.inConstructor() = false;
}

aspect Utils {

  //--- toString ---
  public String SimpleTypeUse.toString() {
    return getID();
  }
  public String ParameterizedTypeUse.toString() {
    StringBuilder sb = new StringBuilder();
    sb.append(getID()).append("<");
    boolean first = true;
    for (TypeUse u: getTypeUses()) {
      if (first) {
        first = false;
      } else {
        sb.append(", ");
      }
      sb.append(u.toString());
    }
    sb.append(">");
    return sb.toString();
  }
  public String TypeDecl.toString() {
    return getID();
  }
}