优化打印逻辑

This commit is contained in:
Luke 2025-04-27 11:46:42 +08:00
parent fd38c94b3d
commit 4df44686e7

View File

@ -5,190 +5,179 @@ import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
import org.jcnc.snow.compiler.parser.ast.base.Node; import org.jcnc.snow.compiler.parser.ast.base.Node;
import java.util.List; import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* 更加健壮完整的 AST -> JSON 序列化器
*/
public class ASTJsonSerializer { public class ASTJsonSerializer {
public static String toJsonString(List<Node> ast) { public static String toJsonString(List<Node> ast) {
return listToJsonArray(ast.stream().map(ASTJsonSerializer::nodeToJson).toList()); return ast.stream()
.map(ASTJsonSerializer::nodeToJson)
.collect(Collectors.joining(",", "[", "]"));
} }
private static String nodeToJson(Node n) { private static String nodeToJson(Node n) {
if (n instanceof ModuleNode m) return moduleToJson(m); return switch (n) {
if (n instanceof FunctionNode f) return functionToJson(f); case ModuleNode m -> moduleToJson(m);
if (n instanceof DeclarationNode d) return declarationToJson(d); case FunctionNode f -> functionToJson(f);
if (n instanceof AssignmentNode a) return assignmentToJson(a); case DeclarationNode d -> declarationToJson(d);
if (n instanceof IfNode i) return ifToJson(i); case AssignmentNode a -> assignmentToJson(a);
if (n instanceof LoopNode l) return loopToJson(l); case IfNode i -> ifToJson(i);
if (n instanceof ReturnNode r) return returnToJson(r); case LoopNode l -> loopToJson(l);
if (n instanceof ExpressionStatementNode e) return exprStmtToJson(e); case ReturnNode r -> returnToJson(r);
return simpleTypeJson(n.getClass().getSimpleName()); case ExpressionStatementNode e -> exprStmtToJson(e);
default -> simpleTypeJson(n.getClass().getSimpleName());
};
} }
private static String moduleToJson(ModuleNode m) { private static String moduleToJson(ModuleNode m) {
return "{" + return """
"\"type\":\"Module\"," + {"type":"Module","name":%1$s,"imports":%2$s,"functions":%3$s}
"\"name\":" + quote(m.name()) + "," + """.formatted(
"\"imports\":" + listToJsonArray(m.imports(), imp -> "{\"type\":\"Import\",\"module\":" + quote(imp.moduleName()) + "}") + "," + quote(m.name()),
"\"functions\":" + listToJsonArray(m.functions(), ASTJsonSerializer::functionToJson) + listToJsonArray(m.imports(),
"}"; imp -> String.format("{\"type\":\"Import\",\"module\":%s}", quote(imp.moduleName()))
),
listToJsonArray(m.functions(), ASTJsonSerializer::functionToJson)
);
} }
private static String functionToJson(FunctionNode f) { private static String functionToJson(FunctionNode f) {
return "{" + return """
"\"type\":\"Function\"," + {"type":"Function","name":%1$s,"parameters":%2$s,"returnType":%3$s,"body":%4$s}
"\"name\":" + quote(f.name()) + "," + """.formatted(
"\"parameters\":" + listToJsonArray(f.parameters(), p -> "{\"name\":" + quote(p.name()) + ",\"type\":" + quote(p.type()) + "}") + "," + quote(f.name()),
"\"returnType\":" + quote(f.returnType()) + "," + listToJsonArray(f.parameters(),
"\"body\":" + listToJsonArray(f.body(), ASTJsonSerializer::nodeToJson) + p -> String.format("{\"name\":%s,\"type\":%s}", quote(p.name()), quote(p.type()))
"}"; ),
quote(f.returnType()),
listToJsonArray(f.body(), ASTJsonSerializer::nodeToJson)
);
} }
private static String declarationToJson(DeclarationNode d) { private static String declarationToJson(DeclarationNode d) {
String json = "{" + var base = new StringBuilder();
"\"type\":\"Declaration\"," + base.append("""
"\"name\":" + quote(d.getName()) + "," + {"type":"Declaration","name":%1$s,"varType":%2$s
"\"varType\":" + quote(d.getType()); """.formatted(quote(d.getName()), quote(d.getType())));
if (d.getInitializer().isPresent()) { d.getInitializer().ifPresent(init ->
json += ",\"initializer\":" + exprToJson(d.getInitializer().get()); base.append(",\"initializer\":").append(exprToJson(init))
} );
return json + "}"; base.append("}");
return base.toString();
} }
private static String assignmentToJson(AssignmentNode a) { private static String assignmentToJson(AssignmentNode a) {
return "{" + return """
"\"type\":\"Assignment\"," + {"type":"Assignment","variable":%1$s,"value":%2$s}
"\"variable\":" + quote(a.variable()) + "," + """.formatted(quote(a.variable()), exprToJson(a.value()));
"\"value\":" + exprToJson(a.value()) +
"}";
} }
private static String ifToJson(IfNode i) { private static String ifToJson(IfNode i) {
StringBuilder sb = new StringBuilder(); var thenJson = listToJsonArray(i.thenBranch(), ASTJsonSerializer::nodeToJson);
sb.append("{" + "\"type\":\"If\"," + "\"condition\":").append(exprToJson(i.condition())).append(","); var elseJson = i.elseBranch().isEmpty() ? ""
sb.append("\"then\":").append(listToJsonArray(i.thenBranch(), ASTJsonSerializer::nodeToJson)); : ",\"else\":" + listToJsonArray(i.elseBranch(), ASTJsonSerializer::nodeToJson);
if (!i.elseBranch().isEmpty()) { return """
sb.append(",\"else\":").append(listToJsonArray(i.elseBranch(), ASTJsonSerializer::nodeToJson)); {"type":"If","condition":%1$s,"then":%2$s%3$s}
""".formatted(exprToJson(i.condition()), thenJson, elseJson);
} }
private static String loopToJson(LoopNode l) {
return """
{"type":"Loop","initializer":%1$s,"condition":%2$s,"update":%3$s,"body":%4$s}
""".formatted(
l.initializer() != null ? nodeToJson(l.initializer()) : "null",
l.condition() != null ? exprToJson(l.condition()) : "null",
l.update() != null ? nodeToJson(l.update()) : "null",
listToJsonArray(l.body(), ASTJsonSerializer::nodeToJson)
);
}
private static String returnToJson(ReturnNode r) {
var sb = new StringBuilder("{\"type\":\"Return\"");
r.getExpression().ifPresent(expr ->
sb.append(",\"value\":").append(exprToJson(expr))
);
sb.append("}"); sb.append("}");
return sb.toString(); return sb.toString();
} }
private static String loopToJson(LoopNode l) {
return "{" +
"\"type\":\"Loop\"," +
"\"initializer\":" + (l.initializer() != null ? nodeToJson(l.initializer()) : "null") + "," +
"\"condition\":" + (l.condition() != null ? exprToJson(l.condition()) : "null") + "," +
"\"update\":" + (l.update() != null ? nodeToJson(l.update()) : "null") + "," +
"\"body\":" + listToJsonArray(l.body(), ASTJsonSerializer::nodeToJson) +
"}";
}
private static String returnToJson(ReturnNode r) {
String json = "{" + "\"type\":\"Return\"";
if (r.getExpression().isPresent()) {
json += ",\"value\":" + exprToJson(r.getExpression().get());
}
return json + "}";
}
private static String exprStmtToJson(ExpressionStatementNode e) { private static String exprStmtToJson(ExpressionStatementNode e) {
return "{" + return """
"\"type\":\"ExpressionStatement\"," + {"type":"ExpressionStatement","expression":%s}
"\"expression\":" + exprToJson(e.expression()) + """.formatted(exprToJson(e.expression()));
"}";
} }
private static String exprToJson(ExpressionNode expr) { private static String exprToJson(ExpressionNode expr) {
if (expr instanceof BinaryExpressionNode b) return binaryToJson(b); return switch (expr) {
if (expr instanceof IdentifierNode id) return idToJson(id); case BinaryExpressionNode b -> binaryToJson(b);
if (expr instanceof NumberLiteralNode n) return numToJson(n); case IdentifierNode id -> idToJson(id);
if (expr instanceof StringLiteralNode s) return strToJson(s); case NumberLiteralNode n -> numToJson(n);
if (expr instanceof CallExpressionNode c) return callToJson(c); case StringLiteralNode s -> strToJson(s);
if (expr instanceof MemberExpressionNode m) return memberToJson(m); case CallExpressionNode c -> callToJson(c);
return simpleTypeJson(expr.getClass().getSimpleName()); case MemberExpressionNode m -> memberToJson(m);
default -> simpleTypeJson(expr.getClass().getSimpleName());
};
} }
private static String binaryToJson(BinaryExpressionNode b) { private static String binaryToJson(BinaryExpressionNode b) {
return "{" + return """
"\"type\":\"BinaryExpression\"," + {"type":"BinaryExpression","left":%1$s,"operator":%2$s,"right":%3$s}
"\"left\":" + exprToJson(b.left()) + "," + """.formatted(exprToJson(b.left()), quote(b.operator()), exprToJson(b.right()));
"\"operator\":" + quote(b.operator()) + "," +
"\"right\":" + exprToJson(b.right()) +
"}";
} }
private static String idToJson(IdentifierNode id) { private static String idToJson(IdentifierNode id) {
return "{" + return """
"\"type\":\"Identifier\"," + {"type":"Identifier","name":%s}
"\"name\":" + quote(id.name()) + """.formatted(quote(id.name()));
"}";
} }
private static String numToJson(NumberLiteralNode n) { private static String numToJson(NumberLiteralNode n) {
return "{" + return """
"\"type\":\"NumberLiteral\"," + {"type":"NumberLiteral","value":%s}
"\"value\":" + quote(n.value()) + """.formatted(quote(n.value()));
"}";
} }
private static String strToJson(StringLiteralNode s) { private static String strToJson(StringLiteralNode s) {
return "{" + return """
"\"type\":\"StringLiteral\"," + {"type":"StringLiteral","value":%s}
"\"value\":" + quote(s.value()) + """.formatted(quote(s.value()));
"}";
} }
private static String callToJson(CallExpressionNode c) { private static String callToJson(CallExpressionNode c) {
return "{" + return """
"\"type\":\"CallExpression\"," + {"type":"CallExpression","callee":%1$s,"arguments":%2$s}
"\"callee\":" + exprToJson(c.callee()) + "," + """.formatted(exprToJson(c.callee()), listToJsonArray(c.arguments(), ASTJsonSerializer::exprToJson));
"\"arguments\":" + listToJsonArray(c.arguments(), ASTJsonSerializer::exprToJson) +
"}";
} }
private static String memberToJson(MemberExpressionNode m) { private static String memberToJson(MemberExpressionNode m) {
return "{" + return """
"\"type\":\"MemberExpression\"," + {"type":"MemberExpression","object":%1$s,"member":%2$s}
"\"object\":" + exprToJson(m.object()) + "," + """.formatted(exprToJson(m.object()), quote(m.member()));
"\"member\":" + quote(m.member()) +
"}";
} }
// ========= 辅助函数 ========= // ======== 通用辅助 ========
private static String simpleTypeJson(String typeName) { private static String simpleTypeJson(String typeName) {
return "{" + "\"type\":" + quote(typeName) + "}"; return "{\"type\":" + quote(typeName) + "}";
} }
private static <T> String listToJsonArray(List<T> list, java.util.function.Function<T, String> mapper) { private static <T> String listToJsonArray(List<T> list, Function<T, String> mapper) {
StringBuilder sb = new StringBuilder(); return list.stream()
sb.append("["); .map(mapper)
for (int i = 0; i < list.size(); i++) { .collect(Collectors.joining(",", "[", "]"));
sb.append(mapper.apply(list.get(i)));
if (i + 1 < list.size()) sb.append(",");
}
sb.append("]");
return sb.toString();
}
private static String listToJsonArray(List<String> list) {
return listToJsonArray(list, s -> s);
} }
private static String quote(String s) { private static String quote(String s) {
StringBuilder sb = new StringBuilder(); var sb = new StringBuilder("\"");
sb.append('"');
for (char c : s.toCharArray()) { for (char c : s.toCharArray()) {
switch (c) { switch (c) {
case '\\': sb.append("\\\\"); break; case '\\' -> sb.append("\\\\");
case '"': sb.append("\\\""); break; case '\"' -> sb.append("\\\"");
case '\n': sb.append("\\n"); break; case '\n' -> sb.append("\\n");
case '\r': sb.append("\\r"); break; case '\r' -> sb.append("\\r");
case '\t': sb.append("\\t"); break; case '\t' -> sb.append("\\t");
default: sb.append(c); default -> sb.append(c);
} }
} }
sb.append('"'); sb.append('"');