diff options
| author | Elizabeth Hunt <me@liz.coffee> | 2026-02-21 12:29:54 -0800 |
|---|---|---|
| committer | Elizabeth Hunt <me@liz.coffee> | 2026-02-21 12:29:54 -0800 |
| commit | 170f5c496054c9c5c2df9b8a1c5c8df7643ea004 (patch) | |
| tree | 1ed217130939a04234761d54ba2ec607866f51ad /core/src/main/java/coffee/liz/lambda/format | |
| parent | d6a294e14604aecd9046cbc19dc1837ca694fbb0 (diff) | |
| download | the-abstraction-engine-java-main.tar.gz the-abstraction-engine-java-main.zip | |
Diffstat (limited to 'core/src/main/java/coffee/liz/lambda/format')
| -rw-r--r-- | core/src/main/java/coffee/liz/lambda/format/ValueEmitter.java | 58 |
1 files changed, 49 insertions, 9 deletions
diff --git a/core/src/main/java/coffee/liz/lambda/format/ValueEmitter.java b/core/src/main/java/coffee/liz/lambda/format/ValueEmitter.java index 337beed..2c844c9 100644 --- a/core/src/main/java/coffee/liz/lambda/format/ValueEmitter.java +++ b/core/src/main/java/coffee/liz/lambda/format/ValueEmitter.java @@ -54,24 +54,39 @@ public final class ValueEmitter { private static ProgramFragment emitClosure(final Environment env, final String parameter, final Expression body, final NameGenerator nameGenerator) { - final LinkedHashMap<String, Supplier<Value>> captures = captures(env); + final Expression sanitizedBody = sanitizeExpression(body); + final Set<String> referencedNames = freeIdentifiers(sanitizedBody, Set.of(parameter)); + final LinkedHashMap<String, Supplier<Value>> captures = captures(env, referencedNames); if (captures.isEmpty()) { - return new ProgramFragment(List.of(), abstraction(parameter, sanitizeExpression(body))); + return new ProgramFragment(List.of(), abstraction(parameter, sanitizedBody)); } - final Set<String> reservedNames = collectIdentifiers(body); + final Set<String> reservedNames = collectIdentifiers(sanitizedBody); final Map<String, ProgramFragment> captureFragments = new LinkedHashMap<>(); + final Set<String> reservedMacroNames = new HashSet<>(); for (final Map.Entry<String, Supplier<Value>> capture : captures.entrySet()) { final ProgramFragment fragment = toProgramFragment(capture.getValue().get(), nameGenerator); captureFragments.put(capture.getKey(), fragment); reservedNames.addAll(collectIdentifiers(fragment.expression())); - fragment.macros().forEach(macro -> reservedNames.add(macro.name())); + fragment.macros().forEach(macro -> { + reservedNames.add(macro.name()); + reservedMacroNames.add(macro.name()); + }); } final Map<String, String> renamedCaptures = new HashMap<>(); + final Set<String> chosenCaptureNames = new HashSet<>(); for (final String captureName : captures.keySet()) { - final String generated = nameGenerator.freshCaptureName(reservedNames); + final boolean clashes = reservedMacroNames.contains(captureName) || chosenCaptureNames.contains(captureName); + if (!clashes) { + renamedCaptures.put(captureName, captureName); + chosenCaptureNames.add(captureName); + continue; + } + + final String generated = nameGenerator.freshCaptureName(reservedNames, chosenCaptureNames); reservedNames.add(generated); + chosenCaptureNames.add(generated); renamedCaptures.put(captureName, generated); } @@ -85,18 +100,43 @@ public final class ValueEmitter { final Set<String> bound = new HashSet<>(); bound.add(parameter); - final Expression rewrittenBody = renameFreeIdentifiers(sanitizeExpression(body), renamedCaptures, bound); + final Expression rewrittenBody = renameFreeIdentifiers(sanitizedBody, renamedCaptures, bound); return new ProgramFragment(macros, abstraction(parameter, rewrittenBody)); } - private static LinkedHashMap<String, Supplier<Value>> captures(final Environment env) { + private static LinkedHashMap<String, Supplier<Value>> captures(final Environment env, + final Set<String> referencedNames) { final LinkedHashMap<String, Supplier<Value>> captures = new LinkedHashMap<>(); for (final Environment.BindingFrame frame : env.bindingFrames()) { + if (!referencedNames.contains(frame.name())) { + continue; + } captures.putIfAbsent(frame.name(), frame.value()); } return captures; } + private static Set<String> freeIdentifiers(final Expression expression, final Set<String> boundNames) { + return switch (expression) { + case IdentifierExpression(var _, var _, String name) -> { + if (boundNames.contains(name)) { + yield Set.of(); + } + yield Set.of(name); + } + case ApplicationExpression(var _, var _, Expression applicable, Expression argument) -> { + final Set<String> free = new HashSet<>(freeIdentifiers(applicable, boundNames)); + free.addAll(freeIdentifiers(argument, boundNames)); + yield free; + } + case AbstractionExpression(var _, var _, String parameter, Expression body) -> { + final Set<String> nestedBound = new HashSet<>(boundNames); + nestedBound.add(parameter); + yield freeIdentifiers(body, nestedBound); + } + }; + } + private static Expression renameFreeIdentifiers(final Expression expression, final Map<String, String> renameMap, final Set<String> boundNames) { return switch (expression) { @@ -165,11 +205,11 @@ public final class ValueEmitter { private static final class NameGenerator { private int nextCapture = 0; - private String freshCaptureName(final Set<String> reservedNames) { + private String freshCaptureName(final Set<String> reservedNames, final Set<String> chosenNames) { String candidate; do { candidate = "_cap" + nextCapture++; - } while (reservedNames.contains(candidate)); + } while (reservedNames.contains(candidate) || chosenNames.contains(candidate)); return candidate; } } |
