docs: 增加注释 doc

This commit is contained in:
Luke 2025-06-24 14:04:34 +08:00
parent 2c4374554e
commit a75e76e05a

View File

@ -10,61 +10,54 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
/** /**
* CloudDSLParser .cloud 配置文件解析器 * CloudDSL 配置文件解析器
* <p>
* 作用
* - 读取 Snow 构建工具自定义的 .cloud 文件
* - 将内容转换为内存中的 {@link Project} 模型
* <p>
* 解析规则
* <p>
* 1. 顶级区块projectpropertiesrepositoriesdependenciesbuild
* sectionName { 开始 } 结束
* <p>
* 2. 区块内部识别 key = value 形式的赋值
* <p>
* 3. build 区块允许嵌套内部键通过 . 展平
* 例如 compile.enabled = true
* <p> * <p>
* 负责将自定义的 .cloud 构建配置文件解析为 {@link Project} 模型
* </p>
*
* <ul>
* <li>顶级区块 projectpropertiesrepositoriesdependenciesbuild <code>sectionName &#123;</code> 开始 <code>&#125;</code> 结束</li>
* <li>区块内部只识别 <code>key = value</code> 赋值行尾可有 <code># 注释</code></li>
* <li>build 区块支持嵌套内部键通过 <code>.</code> 展平例如 <code>compile.enabled = true</code></li>
* </ul>
*
* <pre>
* 示例 .cloud 文件片段
* project {
* group = com.example
* artifact = demo
* version = 1.0.0
* }
* </pre>
*/ */
public final class CloudDSLParser { public final class CloudDSLParser {
/* ---------- 正则表达式 ---------- */ /** 匹配 sectionName { 的行 */
/**
* 匹配 sectionName { 形式的行
*/
private static final Pattern SECTION_HEADER = Pattern.compile("^(\\w+)\\s*\\{\\s*$"); private static final Pattern SECTION_HEADER = Pattern.compile("^(\\w+)\\s*\\{\\s*$");
/** 匹配 key = value 行,忽略行尾注释 */
/**
* 匹配 key = value
* value 允许空格并忽略行尾 # 注释
*/
private static final Pattern KEY_VALUE = Pattern.compile("^(\\w+)\\s*=\\s*([^#]+?)\\s*(?:#.*)?$"); private static final Pattern KEY_VALUE = Pattern.compile("^(\\w+)\\s*=\\s*([^#]+?)\\s*(?:#.*)?$");
/** 匹配仅为 } 的行 */
/**
* 匹配仅包含 } 的行可有前后空白
*/
private static final Pattern BLOCK_END = Pattern.compile("^}\\s*$"); private static final Pattern BLOCK_END = Pattern.compile("^}\\s*$");
/** /** 私有构造方法,工具类禁止实例化 */
* 私有构造禁止实例化 private CloudDSLParser() {}
*/
private CloudDSLParser() {
}
/** /**
* 解析指定 .cloud 文件并生成 {@link Project} 对象 * 解析指定 .cloud 文件为 {@link Project} 对象
* <ul>
* <li>遇到语法错误括号不配对无法识别的行时会抛出异常</li>
* <li>支持嵌套区块和注释</li>
* </ul>
* *
* @param path 文件路径 * @param path .cloud 文件路径
* @return 解析后的 Project * @return 解析得到的 Project 实例
* @throws IOException 文件读取失败 * @throws IOException 文件读取失败
* @throws IllegalStateException 语法错误如括号不匹配未知语句 * @throws IllegalStateException 文件内容格式非法或语法错误
*/ */
public static Project parse(Path path) throws IOException { public static Project parse(Path path) throws IOException {
Deque<String> sectionStack = new ArrayDeque<>(); // 记录当前区块层级 Deque<String> sectionStack = new ArrayDeque<>(); // 当前区块栈
Map<String, String> flatMap = new LinkedHashMap<>(); // 扁平化 key value Map<String, String> flatMap = new LinkedHashMap<>(); // 扁平化后的 key value
List<String> lines = Files.readAllLines(path); List<String> lines = Files.readAllLines(path);
@ -73,19 +66,19 @@ public final class CloudDSLParser {
lineNo++; lineNo++;
String line = raw.trim(); String line = raw.trim();
/* 1. 跳过空行和注释 */ // 跳过空行和注释
if (line.isEmpty() || line.startsWith("#")) { if (line.isEmpty() || line.startsWith("#")) {
continue; continue;
} }
/* 2. 区块起始sectionName { */ // 区块起始
Matcher sec = SECTION_HEADER.matcher(line); Matcher sec = SECTION_HEADER.matcher(line);
if (sec.matches()) { if (sec.matches()) {
sectionStack.push(sec.group(1)); sectionStack.push(sec.group(1));
continue; continue;
} }
/* 3. 区块结束:} */ // 区块结束
if (BLOCK_END.matcher(line).matches()) { if (BLOCK_END.matcher(line).matches()) {
if (sectionStack.isEmpty()) { if (sectionStack.isEmpty()) {
throw new IllegalStateException("" + lineNo + " 行出现未配对的 '}'"); throw new IllegalStateException("" + lineNo + " 行出现未配对的 '}'");
@ -94,13 +87,13 @@ public final class CloudDSLParser {
continue; continue;
} }
/* 4. 键值对key = value */ // 键值对
Matcher kv = KEY_VALUE.matcher(line); Matcher kv = KEY_VALUE.matcher(line);
if (kv.matches()) { if (kv.matches()) {
String key = kv.group(1).trim(); String key = kv.group(1).trim();
String value = kv.group(2).trim(); String value = kv.group(2).trim();
/* 4.1 计算前缀(栈倒序,即从外到内) */ // 计算区块前缀
String prefix = String.join(".", (Iterable<String>) sectionStack::descendingIterator); String prefix = String.join(".", (Iterable<String>) sectionStack::descendingIterator);
if (!prefix.isEmpty()) { if (!prefix.isEmpty()) {
key = prefix + "." + key; key = prefix + "." + key;
@ -110,16 +103,16 @@ public final class CloudDSLParser {
continue; continue;
} }
/* 5. 无法识别的行 */ // 无法识别的行
throw new IllegalStateException("无法解析第 " + lineNo + " 行: " + raw); throw new IllegalStateException("无法解析第 " + lineNo + " 行: " + raw);
} }
/* 6. 检查括号是否全部闭合 */ // 检查区块是否全部闭合
if (!sectionStack.isEmpty()) { if (!sectionStack.isEmpty()) {
throw new IllegalStateException("文件结束但区块未闭合:" + sectionStack); throw new IllegalStateException("文件结束但区块未闭合:" + sectionStack);
} }
/* 7. 构造 Project 模型 */ // 构建 Project 模型
return Project.fromFlatMap(flatMap); return Project.fromFlatMap(flatMap);
} }
} }