|
16 | 16 | import liquidjava.processor.context.GhostState; |
17 | 17 | import liquidjava.processor.context.RefinedVariable; |
18 | 18 | import spoon.reflect.declaration.CtEnum; |
19 | | -import spoon.reflect.declaration.CtType; |
20 | 19 | import spoon.reflect.reference.CtTypeReference; |
21 | 20 |
|
22 | 21 | public class TranslatorContextToZ3 { |
23 | 22 |
|
24 | 23 | static void translateVariables(Context z3, Map<String, CtTypeReference<?>> ctx, |
25 | | - Map<String, Expr<?>> varTranslation) { |
26 | | - |
| 24 | + Map<String, Expr<?>> varTranslation) { |
| 25 | + // Translates all variables into z3 expressions, creating EnumSorts once per unique enum type. |
27 | 26 | Map<String, EnumSort<?>> enumSorts = new HashMap<>(); |
28 | | - translateEnums(z3, ctx, varTranslation, enumSorts); |
29 | | - translateNonEnumVariables(z3, ctx, varTranslation, enumSorts); |
30 | | - |
31 | | - varTranslation.put("true", z3.mkBool(true)); |
32 | | - varTranslation.put("false", z3.mkBool(false)); |
33 | | - } |
34 | 27 |
|
35 | | - private static void translateEnums(Context z3, Map<String, CtTypeReference<?>> ctx, |
36 | | - Map<String, Expr<?>> varTranslation, Map<String, EnumSort<?>> enumSorts) { |
37 | | - // First pass: create one EnumSort per enum type and store actual enum constants |
38 | 28 | for (Map.Entry<String, CtTypeReference<?>> entry : ctx.entrySet()) { |
| 29 | + String name = entry.getKey(); |
39 | 30 | CtTypeReference<?> type = entry.getValue(); |
40 | | - if (!type.isEnum()) |
41 | | - continue; |
42 | | - String typeName = type.getQualifiedName(); |
43 | | - if (enumSorts.containsKey(typeName)) |
| 31 | + |
| 32 | + if (varTranslation.containsKey(name)) continue; |
| 33 | + |
| 34 | + if (type.isEnum() && type.getDeclaration() instanceof CtEnum<?> enumDecl) { |
| 35 | + EnumSort<?> enumSort = translateEnum(z3, varTranslation, enumSorts, type, enumDecl); |
| 36 | + // translateEnum may have already registered name as a literal constant |
| 37 | + // (e.g. Mode.Photo), no need to overwrite |
| 38 | + if (!varTranslation.containsKey(name)) |
| 39 | + varTranslation.put(name, z3.mkConst(name, enumSort)); |
44 | 40 | continue; |
45 | | - CtType<?> decl = type.getDeclaration(); |
46 | | - if (decl instanceof CtEnum<?> enumDecl) { |
47 | | - String[] enumValueNames = enumDecl.getEnumValues().stream().map(ev -> ev.getSimpleName()) |
48 | | - .toArray(String[]::new); |
49 | | - EnumSort<?> enumSort = z3.mkEnumSort(typeName, enumValueNames); |
50 | | - enumSorts.put(typeName, enumSort); |
51 | | - |
52 | | - // Store actual enum constant values (not free variables) |
53 | | - Expr<?>[] consts = enumSort.getConsts(); |
54 | | - for (int i = 0; i < enumValueNames.length; i++) { |
55 | | - String varName = enumDecl.getSimpleName() + "." + enumValueNames[i]; |
56 | | - varTranslation.put(varName, consts[i]); |
57 | | - } |
58 | 41 | } |
| 42 | + varTranslation.put(name, getExpr(z3, name, type)); |
59 | 43 | } |
| 44 | + |
| 45 | + varTranslation.put("true", z3.mkBool(true)); |
| 46 | + varTranslation.put("false", z3.mkBool(false)); |
60 | 47 | } |
61 | 48 |
|
62 | | - private static void translateNonEnumVariables(Context z3, Map<String, CtTypeReference<?>> ctx, |
63 | | - Map<String, Expr<?>> varTranslation, Map<String, EnumSort<?>> enumSorts) { |
64 | | - // Second pass: translate non-enum variables and enum-typed variables (not constants) |
65 | | - for (Map.Entry<String, CtTypeReference<?>> entry : ctx.entrySet()) { |
66 | | - String name = entry.getKey(); |
67 | | - if (varTranslation.containsKey(name)) |
68 | | - continue; // Already translated as an enum constant |
69 | | - CtTypeReference<?> type = entry.getValue(); |
70 | | - if (type.isEnum()) { |
71 | | - String typeName = type.getQualifiedName(); |
72 | | - EnumSort<?> enumSort = enumSorts.get(typeName); |
73 | | - varTranslation.put(name, z3.mkConst(name, enumSort)); |
74 | | - } else { |
75 | | - varTranslation.put(name, getExpr(z3, name, type)); |
76 | | - } |
77 | | - } |
| 49 | + private static EnumSort<?> translateEnum(Context z3, Map<String, Expr<?>> varTranslation, Map<String, EnumSort<?>> enumSorts, CtTypeReference<?> type, CtEnum<?> enumDecl) { |
| 50 | + // Creates (and caches if needed) a z3 EnumSort for a given enum type. Registers enum literal constants |
| 51 | + // on first creation. |
| 52 | + return enumSorts.computeIfAbsent(type.getQualifiedName(), k -> { |
| 53 | + String[] enumValueNames = enumDecl.getEnumValues().stream() |
| 54 | + .map(ev -> ev.getSimpleName()).toArray(String[]::new); |
| 55 | + EnumSort<?> enumSort = z3.mkEnumSort(k, enumValueNames); |
| 56 | + Expr<?>[] consts = enumSort.getConsts(); |
| 57 | + for (int i = 0; i < enumValueNames.length; i++) |
| 58 | + varTranslation.put(enumDecl.getSimpleName() + "." + enumValueNames[i], consts[i]); |
| 59 | + return enumSort; |
| 60 | + }); |
78 | 61 | } |
79 | 62 |
|
80 | 63 | public static void storeVariablesSubtypes(Context z3, List<RefinedVariable> variables, |
|
0 commit comments