|
|
@@ -0,0 +1,257 @@
|
|
|
+package com.example.lambda.service.interpreter.type;
|
|
|
+
|
|
|
+import com.example.lambda.service.interpreter.BasicPattern;
|
|
|
+import com.example.lambda.service.interpreter.Parser;
|
|
|
+import com.example.lambda.service.interpreter.error.ErrorType;
|
|
|
+import com.example.lambda.service.interpreter.error.InterpreterException;
|
|
|
+
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+public class AstUtils {
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 打印 Ast 树
|
|
|
+ *
|
|
|
+ * @param ast
|
|
|
+ */
|
|
|
+ public static void show(Ast ast) {
|
|
|
+ if (ast != null) show(ast, "");
|
|
|
+ else System.out.println("AstUtils.show: error occur, parse failure");
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void show(Ast ast, String prefix) {
|
|
|
+ System.out.print(prefix);
|
|
|
+ String nextPre = prefix + "| ";
|
|
|
+ int index = ast.getIndex();
|
|
|
+ if (ast instanceof Abstract) {
|
|
|
+ if (index < 0) {
|
|
|
+ System.out.println("Abstract:");
|
|
|
+ } else {
|
|
|
+ System.out.println("Abstract: index=" + index);
|
|
|
+ }
|
|
|
+ show(((Abstract) ast).getParam(), nextPre);
|
|
|
+ show(((Abstract) ast).getBody(), nextPre);
|
|
|
+ } else if (ast instanceof Application) {
|
|
|
+ System.out.println("Application:");
|
|
|
+ show(((Application) ast).getLeft(), nextPre);
|
|
|
+ show(((Application) ast).getRight(), nextPre);
|
|
|
+ } else if (ast instanceof Identifier) {
|
|
|
+ if (index < 0) {
|
|
|
+ System.out.print("Identifier");
|
|
|
+ } else {
|
|
|
+ System.out.print("Identifier: index=" + index);
|
|
|
+ }
|
|
|
+ Identifier identifier = (Identifier) ast;
|
|
|
+ System.out.println("(" +
|
|
|
+ identifier.getId() + ":" +
|
|
|
+ identifier.getName() + ")");
|
|
|
+ } else {
|
|
|
+ throw new InterpreterException("未知的 Ast 类型", index, ErrorType.UNKNOWN_TOKEN);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void showSimple(Ast ast) {
|
|
|
+ if (ast != null) showSimple(ast, "");
|
|
|
+ else System.out.println("AstUtils.show: error occur, parse failure");
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void showSimple(Ast ast, String prefix) {
|
|
|
+ System.out.print(prefix);
|
|
|
+ String nextPre = prefix + "| ";
|
|
|
+ int index = ast.getIndex();
|
|
|
+ if (ast instanceof Abstract) {
|
|
|
+ System.out.println("\\" + ((Abstract) ast).getParam().getName());
|
|
|
+ showSimple(((Abstract) ast).getBody(), nextPre);
|
|
|
+ } else if (ast instanceof Application) {
|
|
|
+ System.out.println("App:");
|
|
|
+ showSimple(((Application) ast).getLeft(), nextPre);
|
|
|
+ showSimple(((Application) ast).getRight(), nextPre);
|
|
|
+ } else if (ast instanceof Identifier) {
|
|
|
+ Identifier identifier = (Identifier) ast;
|
|
|
+ if (identifier.getId() < 0) {
|
|
|
+ System.out.println(identifier.getName());
|
|
|
+ } else {
|
|
|
+ System.out.println(identifier.getName() + ":" + identifier.getId());
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ throw new InterpreterException("未知的 Ast 类型", index, ErrorType.UNKNOWN_TOKEN);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据字面量获取对应 Ast
|
|
|
+ *
|
|
|
+ * @param name
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static Ast getConstAst(String name) {
|
|
|
+ name = name.toUpperCase();
|
|
|
+ return new Parser().parse(BasicPattern.valueOf(name).getPattern());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 转为匿名语法树
|
|
|
+ *
|
|
|
+ * @param ast
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static Ast castAnonymous(Ast ast) {
|
|
|
+ anonymousId = 0;
|
|
|
+ ctx = new ArrayList<>();
|
|
|
+ try {
|
|
|
+ return _castAnonymous(ast);
|
|
|
+ } catch (IndexOutOfBoundsException e) {
|
|
|
+ // 属于某个 Abstract 的 body(存在更外层的 id)
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static int anonymousId;
|
|
|
+ private static List<Identifier> ctx;
|
|
|
+
|
|
|
+ private static Ast _castAnonymous(Ast ast) {
|
|
|
+ if (ast instanceof Abstract) {
|
|
|
+ Abstract sample = (Abstract) ast;
|
|
|
+ Identifier param = (Identifier) _castAnonymous(sample.getParam());
|
|
|
+ ctx.add(0, param);
|
|
|
+ Ast body = _castAnonymous(sample.getBody());
|
|
|
+ ctx.remove(0);
|
|
|
+ return new Abstract(sample.getIndex(), param, body);
|
|
|
+ } else if (ast instanceof Application) {
|
|
|
+ Application sample = (Application) ast;
|
|
|
+ Ast left = _castAnonymous(sample.getLeft());
|
|
|
+ Ast right = _castAnonymous(sample.getRight());
|
|
|
+ return new Application(left, right);
|
|
|
+ } else if (ast instanceof Identifier) {
|
|
|
+ Identifier sample = (Identifier) ast;
|
|
|
+ String name = sample.getId() < 0 ? "#" + (++anonymousId) : ctx.get(sample.getId()).getName();
|
|
|
+ return new Identifier(sample.getIndex(), sample.getId(), name);
|
|
|
+ } else {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 比较两个 Ast 是否相同
|
|
|
+ *
|
|
|
+ * @param a
|
|
|
+ * @param b
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static boolean compare(Ast a, Ast b) {
|
|
|
+ String sa = castAnonymous(a).toString();
|
|
|
+ String sb = castAnonymous(b).toString();
|
|
|
+ return sa.equals(sb);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 判断 Ast 的实际类型
|
|
|
+ *
|
|
|
+ * @param ast
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static boolean isApp(Ast ast) {
|
|
|
+ return ast instanceof Application;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static boolean isAbs(Ast ast) {
|
|
|
+ return ast instanceof Abstract;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static boolean isId(Ast ast) {
|
|
|
+ return ast instanceof Identifier;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 规约后 index 无效
|
|
|
+ *
|
|
|
+ * @param ast
|
|
|
+ */
|
|
|
+ public static void clearIndex(Ast ast) {
|
|
|
+ if (isApp(ast)) {
|
|
|
+ Application app = (Application) ast;
|
|
|
+ clearIndex(app.getLeft());
|
|
|
+ clearIndex(app.getRight());
|
|
|
+ } else if (isAbs(ast)) {
|
|
|
+ Abstract abs = (Abstract) ast;
|
|
|
+ abs.setIndex(-1);
|
|
|
+ clearIndex(abs.getParam());
|
|
|
+ clearIndex(abs.getBody());
|
|
|
+ } else if (isId(ast)) {
|
|
|
+ ast.setIndex(-1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将表达式化简回字面量
|
|
|
+ *
|
|
|
+ * @param ast
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static Ast abbreviate(Ast ast) {
|
|
|
+ if (constMapper == null) {
|
|
|
+ constMapper = new HashMap<>();
|
|
|
+ for (BasicPattern basicPattern : BasicPattern.values()) {
|
|
|
+ Ast constAst = new Parser().parse(basicPattern.getPattern());
|
|
|
+ constAst = castAnonymous(constAst);
|
|
|
+ constMapper.put(constAst.toString(), basicPattern.name());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return _abbreviate(castAnonymous(ast));
|
|
|
+ }
|
|
|
+
|
|
|
+ private static Map<String, String> constMapper;
|
|
|
+
|
|
|
+ private static Ast _abbreviate(Ast ast) {
|
|
|
+ if (isApp(ast)) {
|
|
|
+ Application app = (Application) ast;
|
|
|
+ return new Application(
|
|
|
+ _abbreviate(app.getLeft()),
|
|
|
+ _abbreviate(app.getRight())
|
|
|
+ );
|
|
|
+ } else if (isAbs(ast)) {
|
|
|
+ Ast anonymous = castAnonymous(ast);
|
|
|
+ String pattern;
|
|
|
+ if (anonymous != null && constMapper.containsKey(pattern = anonymous.toString())) {
|
|
|
+// return new Const(-1, constMapper.get(pattern));
|
|
|
+ return new Identifier(-1, -1, constMapper.get(pattern));
|
|
|
+ }
|
|
|
+ Abstract abs = (Abstract) ast;
|
|
|
+ return new Abstract(
|
|
|
+ abs.getIndex(),
|
|
|
+ abs.getParam(),
|
|
|
+ _abbreviate(abs.getBody())
|
|
|
+ );
|
|
|
+ }
|
|
|
+ return ast;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 自然数 Ast 转 int,不是自然数则返回 -1
|
|
|
+ *
|
|
|
+ * @param ast
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static int toInt(Ast ast) {
|
|
|
+ if (isAbs(ast)) {
|
|
|
+ ast = ((Abstract) ast).getBody(); // \f.?
|
|
|
+ if (isAbs(ast)) {
|
|
|
+ ast = ((Abstract) ast).getBody(); // \f.\x.?
|
|
|
+ int num = 0;
|
|
|
+ while (!isId(ast)) {
|
|
|
+ if (!isApp(ast)) return -1;
|
|
|
+ Ast left = ((Application) ast).getLeft();
|
|
|
+ if (!isId(left) || ((Identifier) left).getId() != 1) return -1;
|
|
|
+ ast = ((Application) ast).getRight();
|
|
|
+ num += 1;
|
|
|
+ }
|
|
|
+ if (((Identifier) ast).getId() == 0) return num;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+}
|