package function.builtin.predicate; import function.ArgumentValidator; import function.FunctionNames; import function.LispFunction; import sexpression.Cons; import sexpression.SExpression; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.regex.Matcher; import java.util.regex.Pattern; import static function.builtin.GENSYM.GENSYM_PREFIX; import static sexpression.Nil.NIL; import static sexpression.Symbol.T; @FunctionNames({ "GENSYM-EQUAL", "GENSYM-EQUAL?" }) public class GENSYM_EQUAL extends LispFunction { private ArgumentValidator argumentValidator; public GENSYM_EQUAL(String name) { this.argumentValidator = new ArgumentValidator(name); this.argumentValidator.setExactNumberOfArguments(2); } @Override public SExpression call(Cons argumentList) { argumentValidator.validate(argumentList); Cons rest = (Cons) argumentList.getRest(); SExpression firstArgument = argumentList.getFirst(); SExpression secondArgument = rest.getFirst(); return gensymEqual(firstArgument, secondArgument); } private SExpression gensymEqual(SExpression firstArgument, SExpression secondArgument) { String firstEqualized = equalizeGensyms(firstArgument); String secondEqualized = equalizeGensyms(secondArgument); return firstEqualized.equals(secondEqualized) ? T : NIL; } private String equalizeGensyms(SExpression expression) { GensymEqualizer equalizer = new GensymEqualizer(expression.toString()); return equalizer.equalize(); } private static class GensymEqualizer { private static final String GENSYM_REGEX = Pattern.quote(GENSYM_PREFIX) + "[0-9]+"; Map gensymAliases; Matcher matcher; String expression; int counter; public GensymEqualizer(String expression) { this.gensymAliases = new HashMap<>(); this.matcher = Pattern.compile(GENSYM_REGEX).matcher(expression); this.expression = expression; this.counter = 0; } public String equalize() { createGensymAliases(); return equalizeGensyms(); } private void createGensymAliases() { while (matcher.find()) createAliasForGensym(); } private void createAliasForGensym() { String gensym = matcher.group(); if (isNewGensym(gensym)) gensymAliases.put(gensym, GENSYM_PREFIX + (counter++)); } private boolean isNewGensym(String gensym) { return !gensymAliases.containsKey(gensym); } private String equalizeGensyms() { String equalizedExpression = expression; for (Entry entry : gensymAliases.entrySet()) equalizedExpression = equalizedExpression.replace(entry.getKey(), entry.getValue()); return equalizedExpression; } } }