优化打印逻辑
This commit is contained in:
parent
4df44686e7
commit
210a6942f4
@ -34,14 +34,9 @@ public class Main {
|
||||
// 3. 可读地打印 AST
|
||||
ASTPrinter.print(ast);
|
||||
|
||||
// 1) 输出紧凑 JSON
|
||||
String compact = ASTJsonSerializer.toJsonString(ast);
|
||||
// System.out.println("=== Compact JSON ===");
|
||||
// System.out.println(compact);
|
||||
|
||||
// 2) 输出美化后的 JSON
|
||||
// 4. AST JSON
|
||||
System.out.println("=== Pretty JSON ===");
|
||||
System.out.println(JsonFormatter.prettyPrint(compact));
|
||||
System.out.println(JsonFormatter.prettyPrint(ASTJsonSerializer.toJsonString(ast)));
|
||||
|
||||
}
|
||||
}
|
||||
@ -4,183 +4,170 @@ import org.jcnc.snow.compiler.parser.ast.*;
|
||||
import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
|
||||
import org.jcnc.snow.compiler.parser.ast.base.Node;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* ASTJsonSerializer 工具类
|
||||
* <p>
|
||||
* 将编译器生成的 AST(抽象语法树)节点列表转换为通用的 Map/List 结构
|
||||
* 并借助 JSONParser.toJson(Object) 方法序列化为 JSON 字符串。
|
||||
* <p>
|
||||
* 支持的节点类型包括:ModuleNode、FunctionNode、DeclarationNode、
|
||||
* AssignmentNode、IfNode、LoopNode、ReturnNode、ExpressionStatementNode
|
||||
* 以及各种 ExpressionNode(如 BinaryExpressionNode、IdentifierNode 等)。
|
||||
*/
|
||||
public class ASTJsonSerializer {
|
||||
|
||||
/**
|
||||
* 快速创建一个 LinkedHashMap,并写入 type 字段
|
||||
*/
|
||||
private static Map<String, Object> newNodeMap(String type) {
|
||||
Map<String, Object> m = new LinkedHashMap<>();
|
||||
m.put("type", type);
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于构建表达式节点的 Map
|
||||
*/
|
||||
private static Map<String, Object> exprMap(String type, Object... kv) {
|
||||
Map<String, Object> m = new LinkedHashMap<>();
|
||||
m.put("type", type);
|
||||
for (int i = 0; i < kv.length; i += 2) {
|
||||
m.put((String) kv[i], kv[i + 1]);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 AST 根节点列表序列化为 JSON 字符串。
|
||||
*
|
||||
* @param ast 表示抽象语法树根节点的 List<Node>
|
||||
* @return 对应的 JSON 格式字符串
|
||||
*/
|
||||
public static String toJsonString(List<Node> ast) {
|
||||
return ast.stream()
|
||||
.map(ASTJsonSerializer::nodeToJson)
|
||||
.collect(Collectors.joining(",", "[", "]"));
|
||||
List<Object> list = new ArrayList<>(ast.size());
|
||||
for (Node n : ast) {
|
||||
list.add(nodeToMap(n));
|
||||
}
|
||||
return JSONParser.toJson(list);
|
||||
}
|
||||
|
||||
private static String nodeToJson(Node n) {
|
||||
/**
|
||||
* 递归地将 AST 节点转换为 Map 或 List 等通用结构,
|
||||
* 便于后续统一序列化。
|
||||
*/
|
||||
private static Object nodeToMap(Node n) {
|
||||
return switch (n) {
|
||||
case ModuleNode m -> moduleToJson(m);
|
||||
case FunctionNode f -> functionToJson(f);
|
||||
case DeclarationNode d -> declarationToJson(d);
|
||||
case AssignmentNode a -> assignmentToJson(a);
|
||||
case IfNode i -> ifToJson(i);
|
||||
case LoopNode l -> loopToJson(l);
|
||||
case ReturnNode r -> returnToJson(r);
|
||||
case ExpressionStatementNode e -> exprStmtToJson(e);
|
||||
default -> simpleTypeJson(n.getClass().getSimpleName());
|
||||
case ModuleNode(String name, List<ImportNode> imports, List<FunctionNode> functions) -> {
|
||||
Map<String, Object> map = newNodeMap("Module");
|
||||
map.put("name", name);
|
||||
List<Object> imps = new ArrayList<>(imports.size());
|
||||
for (ImportNode imp : imports) {
|
||||
imps.add(Map.of(
|
||||
"type", "Import",
|
||||
"module", imp.moduleName()
|
||||
));
|
||||
}
|
||||
map.put("imports", imps);
|
||||
List<Object> funcs = new ArrayList<>(functions.size());
|
||||
for (FunctionNode f : functions) {
|
||||
funcs.add(nodeToMap(f));
|
||||
}
|
||||
map.put("functions", funcs);
|
||||
yield map;
|
||||
}
|
||||
case FunctionNode f -> {
|
||||
Map<String, Object> map = newNodeMap("Function");
|
||||
map.put("name", f.name());
|
||||
List<Object> params = new ArrayList<>(f.parameters().size());
|
||||
for (var p : f.parameters()) {
|
||||
params.add(Map.of(
|
||||
"name", p.name(),
|
||||
"type", p.type()
|
||||
));
|
||||
}
|
||||
map.put("parameters", params);
|
||||
map.put("returnType", f.returnType());
|
||||
List<Object> body = new ArrayList<>(f.body().size());
|
||||
for (Node stmt : f.body()) {
|
||||
body.add(nodeToMap(stmt));
|
||||
}
|
||||
map.put("body", body);
|
||||
yield map;
|
||||
}
|
||||
case DeclarationNode d -> {
|
||||
Map<String, Object> map = newNodeMap("Declaration");
|
||||
map.put("name", d.getName());
|
||||
map.put("varType", d.getType());
|
||||
map.put("initializer",
|
||||
d.getInitializer().map(ASTJsonSerializer::exprToMap).orElse(null)
|
||||
);
|
||||
yield map;
|
||||
}
|
||||
case AssignmentNode a -> exprMap("Assignment",
|
||||
"variable", a.variable(),
|
||||
"value", exprToMap(a.value())
|
||||
);
|
||||
case IfNode i -> {
|
||||
Map<String, Object> map = newNodeMap("If");
|
||||
map.put("condition", exprToMap(i.condition()));
|
||||
List<Object> thenList = new ArrayList<>(i.thenBranch().size());
|
||||
for (Node stmt : i.thenBranch()) thenList.add(nodeToMap(stmt));
|
||||
map.put("then", thenList);
|
||||
if (!i.elseBranch().isEmpty()) {
|
||||
List<Object> elseList = new ArrayList<>(i.elseBranch().size());
|
||||
for (Node stmt : i.elseBranch()) elseList.add(nodeToMap(stmt));
|
||||
map.put("else", elseList);
|
||||
}
|
||||
yield map;
|
||||
}
|
||||
case LoopNode l -> {
|
||||
Map<String, Object> map = newNodeMap("Loop");
|
||||
map.put("initializer", l.initializer() != null ? nodeToMap(l.initializer()) : null);
|
||||
map.put("condition", l.condition() != null ? exprToMap(l.condition()) : null);
|
||||
map.put("update", l.update() != null ? nodeToMap(l.update()) : null);
|
||||
List<Object> body = new ArrayList<>(l.body().size());
|
||||
for (Node stmt : l.body()) body.add(nodeToMap(stmt));
|
||||
map.put("body", body);
|
||||
yield map;
|
||||
}
|
||||
case ReturnNode r -> {
|
||||
Map<String, Object> map = newNodeMap("Return");
|
||||
r.getExpression().ifPresent(expr -> map.put("value", exprToMap(expr)));
|
||||
yield map;
|
||||
}
|
||||
case ExpressionStatementNode e -> exprMap("ExpressionStatement",
|
||||
"expression", exprToMap(e.expression())
|
||||
);
|
||||
case ExpressionNode expressionNode -> exprToMap(expressionNode);
|
||||
default -> Map.of("type", n.getClass().getSimpleName());
|
||||
};
|
||||
}
|
||||
|
||||
private static String moduleToJson(ModuleNode m) {
|
||||
return """
|
||||
{"type":"Module","name":%1$s,"imports":%2$s,"functions":%3$s}
|
||||
""".formatted(
|
||||
quote(m.name()),
|
||||
listToJsonArray(m.imports(),
|
||||
imp -> String.format("{\"type\":\"Import\",\"module\":%s}", quote(imp.moduleName()))
|
||||
),
|
||||
listToJsonArray(m.functions(), ASTJsonSerializer::functionToJson)
|
||||
);
|
||||
}
|
||||
|
||||
private static String functionToJson(FunctionNode f) {
|
||||
return """
|
||||
{"type":"Function","name":%1$s,"parameters":%2$s,"returnType":%3$s,"body":%4$s}
|
||||
""".formatted(
|
||||
quote(f.name()),
|
||||
listToJsonArray(f.parameters(),
|
||||
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) {
|
||||
var base = new StringBuilder();
|
||||
base.append("""
|
||||
{"type":"Declaration","name":%1$s,"varType":%2$s
|
||||
""".formatted(quote(d.getName()), quote(d.getType())));
|
||||
d.getInitializer().ifPresent(init ->
|
||||
base.append(",\"initializer\":").append(exprToJson(init))
|
||||
);
|
||||
base.append("}");
|
||||
return base.toString();
|
||||
}
|
||||
|
||||
private static String assignmentToJson(AssignmentNode a) {
|
||||
return """
|
||||
{"type":"Assignment","variable":%1$s,"value":%2$s}
|
||||
""".formatted(quote(a.variable()), exprToJson(a.value()));
|
||||
}
|
||||
|
||||
private static String ifToJson(IfNode i) {
|
||||
var thenJson = listToJsonArray(i.thenBranch(), ASTJsonSerializer::nodeToJson);
|
||||
var elseJson = i.elseBranch().isEmpty() ? ""
|
||||
: ",\"else\":" + listToJsonArray(i.elseBranch(), ASTJsonSerializer::nodeToJson);
|
||||
return """
|
||||
{"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("}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static String exprStmtToJson(ExpressionStatementNode e) {
|
||||
return """
|
||||
{"type":"ExpressionStatement","expression":%s}
|
||||
""".formatted(exprToJson(e.expression()));
|
||||
}
|
||||
|
||||
private static String exprToJson(ExpressionNode expr) {
|
||||
/**
|
||||
* 将表达式节点转换为 Map 表示。
|
||||
*/
|
||||
private static Object exprToMap(ExpressionNode expr) {
|
||||
return switch (expr) {
|
||||
case BinaryExpressionNode b -> binaryToJson(b);
|
||||
case IdentifierNode id -> idToJson(id);
|
||||
case NumberLiteralNode n -> numToJson(n);
|
||||
case StringLiteralNode s -> strToJson(s);
|
||||
case CallExpressionNode c -> callToJson(c);
|
||||
case MemberExpressionNode m -> memberToJson(m);
|
||||
default -> simpleTypeJson(expr.getClass().getSimpleName());
|
||||
case BinaryExpressionNode(ExpressionNode left, String operator, ExpressionNode right) -> exprMap("BinaryExpression",
|
||||
"left", exprToMap(left),
|
||||
"operator", operator,
|
||||
"right", exprToMap(right)
|
||||
);
|
||||
case IdentifierNode(String name) -> exprMap("Identifier", "name", name);
|
||||
case NumberLiteralNode(String value) -> exprMap("NumberLiteral", "value", value);
|
||||
case StringLiteralNode(String value) -> exprMap("StringLiteral", "value", value);
|
||||
case CallExpressionNode(ExpressionNode callee, List<ExpressionNode> arguments) -> {
|
||||
List<Object> args = new ArrayList<>(arguments.size());
|
||||
for (ExpressionNode arg : arguments) args.add(exprToMap(arg));
|
||||
yield exprMap("CallExpression", "callee", exprToMap(callee), "arguments", args);
|
||||
}
|
||||
case MemberExpressionNode(ExpressionNode object, String member) -> exprMap("MemberExpression",
|
||||
"object", exprToMap(object),
|
||||
"member", member
|
||||
);
|
||||
default -> Map.of("type", expr.getClass().getSimpleName());
|
||||
};
|
||||
}
|
||||
|
||||
private static String binaryToJson(BinaryExpressionNode b) {
|
||||
return """
|
||||
{"type":"BinaryExpression","left":%1$s,"operator":%2$s,"right":%3$s}
|
||||
""".formatted(exprToJson(b.left()), quote(b.operator()), exprToJson(b.right()));
|
||||
}
|
||||
|
||||
private static String idToJson(IdentifierNode id) {
|
||||
return """
|
||||
{"type":"Identifier","name":%s}
|
||||
""".formatted(quote(id.name()));
|
||||
}
|
||||
|
||||
private static String numToJson(NumberLiteralNode n) {
|
||||
return """
|
||||
{"type":"NumberLiteral","value":%s}
|
||||
""".formatted(quote(n.value()));
|
||||
}
|
||||
|
||||
private static String strToJson(StringLiteralNode s) {
|
||||
return """
|
||||
{"type":"StringLiteral","value":%s}
|
||||
""".formatted(quote(s.value()));
|
||||
}
|
||||
|
||||
private static String callToJson(CallExpressionNode c) {
|
||||
return """
|
||||
{"type":"CallExpression","callee":%1$s,"arguments":%2$s}
|
||||
""".formatted(exprToJson(c.callee()), listToJsonArray(c.arguments(), ASTJsonSerializer::exprToJson));
|
||||
}
|
||||
|
||||
private static String memberToJson(MemberExpressionNode m) {
|
||||
return """
|
||||
{"type":"MemberExpression","object":%1$s,"member":%2$s}
|
||||
""".formatted(exprToJson(m.object()), quote(m.member()));
|
||||
}
|
||||
|
||||
// ======== 通用辅助 ========
|
||||
|
||||
private static String simpleTypeJson(String typeName) {
|
||||
return "{\"type\":" + quote(typeName) + "}";
|
||||
}
|
||||
|
||||
private static <T> String listToJsonArray(List<T> list, Function<T, String> mapper) {
|
||||
return list.stream()
|
||||
.map(mapper)
|
||||
.collect(Collectors.joining(",", "[", "]"));
|
||||
}
|
||||
|
||||
private static String quote(String s) {
|
||||
var sb = new StringBuilder("\"");
|
||||
for (char c : s.toCharArray()) {
|
||||
switch (c) {
|
||||
case '\\' -> sb.append("\\\\");
|
||||
case '\"' -> sb.append("\\\"");
|
||||
case '\n' -> sb.append("\\n");
|
||||
case '\r' -> sb.append("\\r");
|
||||
case '\t' -> sb.append("\\t");
|
||||
default -> sb.append(c);
|
||||
}
|
||||
}
|
||||
sb.append('"');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
371
src/main/java/org/jcnc/snow/compiler/parser/util/JSONParser.java
Normal file
371
src/main/java/org/jcnc/snow/compiler/parser/util/JSONParser.java
Normal file
@ -0,0 +1,371 @@
|
||||
package org.jcnc.snow.compiler.parser.util;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* JSON 工具类,提供线程安全、可重用的解析与序列化功能
|
||||
* <p>
|
||||
* - 解析:将合法的 JSON 文本转换为 Java 原生对象(Map、List、String、Number、Boolean 或 null)
|
||||
* - 序列化:将 Java 原生对象转换为符合 JSON 标准的字符串
|
||||
* <p>
|
||||
* 设计要点:
|
||||
* 1. 使用静态方法作为唯一入口,避免状态共享导致的线程安全问题
|
||||
* 2. 解析器内部使用 char[] 缓冲区,提高访问性能
|
||||
* 3. 维护行列号信息,抛出异常时能精确定位错误位置
|
||||
* 4. 序列化器基于 StringBuilder,预分配容量,减少中间字符串创建
|
||||
*/
|
||||
public class JSONParser {
|
||||
// 私有构造,禁止外部实例化
|
||||
private JSONParser() {}
|
||||
|
||||
/**
|
||||
* 将 JSON 文本解析为对应的 Java 对象
|
||||
* @param input JSON 格式字符串
|
||||
* @return 对应的 Java 原生对象:
|
||||
* - JSON 对象 -> Map<String, Object>
|
||||
* - JSON 数组 -> List<Object>
|
||||
* - JSON 字符串 -> String
|
||||
* - JSON 数值 -> Long 或 Double
|
||||
* - JSON 布尔 -> Boolean
|
||||
* - JSON null -> null
|
||||
* @throws RuntimeException 如果遇到语法错误或多余字符,异常消息中包含行列信息
|
||||
*/
|
||||
public static Object parse(String input) {
|
||||
return new Parser(input).parseInternal();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 Java 原生对象序列化为 JSON 字符串
|
||||
* @param obj 支持的类型:Map、Collection、String、Number、Boolean 或 null
|
||||
* @return 符合 JSON 规范的字符串
|
||||
*/
|
||||
public static String toJson(Object obj) {
|
||||
return Writer.write(obj);
|
||||
}
|
||||
|
||||
// ======= 内部解析器 =======
|
||||
/**
|
||||
* 负责将 char[] 缓冲区中的 JSON 文本解析为 Java 对象
|
||||
*/
|
||||
private static class Parser {
|
||||
/** 输入缓冲区 */
|
||||
private final char[] buf;
|
||||
/** 当前解析到的位置索引 */
|
||||
private int pos;
|
||||
/** 当前字符所在行号,从 1 开始 */
|
||||
private int line;
|
||||
/** 当前字符所在列号,从 1 开始 */
|
||||
private int col;
|
||||
|
||||
/**
|
||||
* 构造解析器,初始化缓冲区和行列信息
|
||||
* @param input 待解析的 JSON 文本
|
||||
*/
|
||||
Parser(String input) {
|
||||
this.buf = input.toCharArray();
|
||||
this.pos = 0;
|
||||
this.line = 1;
|
||||
this.col = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 入口方法,跳过空白后调用 parseValue,再校验尾部无多余字符
|
||||
*/
|
||||
Object parseInternal() {
|
||||
skipWhitespace();
|
||||
Object value = parseValue();
|
||||
skipWhitespace();
|
||||
if (pos < buf.length) {
|
||||
error("存在无法识别的多余字符");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据下一个字符决定解析哪种 JSON 值
|
||||
*/
|
||||
private Object parseValue() {
|
||||
skipWhitespace();
|
||||
if (match("null")) return null;
|
||||
if (match("true")) return Boolean.TRUE;
|
||||
if (match("false")) return Boolean.FALSE;
|
||||
char c = currentChar();
|
||||
if (c == '"') return parseString();
|
||||
if (c == '{') return parseObject();
|
||||
if (c == '[') return parseArray();
|
||||
if (c == '-' || isDigit(c)) return parseNumber();
|
||||
error("遇到意外字符 '" + c + "'");
|
||||
return null; // 永不到达
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 JSON 对象,返回 Map<String, Object>
|
||||
*/
|
||||
private Map<String, Object> parseObject() {
|
||||
expect('{'); // 跳过 '{'
|
||||
skipWhitespace();
|
||||
Map<String, Object> map = new LinkedHashMap<>();
|
||||
// 空对象 {}
|
||||
if (currentChar() == '}') {
|
||||
advance(); // 跳过 '}'
|
||||
return map;
|
||||
}
|
||||
// 多成员对象解析
|
||||
while (true) {
|
||||
skipWhitespace();
|
||||
String key = parseString(); // 解析键
|
||||
skipWhitespace(); expect(':'); skipWhitespace();
|
||||
Object val = parseValue(); // 解析值
|
||||
map.put(key, val);
|
||||
skipWhitespace();
|
||||
if (currentChar() == '}') {
|
||||
advance(); // 跳过 '}'
|
||||
break;
|
||||
}
|
||||
expect(','); skipWhitespace();
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 JSON 数组,返回 List<Object>
|
||||
*/
|
||||
private List<Object> parseArray() {
|
||||
expect('[');
|
||||
skipWhitespace();
|
||||
List<Object> list = new ArrayList<>();
|
||||
// 空数组 []
|
||||
if (currentChar() == ']') {
|
||||
advance(); // 跳过 ']'
|
||||
return list;
|
||||
}
|
||||
// 多元素数组解析
|
||||
while (true) {
|
||||
skipWhitespace();
|
||||
list.add(parseValue());
|
||||
skipWhitespace();
|
||||
if (currentChar() == ']') {
|
||||
advance();
|
||||
break;
|
||||
}
|
||||
expect(','); skipWhitespace();
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 JSON 字符串文字,处理转义字符
|
||||
*/
|
||||
private String parseString() {
|
||||
expect('"'); // 跳过开头 '"'
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while (true) {
|
||||
char c = currentChar();
|
||||
if (c == '"') {
|
||||
advance(); // 跳过结束 '"'
|
||||
break;
|
||||
}
|
||||
if (c == '\\') {
|
||||
advance(); // 跳过 '\'
|
||||
c = currentChar();
|
||||
switch (c) {
|
||||
case '"': sb.append('"'); break;
|
||||
case '\\': sb.append('\\'); break;
|
||||
case '/': sb.append('/'); break;
|
||||
case 'b': sb.append('\b'); break;
|
||||
case 'f': sb.append('\f'); break;
|
||||
case 'n': sb.append('\n'); break;
|
||||
case 'r': sb.append('\r'); break;
|
||||
case 't': sb.append('\t'); break;
|
||||
case 'u': // 解析 Unicode 转义
|
||||
String hex = new String(buf, pos+1, 4);
|
||||
sb.append((char) Integer.parseInt(hex, 16));
|
||||
pos += 4; col += 4;
|
||||
break;
|
||||
default:
|
||||
error("无效转义字符 '\\" + c + "'");
|
||||
}
|
||||
advance();
|
||||
} else {
|
||||
sb.append(c);
|
||||
advance();
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 JSON 数值,支持整数、浮点及科学计数法
|
||||
*/
|
||||
private Number parseNumber() {
|
||||
int start = pos;
|
||||
if (currentChar() == '-') advance();
|
||||
while (isDigit(currentChar())) advance();
|
||||
if (currentChar() == '.') {
|
||||
advance();
|
||||
while (isDigit(currentChar())) advance();
|
||||
}
|
||||
if (currentChar() == 'e' || currentChar() == 'E') {
|
||||
advance();
|
||||
if (currentChar() == '+' || currentChar() == '-') advance();
|
||||
while (isDigit(currentChar())) advance();
|
||||
}
|
||||
String num = new String(buf, start, pos - start);
|
||||
// 判断返回 Long 还是 Double
|
||||
if (num.indexOf('.') >= 0 || num.indexOf('e') >= 0 || num.indexOf('E') >= 0) {
|
||||
return Double.parseDouble(num);
|
||||
}
|
||||
try {
|
||||
return Long.parseLong(num);
|
||||
} catch (NumberFormatException e) {
|
||||
return Double.parseDouble(num);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳过所有空白字符,支持空格、制表符、回车、换行
|
||||
*/
|
||||
private void skipWhitespace() {
|
||||
while (pos < buf.length) {
|
||||
char c = buf[pos];
|
||||
if (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
|
||||
advance();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前位置字符,超出范围返回 '\0'
|
||||
*/
|
||||
private char currentChar() {
|
||||
return pos < buf.length ? buf[pos] : '\0';
|
||||
}
|
||||
|
||||
/**
|
||||
* 推进到下一个字符,并更新行列信息
|
||||
*/
|
||||
private void advance() {
|
||||
if (pos < buf.length) {
|
||||
if (buf[pos] == '\n') {
|
||||
line++; col = 1;
|
||||
} else {
|
||||
col++;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证当前位置字符等于预期字符,否则抛出错误
|
||||
*/
|
||||
private void expect(char c) {
|
||||
if (currentChar() != c) {
|
||||
error("期望 '" + c + "',但遇到 '" + currentChar() + "'");
|
||||
}
|
||||
advance();
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试匹配给定字符串,匹配成功则移动位置并返回 true
|
||||
*/
|
||||
private boolean match(String s) {
|
||||
int len = s.length();
|
||||
if (pos + len > buf.length) return false;
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (buf[pos + i] != s.charAt(i)) return false;
|
||||
}
|
||||
for (int i = 0; i < len; i++) advance();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断字符是否为数字
|
||||
*/
|
||||
private boolean isDigit(char c) {
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
/**
|
||||
* 抛出带行列定位的解析错误
|
||||
*/
|
||||
private void error(String msg) {
|
||||
throw new RuntimeException("Error at line " + line + ", column " + col + ": " + msg);
|
||||
}
|
||||
}
|
||||
|
||||
// ======= 内部序列化器 =======
|
||||
/**
|
||||
* 负责高效地将 Java 对象写为 JSON 文本
|
||||
*/
|
||||
private static class Writer {
|
||||
/** 默认 StringBuilder 初始容量,避免频繁扩容 */
|
||||
private static final int DEFAULT_CAPACITY = 1024;
|
||||
|
||||
/**
|
||||
* 入口方法,根据 obj 类型分派写入逻辑
|
||||
*/
|
||||
static String write(Object obj) {
|
||||
StringBuilder sb = new StringBuilder(DEFAULT_CAPACITY);
|
||||
writeValue(obj, sb);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据对象类型选择合适的写入方式
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static void writeValue(Object obj, StringBuilder sb) {
|
||||
if (obj == null) {
|
||||
sb.append("null");
|
||||
} else if (obj instanceof String) {
|
||||
quote((String) obj, sb);
|
||||
} else if (obj instanceof Number || obj instanceof Boolean) {
|
||||
sb.append(obj.toString());
|
||||
} else if (obj instanceof Map) {
|
||||
sb.append('{');
|
||||
boolean first = true;
|
||||
for (Entry<?, ?> e : ((Map<?, ?>) obj).entrySet()) {
|
||||
if (!first) sb.append(',');
|
||||
first = false;
|
||||
quote(e.getKey().toString(), sb);
|
||||
sb.append(':');
|
||||
writeValue(e.getValue(), sb);
|
||||
}
|
||||
sb.append('}');
|
||||
} else if (obj instanceof Collection) {
|
||||
sb.append('[');
|
||||
boolean first = true;
|
||||
for (Object item : (Collection<?>) obj) {
|
||||
if (!first) sb.append(',');
|
||||
first = false;
|
||||
writeValue(item, sb);
|
||||
}
|
||||
sb.append(']');
|
||||
} else {
|
||||
// 其他类型,使用 toString 并加引号
|
||||
quote(obj.toString(), sb);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 为字符串添加双引号并转义必须的字符
|
||||
*/
|
||||
private static void quote(String s, StringBuilder sb) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
sb.append('"');
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -37,29 +37,25 @@ public class JsonFormatter {
|
||||
sb.append(c);
|
||||
} else if (!inQuotes) {
|
||||
switch (c) {
|
||||
case '{', '[':
|
||||
case '{', '[' -> {
|
||||
sb.append(c).append('\n');
|
||||
indent++;
|
||||
appendIndent(sb, indent);
|
||||
break;
|
||||
case '}', ']':
|
||||
}
|
||||
case '}', ']' -> {
|
||||
sb.append('\n');
|
||||
indent--;
|
||||
appendIndent(sb, indent);
|
||||
sb.append(c);
|
||||
break;
|
||||
case ',':
|
||||
sb.append(c).append('\n');
|
||||
appendIndent(sb, indent);
|
||||
break;
|
||||
case ':':
|
||||
sb.append(c).append(' ');
|
||||
break;
|
||||
default:
|
||||
}
|
||||
case ',' -> sb.append(c).append('\n').append(" ".repeat(indent));
|
||||
case ':' -> sb.append(c).append(' ');
|
||||
default -> {
|
||||
if (!Character.isWhitespace(c)) {
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 字符串内部原样输出
|
||||
sb.append(c);
|
||||
|
||||
10
test
10
test
@ -1,15 +1,11 @@
|
||||
module: CommonTasks
|
||||
function: add_numbers
|
||||
|
||||
body:
|
||||
return num1 + num2
|
||||
end body
|
||||
|
||||
parameter:
|
||||
|
||||
declare num1: int
|
||||
declare num2: int
|
||||
|
||||
return_type: int
|
||||
|
||||
end function
|
||||
@ -41,7 +37,6 @@ end module
|
||||
module: MainModule
|
||||
import: CommonTasks, MathUtils, StringUtils, BuiltinUtils
|
||||
|
||||
|
||||
function: test
|
||||
parameter:
|
||||
declare first_str: string
|
||||
@ -52,7 +47,6 @@ module: MainModule
|
||||
end body
|
||||
end function
|
||||
|
||||
|
||||
function: main
|
||||
parameter:
|
||||
declare args: string
|
||||
@ -89,9 +83,9 @@ module: MainModule
|
||||
BuiltinUtils.print(" first inner")
|
||||
else
|
||||
if j % 2 == 0 then
|
||||
BuiltinUtils.print(" j even")
|
||||
BuiltinUtils.print("j even")
|
||||
else
|
||||
BuiltinUtils.print(" j odd")
|
||||
BuiltinUtils.print("j odd")
|
||||
end if
|
||||
end if
|
||||
end body
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user