Added enum types and verification#168
Conversation
Added a test for enums to, in the future, help clean the refinement message.
| ID_UPPER '(' args? ')'; | ||
|
|
||
| enumCall: | ||
| OBJECT_TYPE; |
There was a problem hiding this comment.
I understand you used OBJECT_TYPE because of the rule ambiguity. However, this raises a concern, because it allows for multiple chaining of ids (e.g., Mode.photo.photo, Mode.photo.photo.photo, etc.) which should not be syntactically valid.
We could avoid the ambiguity by forcing the OBJECT_TYPE to always start with a lowercase letter and declare enumCall as ID '.' ID, but Java packages are allowed start with an uppercase letter (even though it's highly discouraged).
So, we can introduce another terminal, just for enums:
enumCall:
ENUM_CALL;
// ...
ENUM_CALL: [a-zA-Z_][a-zA-Z0-9_]* '.' [a-zA-Z_][a-zA-Z0-9_]*;
This way, you guarantee the enums are always represented by two ids separated by a dot, without ambiguity.
There was a problem hiding this comment.
That's understandable, my issue with that, at the time of development, was if ID and ID_UPPER wouldn't, even if they are slightly different, lead to ambiguity due to other grammar rules. I should've explored more formats.
| private String enumCreate(EnumContext rc) { | ||
| String enumText = rc.enumCall().getText(); | ||
| int lastDot = enumText.lastIndexOf('.'); | ||
| String enumClass = enumText.substring(0, lastDot); | ||
| String enumConst = enumText.substring(lastDot + 1); | ||
| String varName = String.format(Formats.ENUM_VALUE, enumClass, enumConst); | ||
| return varName; |
There was a problem hiding this comment.
I don't like the "enum#%s#%s" format because it's hard to read in the error messages. Here you can simply return the enumText, and everywhere else still use this format but change it to "%s.%s" instead.
There was a problem hiding this comment.
I should've gone with a better format, I admit. I wasn't sure due to the rest of the existing types.
| return new Var(((VarContext) rc).ID().getText()); | ||
|
|
||
| else if (rc instanceof EnumContext) { | ||
| return new Var(enumCreate((EnumContext) rc)); |
There was a problem hiding this comment.
I don't think the enums should be represented as variables. They should have its own AST node and also its own representation in the context.
| String varName = String.format(Formats.ENUM_VALUE, enumName, ev.getSimpleName()); | ||
| Predicate refinement = Predicate.createEquals(Predicate.createVar(varName), | ||
| Predicate.createLit(String.valueOf(ordinal), Types.INT)); | ||
| context.addGlobalVariableToContext(varName, qualifiedEnumName, enumRead.getReference(), refinement); |
There was a problem hiding this comment.
Why global? Shouldn't it only be visible within the class or package where it was declared?
There was a problem hiding this comment.
If there is an enum that is used across methods, and a shared package is needed, when the context is reinitialized, the local context is cleaned. If it's kept in the global context, the placement is irrelevant.
For example, the following common package a layer above the testSuite.
When line 134 is changed to context.addVarToContext(varName, enumRead.getReference(), refinement, enumRead), the following occurs:
There was a problem hiding this comment.
That's not really a shared package because it's not even included in the verification, each test is ran individually from its file or folder.
There was a problem hiding this comment.
The issue is: if I declare an enum X in class A, should I be able to use it in class B? It might be fine, just raising some questions about how it should work.
There was a problem hiding this comment.
Also, if we can use enums from different classes, we should make sure they have their fully qualified name to distinguish enums with the same name from different classes.
There was a problem hiding this comment.
I didn't realize the testing was that restrictive. I can try and create some test scenarios that take into consideration global and local context. The other option would be to restrict enum verification to only in the same file, but that feels like a cop-out instead of an actual fix/intended functionality. 🤔
| public static final String INSTANCE = "#%s_%d"; | ||
| public static final String THIS = "this#%s"; | ||
| public static final String RET = "#ret_%d"; | ||
| public static final String ENUM_VALUE = "enum#%s#%s"; |
There was a problem hiding this comment.
| public static final String ENUM_VALUE = "enum#%s#%s"; | |
| public static final String ENUM = "%s.%s"; |
| case "java.lang.Enum" -> z3.mkIntConst(name); | ||
| default -> { | ||
| if (type.isEnum()) | ||
| yield z3.mkIntConst(name); | ||
| yield z3.mkConst(name, z3.mkUninterpretedSort(typeName)); | ||
| } |
There was a problem hiding this comment.
Converting the enums to integers is makes sense, but we can improve it. Instead, we can use the Z3 EnumSort, so the error messages and the counterexamples show the enum values instead of the integers they represent, which I can help you with.
| int ordinal = 0; | ||
| for (CtEnumValue ev : enumRead.getEnumValues()) { |
There was a problem hiding this comment.
Using a traditional for loop here might be a good idea, but that's also fine. Also, you should use CtEnumValue<?> here.
Created AST node and visitors for enums. Changed grammar as suggested to specific rules and positioning to avoid ambiguity. Changed format.
|
Currently every test file/folder is verified completely isolated from one another. Everything needed for it should be in the corresponding file/folder, even if that means unwanted repetition. |

This would fix #23 with the addition of enum types and verifications.
The grammar was implemented taking into consideration the concerns of verbosity and ambiguity. The solution developed uses a
Enum.Valueformat, asValueformats were failing due to ambiguity. This was discussed briefly with @rcosta358 in regards to using something likeenum()instead, but it was found a bit too off/verbose.The default branch in
TranslatorContextToZ3was changed.Enumtypes fall into a sort-of fallback option due to being treated as anOBJECT_TYPE. By checking if the type is, in fact, an enum, other cases can fall intomkUninterpretedSort.The field metadata is inserted similarly to other types, but with a specific format (
ENUM_VALUE).Treating an enum as an
OBJECT_TYPEis the main "issue" I'm having, as it looks as though it's being treated as a fallback approach due to dot consumption early on. However, this might be my lack of experience.Another visual issue that I had was the
Refinement Errormessage (as shown inEnumRefinementMessage), as it's not clear enough as to why the refinement failed.