增加ast的else打印

This commit is contained in:
Luke 2025-04-27 11:09:44 +08:00
parent e3bc1a99e7
commit 60eaedb6b0
3 changed files with 215 additions and 349 deletions

View File

@ -7,6 +7,8 @@ import org.jcnc.snow.compiler.parser.ParserEngine;
import org.jcnc.snow.compiler.parser.context.ParserContext;
import org.jcnc.snow.compiler.parser.ast.Node;
import org.jcnc.snow.compiler.parser.function.ASTPrinter;
import org.jcnc.snow.compiler.parser.util.ASTJsonSerializer;
import org.jcnc.snow.compiler.parser.util.JsonFormatter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@ -32,14 +34,14 @@ public class Main {
// 3. 可读地打印 AST
ASTPrinter.print(ast);
// // 1) 输出紧凑 JSON
// String compact = ASTJsonSerializer.toJsonString(ast);
// 1) 输出紧凑 JSON
String compact = ASTJsonSerializer.toJsonString(ast);
// System.out.println("=== Compact JSON ===");
// System.out.println(compact);
//
// // 2) 输出美化后的 JSON
// System.out.println("=== Pretty JSON ===");
// System.out.println(JsonFormatter.prettyPrint(compact));
// 2) 输出美化后的 JSON
System.out.println("=== Pretty JSON ===");
System.out.println(JsonFormatter.prettyPrint(compact));
}
}

View File

@ -4,28 +4,13 @@ import org.jcnc.snow.compiler.parser.ast.*;
import java.util.List;
/**
* ASTJsonSerializer 是一个用于将抽象语法树AST序列化为 JSON 字符串的工具类
* 该类通过访问不同类型的语法树节点将其结构以标准 JSON 格式输出适用于调试可视化或进一步处理
* 更加健壮完整的 AST -> JSON 序列化器
*/
public class ASTJsonSerializer {
/**
* 将语法树节点列表序列化为 JSON 字符串
*
* @param ast 抽象语法树的节点列表
* @return 表示整个 AST JSON 字符串
*/
public static String toJsonString(List<Node> ast) {
StringBuilder sb = new StringBuilder();
sb.append("[");
for (int i = 0; i < ast.size(); i++) {
sb.append(nodeToJson(ast.get(i)));
if (i + 1 < ast.size()) sb.append(",");
}
sb.append("]");
return sb.toString();
return listToJsonArray(ast.stream().map(ASTJsonSerializer::nodeToJson).toList());
}
private static String nodeToJson(Node n) {
@ -36,174 +21,164 @@ public class ASTJsonSerializer {
if (n instanceof IfNode i) return ifToJson(i);
if (n instanceof LoopNode l) return loopToJson(l);
if (n instanceof ReturnNode r) return returnToJson(r);
if (n instanceof ExpressionStatementNode es)
return exprStmtToJson(es);
// fallback仅输出类型名
return "{\"type\":\"" + n.getClass().getSimpleName() + "\"}";
if (n instanceof ExpressionStatementNode e) return exprStmtToJson(e);
return simpleTypeJson(n.getClass().getSimpleName());
}
private static String moduleToJson(ModuleNode m) {
StringBuilder sb = new StringBuilder();
sb.append("{\"type\":\"Module\",")
.append("\"name\":").append(quote(m.name())).append(",");
// imports
sb.append("\"imports\":[");
for (int i = 0; i < m.imports().size(); i++) {
ImportNode imp = m.imports().get(i);
sb.append("{\"type\":\"Import\",\"module\":")
.append(quote(imp.moduleName())).append("}");
if (i + 1 < m.imports().size()) sb.append(",");
}
sb.append("],");
// functions
sb.append("\"functions\":[");
for (int i = 0; i < m.functions().size(); i++) {
sb.append(functionToJson(m.functions().get(i)));
if (i + 1 < m.functions().size()) sb.append(",");
}
sb.append("]}");
return sb.toString();
return "{" +
"\"type\":\"Module\"," +
"\"name\":" + quote(m.name()) + "," +
"\"imports\":" + listToJsonArray(m.imports(), imp -> "{\"type\":\"Import\",\"module\":" + quote(imp.moduleName()) + "}") + "," +
"\"functions\":" + listToJsonArray(m.functions(), ASTJsonSerializer::functionToJson) +
"}";
}
private static String functionToJson(FunctionNode f) {
StringBuilder sb = new StringBuilder();
sb.append("{\"type\":\"Function\",")
.append("\"name\":").append(quote(f.name())).append(",");
// parameters
sb.append("\"parameters\":[");
for (int i = 0; i < f.parameters().size(); i++) {
ParameterNode p = f.parameters().get(i);
sb.append("{\"name\":").append(quote(p.name()))
.append(",\"type\":").append(quote(p.type())).append("}");
if (i + 1 < f.parameters().size()) sb.append(",");
}
sb.append("],");
sb.append("\"returnType\":").append(quote(f.returnType())).append(",");
// body
sb.append("\"body\":[");
List<StatementNode> body = f.body();
return getString(sb, body);
return "{" +
"\"type\":\"Function\"," +
"\"name\":" + quote(f.name()) + "," +
"\"parameters\":" + listToJsonArray(f.parameters(), p -> "{\"name\":" + quote(p.name()) + ",\"type\":" + quote(p.type()) + "}") + "," +
"\"returnType\":" + quote(f.returnType()) + "," +
"\"body\":" + listToJsonArray(f.body(), ASTJsonSerializer::nodeToJson) +
"}";
}
private static String declarationToJson(DeclarationNode d) {
StringBuilder sb = new StringBuilder();
sb.append("{\"type\":\"Declaration\",")
.append("\"name\":").append(quote(d.getName())).append(",")
.append("\"varType\":").append(quote(d.getType()));
d.getInitializer().ifPresent(init ->
sb.append(",\"initializer\":").append(exprToJson(init))
);
sb.append("}");
return sb.toString();
String json = "{" +
"\"type\":\"Declaration\"," +
"\"name\":" + quote(d.getName()) + "," +
"\"varType\":" + quote(d.getType());
if (d.getInitializer().isPresent()) {
json += ",\"initializer\":" + exprToJson(d.getInitializer().get());
}
return json + "}";
}
private static String assignmentToJson(AssignmentNode a) {
return "{\"type\":\"Assignment\",\"variable\":"
+ quote(a.variable())
+ ",\"value\":"
+ exprToJson(a.value())
+ "}";
return "{" +
"\"type\":\"Assignment\"," +
"\"variable\":" + quote(a.variable()) + "," +
"\"value\":" + exprToJson(a.value()) +
"}";
}
private static String ifToJson(IfNode i) {
StringBuilder sb = new StringBuilder();
sb.append("{\"type\":\"If\",\"condition\":")
.append(exprToJson(i.condition())).append(",");
sb.append("\"then\":[");
List<StatementNode> thenBranch = i.thenBranch();
return getString(sb, thenBranch);
sb.append("{" + "\"type\":\"If\"," + "\"condition\":").append(exprToJson(i.condition())).append(",");
sb.append("\"then\":").append(listToJsonArray(i.thenBranch(), ASTJsonSerializer::nodeToJson));
if (!i.elseBranch().isEmpty()) {
sb.append(",\"else\":").append(listToJsonArray(i.elseBranch(), ASTJsonSerializer::nodeToJson));
}
private static String getString(StringBuilder sb, List<StatementNode> thenBranch) {
for (int j = 0; j < thenBranch.size(); j++) {
sb.append(nodeToJson(thenBranch.get(j)));
if (j + 1 < thenBranch.size()) sb.append(",");
}
sb.append("]}");
return sb.toString();
}
private static String loopToJson(LoopNode l) {
StringBuilder sb = new StringBuilder();
sb.append("{\"type\":\"Loop\",")
.append("\"initializer\":").append(nodeToJson(l.initializer())).append(",")
.append("\"condition\":").append(exprToJson(l.condition())).append(",")
.append("\"update\":").append(nodeToJson(l.update())).append(",")
.append("\"body\":[");
List<StatementNode> body = l.body();
return getString(sb, body);
}
private static String returnToJson(ReturnNode r) {
StringBuilder sb = new StringBuilder();
sb.append("{\"type\":\"Return\"");
r.getExpression().ifPresent(expr ->
sb.append(",\"value\":").append(exprToJson(expr))
);
sb.append("}");
return sb.toString();
}
private static String exprStmtToJson(ExpressionStatementNode es) {
return "{\"type\":\"ExpressionStatement\",\"expression\":"
+ exprToJson(es.expression())
+ "}";
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) {
return "{" +
"\"type\":\"ExpressionStatement\"," +
"\"expression\":" + exprToJson(e.expression()) +
"}";
}
private static String exprToJson(ExpressionNode expr) {
if (expr instanceof BinaryExpressionNode b) return binaryToJson(b);
if (expr instanceof IdentifierNode id) return idToJson(id);
if (expr instanceof NumberLiteralNode num) return numToJson(num);
if (expr instanceof StringLiteralNode str) return strToJson(str);
if (expr instanceof NumberLiteralNode n) return numToJson(n);
if (expr instanceof StringLiteralNode s) return strToJson(s);
if (expr instanceof CallExpressionNode c) return callToJson(c);
if (expr instanceof MemberExpressionNode m) return memberToJson(m);
// fallback
return "{\"type\":\"" + expr.getClass().getSimpleName() + "\"}";
return simpleTypeJson(expr.getClass().getSimpleName());
}
private static String binaryToJson(BinaryExpressionNode b) {
return "{\"type\":\"BinaryExpression\","
+ "\"left\":" + exprToJson(b.left()) + ","
+ "\"operator\":" + quote(b.operator()) + ","
+ "\"right\":" + exprToJson(b.right())
+ "}";
}
private static String idToJson(IdentifierNode id) {
return "{\"type\":\"Identifier\",\"name\":" + quote(id.name()) + "}";
}
private static String numToJson(NumberLiteralNode num) {
return "{\"type\":\"NumberLiteral\",\"value\":" + quote(num.value()) + "}";
}
private static String strToJson(StringLiteralNode str) {
return "{\"type\":\"StringLiteral\",\"value\":" + quote(str.value()) + "}";
}
private static String callToJson(CallExpressionNode c) {
StringBuilder sb = new StringBuilder();
sb.append("{\"type\":\"CallExpression\",\"callee\":")
.append(exprToJson(c.callee())).append(",")
.append("\"arguments\":[");
for (int i = 0; i < c.arguments().size(); i++) {
sb.append(exprToJson(c.arguments().get(i)));
if (i + 1 < c.arguments().size()) sb.append(",");
}
sb.append("]}");
return sb.toString();
}
private static String memberToJson(MemberExpressionNode m) {
return "{\"type\":\"MemberExpression\",\"object\":"
+ exprToJson(m.object())
+ ",\"member\":" + quote(m.member())
+ "}";
return "{" +
"\"type\":\"BinaryExpression\"," +
"\"left\":" + exprToJson(b.left()) + "," +
"\"operator\":" + quote(b.operator()) + "," +
"\"right\":" + exprToJson(b.right()) +
"}";
}
/**
* 将字符串转换为合法的 JSON 字符串常量添加双引号并进行必要的转义
*
* @param s 原始字符串
* @return 转义并加双引号的 JSON 字符串
*/ private static String quote(String s) {
private static String idToJson(IdentifierNode id) {
return "{" +
"\"type\":\"Identifier\"," +
"\"name\":" + quote(id.name()) +
"}";
}
private static String numToJson(NumberLiteralNode n) {
return "{" +
"\"type\":\"NumberLiteral\"," +
"\"value\":" + quote(n.value()) +
"}";
}
private static String strToJson(StringLiteralNode s) {
return "{" +
"\"type\":\"StringLiteral\"," +
"\"value\":" + quote(s.value()) +
"}";
}
private static String callToJson(CallExpressionNode c) {
return "{" +
"\"type\":\"CallExpression\"," +
"\"callee\":" + exprToJson(c.callee()) + "," +
"\"arguments\":" + listToJsonArray(c.arguments(), ASTJsonSerializer::exprToJson) +
"}";
}
private static String memberToJson(MemberExpressionNode m) {
return "{" +
"\"type\":\"MemberExpression\"," +
"\"object\":" + exprToJson(m.object()) + "," +
"\"member\":" + quote(m.member()) +
"}";
}
// ========= 辅助函数 =========
private static String simpleTypeJson(String typeName) {
return "{" + "\"type\":" + quote(typeName) + "}";
}
private static <T> String listToJsonArray(List<T> list, java.util.function.Function<T, String> mapper) {
StringBuilder sb = new StringBuilder();
sb.append("\"");
sb.append("[");
for (int i = 0; i < list.size(); i++) {
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) {
StringBuilder sb = new StringBuilder();
sb.append('"');
for (char c : s.toCharArray()) {
switch (c) {
case '\\': sb.append("\\\\"); break;
@ -214,7 +189,7 @@ public class ASTJsonSerializer {
default: sb.append(c);
}
}
sb.append("\"");
sb.append('"');
return sb.toString();
}
}

113
test
View File

@ -52,6 +52,7 @@ module: MainModule
end body
end function
function: main
parameter:
declare args: string
@ -73,63 +74,6 @@ module: MainModule
body:
if i % 2 == 0 then
BuiltinUtils.print("i is even: " + BuiltinUtils.to_string(i))
if i > 2 then
BuiltinUtils.print("i is greater than 2")
loop:
initializer:
declare k: int = 0
condition:
k < 3
update:
k = k + 1
body:
BuiltinUtils.print("k = " + BuiltinUtils.to_string(k))
if k == 2 then
BuiltinUtils.print("k is two")
loop:
initializer:
declare n: int = 0
condition:
n < 2
update:
n = n + 1
body:
BuiltinUtils.print("n = " + BuiltinUtils.to_string(n))
if n == 1 then
BuiltinUtils.print("n is one")
if i > 3 then
BuiltinUtils.print("deep i > 3 block")
loop:
initializer:
declare x: int = 0
condition:
x < 2
update:
x = x + 1
body:
if x == 1 then
BuiltinUtils.print("x is one at depth")
else
BuiltinUtils.print("x is zero at depth")
end if
end body
end loop
end if
end if
end body
end loop
end if
end body
end loop
end if
else
BuiltinUtils.print("i is odd: " + BuiltinUtils.to_string(i))
@ -146,60 +90,8 @@ module: MainModule
else
if j % 2 == 0 then
BuiltinUtils.print(" j even")
if j > 2 then
BuiltinUtils.print("j > 2, deeper if")
loop:
initializer:
declare y: int = 0
condition:
y < 2
update:
y = y + 1
body:
BuiltinUtils.print("y in deep even j loop: " + BuiltinUtils.to_string(y))
if y == 1 then
BuiltinUtils.print("y is one")
end if
end body
end loop
end if
else
BuiltinUtils.print(" j odd")
loop:
initializer:
declare m: int = 0
condition:
m < 2
update:
m = m + 1
body:
BuiltinUtils.print("m = " + BuiltinUtils.to_string(m))
if m == 1 then
BuiltinUtils.print("m is one")
if j > 3 then
BuiltinUtils.print("j > 3, going deeper")
loop:
initializer:
declare z: int = 0
condition:
z < 2
update:
z = z + 1
body:
BuiltinUtils.print("z = " + BuiltinUtils.to_string(z))
end body
end loop
end if
end if
end body
end loop
end if
end if
end body
@ -217,7 +109,4 @@ module: MainModule
end body
end function
end module