diff --git a/src/main/java/org/jcnc/snow/compiler/Main.java b/src/main/java/org/jcnc/snow/compiler/Main.java index 2a1b0e4..3d7d89b 100644 --- a/src/main/java/org/jcnc/snow/compiler/Main.java +++ b/src/main/java/org/jcnc/snow/compiler/Main.java @@ -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)); } } \ No newline at end of file diff --git a/src/main/java/org/jcnc/snow/compiler/parser/util/ASTJsonSerializer.java b/src/main/java/org/jcnc/snow/compiler/parser/util/ASTJsonSerializer.java index 5a1e012..a0a3936 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/util/ASTJsonSerializer.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/util/ASTJsonSerializer.java @@ -4,217 +4,192 @@ 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 ast) { + return listToJsonArray(ast.stream().map(ASTJsonSerializer::nodeToJson).toList()); + } + + private static String nodeToJson(Node n) { + if (n instanceof ModuleNode m) return moduleToJson(m); + if (n instanceof FunctionNode f) return functionToJson(f); + if (n instanceof DeclarationNode d) return declarationToJson(d); + if (n instanceof AssignmentNode a) return assignmentToJson(a); + 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 e) return exprStmtToJson(e); + return simpleTypeJson(n.getClass().getSimpleName()); + } + + private static String moduleToJson(ModuleNode m) { + 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) { + 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) { + 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()) + + "}"; + } + + private static String ifToJson(IfNode i) { + StringBuilder sb = new StringBuilder(); + 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)); + } + sb.append("}"); + 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) { + 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 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); + 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 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 String listToJsonArray(List list, java.util.function.Function mapper) { 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(","); + 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 nodeToJson(Node n) { - if (n instanceof ModuleNode m) return moduleToJson(m); - if (n instanceof FunctionNode f) return functionToJson(f); - if (n instanceof DeclarationNode d) return declarationToJson(d); - if (n instanceof AssignmentNode a) return assignmentToJson(a); - 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() + "\"}"; + private static String listToJsonArray(List list) { + return listToJsonArray(list, s -> s); } - private static String moduleToJson(ModuleNode m) { + private static String quote(String s) { 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(); - } - - 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 body = f.body(); - return getString(sb, body); - } - - 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(); - } - - private static String assignmentToJson(AssignmentNode a) { - 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 thenBranch = i.thenBranch(); - return getString(sb, thenBranch); - } - - private static String getString(StringBuilder sb, List 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 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 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 CallExpressionNode c) return callToJson(c); - if (expr instanceof MemberExpressionNode m) return memberToJson(m); - // fallback - return "{\"type\":\"" + 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()) - + "}"; - } - - /** - * 将字符串转换为合法的 JSON 字符串常量(添加双引号并进行必要的转义)。 - * - * @param s 原始字符串。 - * @return 转义并加双引号的 JSON 字符串。 - */ private static String quote(String s) { - StringBuilder sb = new StringBuilder(); - sb.append("\""); + sb.append('"'); for (char c : s.toCharArray()) { switch (c) { case '\\': sb.append("\\\\"); break; - case '"': sb.append("\\\""); break; - case '\n': sb.append("\\n"); break; - case '\r': sb.append("\\r"); break; - case '\t': sb.append("\\t"); break; - default: sb.append(c); + case '"': sb.append("\\\""); break; + case '\n': sb.append("\\n"); break; + case '\r': sb.append("\\r"); break; + case '\t': sb.append("\\t"); break; + default: sb.append(c); } } - sb.append("\""); + sb.append('"'); return sb.toString(); } -} +} \ No newline at end of file diff --git a/test b/test index cb9adee..d2eb11e 100644 --- a/test +++ b/test @@ -52,172 +52,61 @@ module: MainModule end body end function - function: main - parameter: - declare args: string - return_type: void - body: - declare input_number: int = BuiltinUtils.to_int(args) - if input_number <= 0 then - input_number = 5 - end if + function: main + parameter: + declare args: string + return_type: void + body: + declare input_number: int = BuiltinUtils.to_int(args) - loop: - initializer: - declare i: int = 0 - condition: - i < input_number - update: - i = i + 1 - body: - if i % 2 == 0 then - BuiltinUtils.print("i is even: " + BuiltinUtils.to_string(i)) + if input_number <= 0 then + input_number = 5 + end if - if i > 2 then - BuiltinUtils.print("i is greater than 2") + loop: + initializer: + declare i: int = 0 + condition: + i < input_number + update: + i = i + 1 + body: + if i % 2 == 0 then + BuiltinUtils.print("i is even: " + BuiltinUtils.to_string(i)) + else + BuiltinUtils.print("i is odd: " + BuiltinUtils.to_string(i)) loop: initializer: - declare k: int = 0 + declare j: int = 0 condition: - k < 3 + j < i update: - k = k + 1 + j = j + 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 + if j == 1 then + BuiltinUtils.print(" first inner") + else + if j % 2 == 0 then + BuiltinUtils.print(" j even") + else + BuiltinUtils.print(" j odd") + end if end if end body end loop end if - else - BuiltinUtils.print("i is odd: " + BuiltinUtils.to_string(i)) + declare sum: int = CommonTasks.add_numbers(i, 10) + declare squared: int = MathUtils.square_number(sum) + BuiltinUtils.print(" i+10 squared = " + BuiltinUtils.to_string(squared)) + end body + end loop - loop: - initializer: - declare j: int = 0 - condition: - j < i - update: - j = j + 1 - body: - if j == 1 then - BuiltinUtils.print("first inner") - 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 - end loop - end if - - declare sum: int = CommonTasks.add_numbers(i, 10) - declare squared: int = MathUtils.square_number(sum) - BuiltinUtils.print("i+10 squared = " + BuiltinUtils.to_string(squared)) - end body - end loop - - declare final_message: string = StringUtils.concatenate("Finished with input: ", BuiltinUtils.to_string(input_number)) - BuiltinUtils.print(final_message) - end body + declare final_message: string = StringUtils.concatenate("Finished with input: ", BuiltinUtils.to_string(input_number)) + BuiltinUtils.print(final_message) + end body end function - - - end module