共计 11743 个字符,预计需要花费 30 分钟才能阅读完成。
Symbols
public interface Symbols {static Symbols of(String name) {return new SimpleSymbols(name);
}
String getName();
@Value
class SimpleSymbols implements Symbols {
String name;
@Override
public String toString() {return "`" + name;}
}
}
Strings
public interface Strings {static Strings of(String str) {return new SimpleStr(str);
}
String getString();
@Value
class SimpleStr implements Strings {
String string;
@Override
public String toString() {return "'"+ string+"'";}
}
}
Cons
@RequiredArgsConstructor(staticName = "of")
public class Cons implements Iterable<Object> {
private final List<Object> data;
private final Cons parent;
private final boolean exp;
public static Cons newInstance(Cons parent) {return Cons.of(new ArrayList<>(), parent, true);
}
public void add(Object obj) {data.add(obj);
}
public Object car() {return iterator().next();}
public Cons carCons() {return (Cons) car();}
public Symbols carSymbols() {return (Symbols) car();}
public Cons cdr() {return Cons.of(data.subList(1, data.size() ), this,false);
}
public Collection<Object> data() {return Collections.unmodifiableList(data);
}
public Cons parent() {return parent;}
public boolean isExp() {return exp;}
public boolean isEmpty(){return data.isEmpty();
}
@Override
public Iterator<Object> iterator() {return data.iterator();
}
@Override
public String toString() {Optional<String> reduce = data.stream().map(Object::toString).reduce((x, y) -> x + "" + y).map(o ->"("+ o +")");
return reduce.orElse("()");
}
}
Parse
@Slf4j
public class Parse {
private static final String PREFIX = "(";
private static final String SUFFIX = ")";
public static Cons parse(String expStr) {return parse(format(replaceSpace(expStr)), Cons.newInstance(null));
}
private static Cons parse(String expStr, Cons r) {String tempExpStr = expStr.trim();
boolean isPush = tempExpStr.indexOf(PREFIX) == 0;
String nextStr = tempExpStr.substring(1);
int prefixIndex2 = nextStr.indexOf(PREFIX);
int suffixIndex2 = nextStr.indexOf(SUFFIX);
int nextFixIndex = (prefixIndex2==-1||suffixIndex2==-1? Math.max(prefixIndex2,suffixIndex2):Math.min(prefixIndex2, suffixIndex2) );
if(nextFixIndex>-1){if (isPush) {Cons astList = Cons.newInstance(r);
String subExpStr = nextStr.substring(0, nextFixIndex);
exp2List(subExpStr).forEach(astList::add);
r.add(astList);
return parse(tempExpStr.substring(nextFixIndex+1), astList);
} else {String subExpStr = nextStr.substring(0, nextFixIndex);
exp2List(subExpStr).forEach(r.parent()::add);
return parse(tempExpStr.substring(nextFixIndex+1), r.parent());
}
}else{return r;}
}
private static List<Object> exp2List(String exp){return exp.trim().length()==0? Collections.emptyList(): Arrays.stream(exp.trim().split(" ")).map(Parse::parseObj).collect(Collectors.toList());
}
private static String format(String str) {return str.contains("") ? format(str.replaceAll(" "," ")) : str;
}
private static String replaceSpace(String str){if(str.contains("'")){int first = str.indexOf("'");
int last = str.substring(first+1).indexOf("'")+first+1;
String substring = str.substring(first, last + 1);
substring = substring.replaceAll("","\\\\\\O");
return str.substring(0, first) + substring + replaceSpace(str.substring(last + 1));
}
return str;
}
private static Object parseObj(String atom){
try {return Integer.valueOf(atom);
} catch (NumberFormatException e) {if (atom.equals("true") || atom.equals("false")) {return Boolean.valueOf(atom);
} else if (atom.indexOf("'") == 0 && atom.lastIndexOf("'") == atom.length() - 1) {return Strings.of(atom.replaceAll("'","").replaceAll("\\\\O", " "));
} else {return Symbols.of(atom);
}
}
}
public static void main(String[] args) {log.debug("{}", (parse("(1 2 3 4 5 6 7 (8 9 10) 11 12 (13 (14 15)) 16 true's 5 8''456' a b c (7 8 9))")));
log.debug("{}", parse("(let ((cons (lambda (x y) (lambda (g) (g x y (lambda (a) (set! x a)) (lambda (a) (set! y a)))))) (car (lambda (f) (f (lambda (x y sx sy) (x))))) (cdr (lambda (f) (f (lambda (x y sx sy) (y))))) (set-car! (lambda (f a) (f (lambda (x y sx sy) ((sx a) f))))) (set-cdr! (lambda (f a) (f (lambda (x y sx sy) ((sy a) f)))))) (cdr (set-cdr! (cons 1 2) 3)))"));
}
}
Env
public class Env {private final Map<String, Object> env = new HashMap<>();
private Env parent;
public static Env newInstance(Env parent) {Env env1 = new Env();
env1.parent = parent;
return env1;
}
public void setEnv(Symbols symbols, Object val) {setEnv(symbols.getName(),val);
}
public void setEnv(String key, Object val) {env.put(key, val);
}
public Optional<Object> env(Symbols symbols) {String symbolsName = symbols.getName();
return Optional.ofNullable(env.containsKey(symbolsName) ? env.get(symbolsName) : (parent != null ? parent.env(symbols).orElse(null) : null));
}
public boolean contains(Symbols symbols){return env.containsKey(symbols.getName());
}
public Env parent(){return parent;}
}
JLispInterpreter3
@Slf4j
public class JLispInterpreter3 {
private static final Predicate<Object> IS_EXP = o -> o instanceof Cons;
private static final Predicate<Object> IS_SYMBOLS = o -> o instanceof Symbols;
private static final Predicate<Object> IS_FUN = o -> o instanceof Function;
private static final Predicate<Object> IS_ATOM = o -> o instanceof Number || o instanceof String || o instanceof Boolean;
private static final BiPredicate<Cons, Object> CAN_APPLY = (exp, v) -> IS_FUN.test(v) && exp.isExp();
public static Object eval(String exp) {Env root = Env.newInstance(null);
FunManager.FUNCTIONAL.forEach(root::setEnv);
return eval(Parse.parse(exp), Env.newInstance(root));
}
private static Object eval(Cons exp, Env env) {Object car = exp.car();
Cons cdr = exp.cdr();
if (IS_EXP.test(car)) {Object v = eval(exp.carCons(), env);
if (CAN_APPLY.test(exp, v)) {return apply(v, cdr, env);
}
return cdr.isEmpty() ? v : eval(cdr, env);
} else if (IS_SYMBOLS.test(car)) {Object v = env.env(exp.carSymbols()).orElseThrow(() -> new IllegalArgumentException(exp.parent() + ":" + exp.carSymbols() + "not define"));
if (CAN_APPLY.test(exp, v)) {return apply(v, cdr, env);
}
return cdr.isEmpty() ? v : eval(cdr, env);
} else if (IS_ATOM.test(car)) {return cdr.isEmpty() ? car : eval(cdr, env);
} else {return cdr.isEmpty() ? car : eval(cdr, env);
}
}
private static Object apply(Object v, Cons cdr, Env env) {return ((Function<ApplyArgs, Object>) v).apply(ApplyArgs.of(cdr, env, () -> cdr.data().stream().map(o -> getAtom(o, cdr, env)).toArray(), JLispInterpreter3::eval));
}
private static Object getAtom(Object o, Cons exp, Env env) {if (IS_EXP.test(o)) {return eval((Cons) o, env);
} else if (IS_SYMBOLS.test(o)) {return eval(toSubCons(o, exp), env);
} else {return o;}
}
private static Cons toSubCons(Object obj, Cons parent) {return Cons.of(Collections.singletonList(obj),parent, false);
}
@Value(staticConstructor = "of")
public static class ApplyArgs {
Cons exp;
Env env;
Supplier<Object[]> lazyArgs;
BiFunction<Cons, Env, Object> eval;
}
}
FunManager
class FunManager{private static final Map<String, Function<ApplyArgs, Object>> FUNCTIONAL = new ConcurrentHashMap<>();
static {reg("+", applyArgs -> toIntStream(applyArgs.getLazyArgs()).reduce(Integer::sum).orElse(null));
reg("-", applyArgs -> toIntStream(applyArgs.getLazyArgs()).reduce((a, b) -> a - b).orElse(null));
reg("*", applyArgs -> toIntStream(applyArgs.getLazyArgs()).reduce((a, b) -> a * b).orElse(null));
reg("/", applyArgs -> toIntStream(applyArgs.getLazyArgs()).reduce((a, b) -> a / b).orElse(null));
reg("lambda", applyArgs -> lambda(applyArgs.getExp(), applyArgs.getEnv()));
reg("define", FunManager::define);
reg("let", applyArgs -> let(applyArgs.getExp(), applyArgs.getEnv(), applyArgs.getEval()));
reg("set!", applyArgs -> set(applyArgs.getExp(), applyArgs.getEnv(), applyArgs.getEval()));
reg("apply", applyArgs -> apply0(applyArgs.getExp(), applyArgs.getEnv()));
regBooleanFun();
reg("if", applyArgs -> if0(applyArgs.getExp(), applyArgs.getEnv(), applyArgs.getEval()));
reg("cond", applyArgs -> cond(applyArgs.getExp(), applyArgs.getEnv(), applyArgs.getEval()));
}
private static void reg(String optKey, Function<ApplyArgs, Object> opt) {FUNCTIONAL.put(optKey, opt);
}
private static Function<ApplyArgs, Object> lambda(Cons cdr, Env env) {return (applyArgs) -> {Object[] x = applyArgs.getLazyArgs().get();
Cons args = cdr.carCons();
Cons body = cdr.cdr();
validateTrue(args.data().size() == x.length, "参数不统一");
Env env0 = Env.newInstance(env);
int i = 0;
for (Object argName : args) {env0.setEnv(((Symbols) argName), x[i]);
i++;
}
return applyArgs.getEval().apply(body, env0);
};
}
private static Object if0(Cons cdr, Env env, BiFunction<Cons, Env, Object> eval) {Cons car = cdr.carCons();
if (isaBoolean(eval.apply(car, env))) {Object then = cdr.cdr().car();
return getAtom(then, cdr.cdr(), env);
} else {if (cdr.cdr().cdr().data().size() > 0) {return eval.apply(cdr.cdr().cdr(), env);
}
return null;
}
}
private static Object cond(Cons cdr, Env env, BiFunction<Cons, Env, Object> eval){Cons car = cdr.carCons();
Cons predicateExp = car.carCons();
Cons body = car.cdr();
if(isaBoolean(eval.apply(predicateExp, env))){return eval.apply(body, env);
}else{Cons elseCdr = cdr.cdr();
if(elseCdr.data().size()==1){
// 去掉括號
while (IS_EXP.test(elseCdr.car())&&elseCdr.data().size()==1){elseCdr = elseCdr.carCons();
}
validateTrue(IS_SYMBOLS.test(elseCdr.car())&&elseCdr.carSymbols().getName().equals("else"),"cond last item not else key");
return eval.apply(elseCdr.cdr(), env);
}
return cond(elseCdr, env, eval);
}
}
private static Object define(ApplyArgs applyArgs) {Cons cdr = applyArgs.getExp();
Object val = applyArgs.eval.apply(cdr.cdr(), applyArgs.getEnv());
validateTrue(!applyArgs.getEnv().contains(cdr.carSymbols()), "Do not repeat the definition" + cdr.carSymbols());
applyArgs.getEnv().setEnv(cdr.carSymbols(), val);
return null;
}
private static Object let(Cons cdr, Env env, BiFunction<Cons, Env, Object> eval) {Object car0 = cdr.car();
validateTrue(car0 instanceof Cons && cdr.data().size() == 2, "please check" + car0);
Env env0 = Env.newInstance(env);
Cons car = cdr.carCons();
Cons body = cdr.cdr().carCons();
for (Object con : car) {validateTrue(IS_EXP.test(con), "please check" + con);
Cons item = (Cons) con;
Symbols var = item.carSymbols();
validateTrue(!env0.contains(var), "Do not repeat the let" + var);
env0.setEnv(var, eval.apply(item.cdr(), env));
}
return eval.apply(body, env0);
}
private static Object set(Cons cdr,Env env, BiFunction<Cons, Env, Object> eval) {Symbols var = cdr.carSymbols();
Object val = eval.apply(cdr.cdr(),env);
validateTrue(env.env(var).isPresent(), "not definition set! error" + var);
Env envParent = env;
while (!envParent.contains(var)) {envParent = envParent.parent();
}
envParent.setEnv(var, val);
return null;
}
private static Object apply0(Cons cdr, Env env) {Object f = cdr.car();
f = getAtom(f, cdr, env);
if (IS_FUN.test(f)) {return apply(f, cdr.cdr(), env);
} else {throw new IllegalArgumentException("apply" + cdr);
}
}
private static void validateTrue(boolean flag, String err) {if (!flag) {throw new IllegalArgumentException(err);
}
}
private static void regBooleanFun() {
reg("and", applyArgs -> {Object[] ts = applyArgs.getLazyArgs().get();
return Stream.of(ts).allMatch(FunManager::isaBoolean) ? ts[ts.length - 1] : false;
});
reg("or", applyArgs -> Stream.of(applyArgs.getLazyArgs().get()).filter(FunManager::isaBoolean).findFirst().orElse(false));
reg("not", applyArgs -> {Object[] ts = applyArgs.getLazyArgs().get();
validateTrue(ts.length == 1, applyArgs.getExp() + "not args only one");
return !isaBoolean(ts[0]);
});
reg("<", applyArgs -> predicate(applyArgs.getExp(), applyArgs.getLazyArgs(), (x, y) -> (x instanceof Integer && y instanceof Integer) ? (Integer) x < (Integer) y : x.toString().length() < y.toString().length()));
reg("<=", applyArgs -> predicate(applyArgs.getExp(), applyArgs.getLazyArgs(), (x, y) -> (x instanceof Integer && y instanceof Integer) ? (Integer) x <= (Integer) y : x.toString().length() <= y.toString().length()));
reg("=", applyArgs -> predicate(applyArgs.getExp(), applyArgs.getLazyArgs(), Object::equals));
reg("!=", applyArgs -> predicate(applyArgs.getExp(), applyArgs.getLazyArgs(), (x, y) -> !x.equals(y)));
reg(">", applyArgs -> predicate(applyArgs.getExp(), applyArgs.getLazyArgs(), (x, y) -> (x instanceof Integer && y instanceof Integer) ? (Integer) x > (Integer) y : x.toString().length() > y.toString().length()));
reg(">=", applyArgs -> predicate(applyArgs.getExp(), applyArgs.getLazyArgs(), (x, y) -> (x instanceof Integer && y instanceof Integer) ? (Integer) x >= (Integer) y : x.toString().length() >= y.toString().length()));
}
private static Object predicate(Cons exp, Supplier<Object[]> lazyArgs, BiPredicate<Object, Object> predicates) {Object[] objs = lazyArgs.get();
validateTrue(objs.length > 1, exp + "args qty > 1");
Object o = objs[0];
for (int i = 1; i < objs.length; i++) {Object o1 = objs[i];
boolean b = predicates.test(o, o1);
if (!b) {return b;}
o = o1;
}
return true;
}
private static boolean isaBoolean(Object o) {if (o instanceof Boolean) {return (Boolean) o;
} else {return !o.equals(0);
}
}
private static Stream<Integer> toIntStream(Supplier<Object[]> supplierObjs) {return Stream.of(supplierObjs.get()).map(Object::toString).map(Integer::valueOf).collect(Collectors.toList()).stream();}
}
正文完