优化打印逻辑
This commit is contained in:
parent
fd38c94b3d
commit
4df44686e7
@ -5,193 +5,182 @@ 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('"');
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user