aboutsummaryrefslogtreecommitdiff
path: root/core/src/main/java/coffee/liz/lambda
diff options
context:
space:
mode:
authorElizabeth Hunt <me@liz.coffee>2026-02-21 12:29:54 -0800
committerElizabeth Hunt <me@liz.coffee>2026-02-21 12:29:54 -0800
commit170f5c496054c9c5c2df9b8a1c5c8df7643ea004 (patch)
tree1ed217130939a04234761d54ba2ec607866f51ad /core/src/main/java/coffee/liz/lambda
parentd6a294e14604aecd9046cbc19dc1837ca694fbb0 (diff)
downloadthe-abstraction-engine-java-170f5c496054c9c5c2df9b8a1c5c8df7643ea004.tar.gz
the-abstraction-engine-java-170f5c496054c9c5c2df9b8a1c5c8df7643ea004.zip
Diffstat (limited to 'core/src/main/java/coffee/liz/lambda')
-rw-r--r--core/src/main/java/coffee/liz/lambda/format/ValueEmitter.java58
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;
}
}