|
9 | 9 |
|
10 | 10 | import de.uka.ilkd.key.java.ConvertException; |
11 | 11 | import de.uka.ilkd.key.nparser.KeyAst; |
| 12 | +import de.uka.ilkd.key.parser.Location; |
12 | 13 | import de.uka.ilkd.key.settings.ProofIndependentSettings; |
13 | 14 | import de.uka.ilkd.key.speclang.PositionedString; |
14 | 15 | import de.uka.ilkd.key.speclang.jml.pretranslation.*; |
|
65 | 66 | /// [JMLTransformer#KEY_SPEC_CASE], and [JMLTransformer#KEY_SPEC_CASE]. |
66 | 67 | /// |
67 | 68 | /// JMLModifier are reduced to *normal* modifier of {@link DefaultKeyword}. |
| 69 | +/// |
| 70 | +/// @author weigl |
| 71 | +/// @author drodt |
| 72 | +/// @author lanzinger |
| 73 | +/// @author bubel |
| 74 | +/// @author pfeifer |
| 75 | +/// @author ulbrich |
68 | 76 | @SuppressWarnings("OptionalGetWithoutIsPresent") |
69 | 77 | public final class JMLTransformer extends JavaTransformer { |
70 | 78 | public static final EnumSet<JMLModifier> JAVA_MODS = |
@@ -142,10 +150,8 @@ public JMLTransformer(TransformationPipelineServices services) { |
142 | 150 | * @param decl the given ghost/model declaration (TextualJMLFieldDecl is also used to represent |
143 | 151 | * local variable declarations!) |
144 | 152 | * @return the newly created statement |
145 | | - * @throws SLTranslationException |
146 | 153 | */ |
147 | | - private @NonNull Statement transformVariableDecl(TextualJMLFieldDecl decl) |
148 | | - throws SLTranslationException { |
| 154 | + private @NonNull Statement transformVariableDecl(TextualJMLFieldDecl decl) { |
149 | 155 | NodeList<Modifier> modifiers = new NodeList<>(); |
150 | 156 | for (JMLModifier m : decl.getModifiers()) { |
151 | 157 | if (m.equals(JMLModifier.MODEL)) { |
@@ -220,8 +226,7 @@ public JMLTransformer(TransformationPipelineServices services) { |
220 | 226 | } |
221 | 227 |
|
222 | 228 |
|
223 | | - private Statement transformAssertStatement(TextualJMLAssertStatement stat) |
224 | | - throws SLTranslationException { |
| 229 | + private Statement transformAssertStatement(TextualJMLAssertStatement stat) { |
225 | 230 | KeyAst.Expression ctx = stat.getContext(); |
226 | 231 | de.uka.ilkd.key.java.Position pos = ctx.getStartLocation().getPosition(); |
227 | 232 | int kind = switch (stat.getKind()) { |
@@ -259,7 +264,7 @@ private KeYMarkerStatement transformMergePointDecl(TextualJMLMergePointDecl stat |
259 | 264 | * @throws SLTranslationException |
260 | 265 | */ |
261 | 266 | private void transformClassLevelComments(TypeDeclaration<?> td) throws SLTranslationException { |
262 | | - URI fileName = td.findCompilationUnit().flatMap(it -> it.getStorage()) |
| 267 | + URI fileName = td.findCompilationUnit().flatMap(CompilationUnit::getStorage) |
263 | 268 | .map(it -> it.getPath().toUri()) |
264 | 269 | .orElse(null); |
265 | 270 |
|
@@ -310,25 +315,23 @@ private void transformClassLevelComments(TypeDeclaration<?> td) throws SLTransla |
310 | 315 | // in a later loop iteration to the model method declaration |
311 | 316 | specCases.add(specCase); |
312 | 317 | } else if (c instanceof TextualJMLModifierList newModifiers) { |
313 | | - assert jmlModifiers == null |
314 | | - : "There seems to be more than one set of dangling modifiers"; |
| 318 | + if (jmlModifiers != null) { |
| 319 | + throw new SLTranslationException("There seems to be more than one set of dangling modifiers", |
| 320 | + c.getLocation()); |
| 321 | + } |
315 | 322 | jmlModifiers = newModifiers; |
316 | 323 | } else { |
317 | | - String errorMessage = ""; |
318 | | - if (c instanceof TextualJMLSetStatement) { |
319 | | - errorMessage = "A set assignment only allowed inside of a method body"; |
320 | | - } else if (c instanceof TextualJMLMergePointDecl) { |
321 | | - errorMessage = "Merge points are only allowed inside of a method body"; |
322 | | - } else if (c instanceof TextualJMLLoopSpec) { |
323 | | - errorMessage = |
324 | | - "Loop specifications are only allowed inside of a method body or initializers"; |
325 | | - } else if (c instanceof TextualJMLAssertStatement) { |
326 | | - errorMessage = |
327 | | - "Assert statements are only allowed inside of a method body or initializers"; |
328 | | - } else { |
329 | | - errorMessage = |
330 | | - "Unknown subclass of TextualJMLSpecCase: " + c.getClass(); |
331 | | - } |
| 324 | + String errorMessage = switch (c) { |
| 325 | + case TextualJMLSetStatement a -> |
| 326 | + "A set assignment only allowed inside of a method body"; |
| 327 | + case TextualJMLMergePointDecl a -> |
| 328 | + "Merge points are only allowed inside of a method body"; |
| 329 | + case TextualJMLLoopSpec a -> |
| 330 | + "Loop specifications are only allowed inside of a method body or initializers"; |
| 331 | + case TextualJMLAssertStatement a -> |
| 332 | + "Assert statements are only allowed inside of a method body or initializers"; |
| 333 | + default -> "Unknown subclass of TextualJMLSpecCase: " + c.getClass(); |
| 334 | + }; |
332 | 335 | throw new ConvertException(errorMessage, c.getLocation()); |
333 | 336 | } |
334 | 337 | } |
@@ -414,6 +417,24 @@ private void transformMethodLevelCommentsAt(BlockStmt blockStmt, URI fileName) |
414 | 417 | for (int i = 0; i < stmts.size(); i++) { |
415 | 418 | var stmt = stmts.get(i); |
416 | 419 | newStmts.add(stmt); |
| 420 | + |
| 421 | + while(stmt instanceof LabeledStmt labeledStmt) { |
| 422 | + var inner = labeledStmt.getStatement(); |
| 423 | + |
| 424 | + if(inner instanceof JmlDocsStatements) { |
| 425 | + throw new SLTranslationException(("Here is something wrong. Your label '%s' is glued to a " + |
| 426 | + "JML annotation instead of a Java statement. Please consider the use of braces") |
| 427 | + .formatted(labeledStmt.getLabel()), |
| 428 | + Location.fromNode(inner)); |
| 429 | + } |
| 430 | + // go into the labled statement |
| 431 | + stmt = inner; |
| 432 | + // and treat it like a regular statement. Especially, that means |
| 433 | + // the processing go into labled blocks `l:{}`, labled ifs `l:if(){}` or labled loops. |
| 434 | + // It can not be a JML annotation statement by the exception above; |
| 435 | + } |
| 436 | + |
| 437 | + |
417 | 438 | if (stmt instanceof BlockStmt bs) { |
418 | 439 | transformMethodLevelCommentsAt(bs, fileName); |
419 | 440 | } else if (stmt instanceof IfStmt is) { |
@@ -458,6 +479,10 @@ private void transformMethodLevelCommentsAt(BlockStmt blockStmt, URI fileName) |
458 | 479 | } |
459 | 480 | case TextualJMLLoopSpec spec -> { |
460 | 481 | var specifiedStmt = stmts.get(i + 1); |
| 482 | + // go into labled statements |
| 483 | + while(specifiedStmt instanceof LabeledStmt labeledStmt) { |
| 484 | + specifiedStmt = labeledStmt.getStatement(); |
| 485 | + } |
461 | 486 | if (specifiedStmt instanceof BlockStmt |
462 | 487 | || specifiedStmt instanceof NodeWithBody<?> /* aka loops */ |
463 | 488 | || specifiedStmt instanceof LabeledStmt) { |
|
0 commit comments