From 6acfac396087dab8d4a59db411f058dc933a04b0 Mon Sep 17 00:00:00 2001
From: Luke This class uses an array for fast, constant-time access to corresponding command instances.
- * 用法示例: + * 用法示例: * $ snow init **/ diff --git a/src/main/java/org/jcnc/snow/cli/commands/InstallCommand.java b/src/main/java/org/jcnc/snow/cli/commands/InstallCommand.java index 09eb9b3c..ee47b440 100644 --- a/src/main/java/org/jcnc/snow/cli/commands/InstallCommand.java +++ b/src/main/java/org/jcnc/snow/cli/commands/InstallCommand.java @@ -14,7 +14,7 @@ import java.nio.file.Paths; * * *
- * 用法示例: + * 用法示例: * $ snow install **/ diff --git a/src/main/java/org/jcnc/snow/cli/commands/PublishCommand.java b/src/main/java/org/jcnc/snow/cli/commands/PublishCommand.java index 347aeffc..4e8d5de2 100644 --- a/src/main/java/org/jcnc/snow/cli/commands/PublishCommand.java +++ b/src/main/java/org/jcnc/snow/cli/commands/PublishCommand.java @@ -17,7 +17,7 @@ import java.nio.file.Paths; * * *
- * 用法示例: + * 用法示例: * $ snow publish **/ diff --git a/src/main/java/org/jcnc/snow/cli/commands/RunCommand.java b/src/main/java/org/jcnc/snow/cli/commands/RunCommand.java index 159dcb57..16c770ef 100644 --- a/src/main/java/org/jcnc/snow/cli/commands/RunCommand.java +++ b/src/main/java/org/jcnc/snow/cli/commands/RunCommand.java @@ -11,7 +11,7 @@ import org.jcnc.snow.pkg.tasks.RunTask; * * *
- * 用法示例: + * 用法示例: * $ snow run main.water **/ diff --git a/src/main/java/org/jcnc/snow/cli/commands/VersionCommand.java b/src/main/java/org/jcnc/snow/cli/commands/VersionCommand.java index 94fc6e79..e12bec7c 100644 --- a/src/main/java/org/jcnc/snow/cli/commands/VersionCommand.java +++ b/src/main/java/org/jcnc/snow/cli/commands/VersionCommand.java @@ -10,7 +10,7 @@ import org.jcnc.snow.cli.api.CLICommand; * * *
- * 用法示例: + * 用法示例: * $ snow version **/ diff --git a/src/main/java/org/jcnc/snow/cli/doc/README.md b/src/main/java/org/jcnc/snow/cli/doc/README.md index b823c200..7244a38f 100644 --- a/src/main/java/org/jcnc/snow/cli/doc/README.md +++ b/src/main/java/org/jcnc/snow/cli/doc/README.md @@ -4,10 +4,13 @@ ## 项目简介 -**CLI(Command Line Interface)** 是 Snow 项目对外的统一入口,提供从初始化项目、解析依赖、编译、打包、运行到发布的一站式指令集。 -该模块以**薄封装/强委托**为设计目标:在 CLI 层完成参数解析、子命令分发与生命周期编排,将实际业务逻辑(编译/运行/打包/依赖解析等)委托给 `pkg` 层的任务与工具执行。 +**CLI(Command Line Interface)** 是 Snow +项目对外的统一入口,提供从初始化项目、解析依赖、编译、打包、运行到发布的一站式指令集。 +该模块以**薄封装/强委托**为设计目标:在 CLI 层完成参数解析、子命令分发与生命周期编排,将实际业务逻辑(编译/运行/打包/依赖解析等)委托给 +`pkg` 层的任务与工具执行。 -核心入口类 `SnowCLI` 通过注册一组 `CLICommand` 子命令(如 `build` / `compile` / `run` / `publish` 等),统一处理**全局帮助**、**版本信息**、**未知命令兜底**与**退出码约定**,并支持在将来通过 `ServiceLoader`/注册表扩展新的命令。 +核心入口类 `SnowCLI` 通过注册一组 `CLICommand` 子命令(如 `build` / `compile` / `run` / `publish` 等),统一处理**全局帮助 +**、**版本信息**、**未知命令兜底**与**退出码约定**,并支持在将来通过 `ServiceLoader`/注册表扩展新的命令。 ## 核心功能 @@ -34,7 +37,8 @@ * DSL 解析:`CloudDSLParser` 读取 `project.cloud` 为 `Project` 模型 * 依赖解析与缓存:`DependencyResolver`(默认缓存目录位于用户主目录 `~/.snow/cache`) - * 生命周期编排:`LifecycleManager` / `LifecyclePhase` 注册并顺序执行任务(如 `RESOLVE_DEPENDENCIES` / `COMPILE` / `PACKAGE` / `PUBLISH` / `CLEAN` / `INIT` 等) + * 生命周期编排:`LifecycleManager` / `LifecyclePhase` 注册并顺序执行任务(如 `RESOLVE_DEPENDENCIES` / `COMPILE` / + `PACKAGE` / `PUBLISH` / `CLEAN` / `INIT` 等) * 具体任务:`CompileTask`、`RunTask`、`PackageTask`、`GenerateTask`、`CleanTask`、`PublishTask`(CLI 仅做参数组装与委托) * **错误处理与退出码约定** diff --git a/src/main/java/org/jcnc/snow/compiler/backend/alloc/RegisterAllocator.java b/src/main/java/org/jcnc/snow/compiler/backend/alloc/RegisterAllocator.java index c7a1c112..6df97a89 100644 --- a/src/main/java/org/jcnc/snow/compiler/backend/alloc/RegisterAllocator.java +++ b/src/main/java/org/jcnc/snow/compiler/backend/alloc/RegisterAllocator.java @@ -15,7 +15,7 @@ import java.util.Map; * 各虚拟寄存器实际对应的物理寄存器或栈槽号。采用简单的线性扫描分配策略。 * *
- * 分配过程如下: + * 分配过程如下: *
- * 分配顺序说明: + * 分配顺序说明: *
* 主要功能 *
* 支持的类型标记字符包括: B(byte)、S(short)、I(int)、L(long)、F(float)、D(double)。
- * 所有可能的类型转换均已覆盖,如下所示:
+ * 所有可能的类型转换均已覆盖,如下所示:
* B → S/I/L/F/D
* S → B/I/L/F/D
* I → B/S/L/F/D
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/builder/core/IRBuilderScope.java b/src/main/java/org/jcnc/snow/compiler/ir/builder/core/IRBuilderScope.java
index 08169f07..4df33b4d 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/builder/core/IRBuilderScope.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/builder/core/IRBuilderScope.java
@@ -23,26 +23,125 @@ import java.util.Map;
*/
public final class IRBuilderScope {
- /** 变量名到虚拟寄存器的映射表(本地变量) */
+ /**
+ * 结构体字段布局表:结构体名 → (字段名 → 槽位下标)
+ */
+ private static final Map
+ * 该方法用于维护结构体与其父类之间的映射关系。通过调用此方法,
+ * 可以为某个结构体名称指定其父结构体名称,并保存到全局的
+ * {@code STRUCT_PARENTS} 映射中。
+ *
+ * 查询逻辑如下:
+ *
+ *
+ *
+ *
+ *
- * 该方法用于维护结构体与其父类之间的映射关系。通过调用此方法, - * 可以为某个结构体名称指定其父结构体名称,并保存到全局的 - * {@code STRUCT_PARENTS} 映射中。 - *
- * - * @param structName 子结构体的名称,不能为空或 {@code null} - * @param parentName 父结构体的名称,不能为空、不能为 {@code null} 或空白 - */ - static void registerStructParent(String structName, String parentName) { - if (structName == null || parentName == null || parentName.isBlank()) return; - STRUCT_PARENTS.put(structName, parentName); - } - - /** - * 获取某个结构体的父结构体名称。 - *- * 查询逻辑如下: - *
StructName 为键注册到 {@link IRBuilderScope} 的全局布局表。* 使用说明 *
* func 名称(%0, %1, ...) {
* 指令0
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/core/IRInstruction.java b/src/main/java/org/jcnc/snow/compiler/ir/core/IRInstruction.java
index 2821d586..4977526b 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/core/IRInstruction.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/core/IRInstruction.java
@@ -1,6 +1,7 @@
package org.jcnc.snow.compiler.ir.core;
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
+
import java.util.List;
/**
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/doc/README.md b/src/main/java/org/jcnc/snow/compiler/ir/doc/README.md
index ce3e936f..edc47082 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/doc/README.md
+++ b/src/main/java/org/jcnc/snow/compiler/ir/doc/README.md
@@ -7,7 +7,9 @@
**IR(Intermediate Representation)** 是 Snow 编译器项目的核心模块,承担中间表示的构建、组织与管理任务。
它用于在前端语法分析与后端目标代码生成之间,提供结构清晰、便于优化和转换的抽象表示形式。
-本 IR 模块采用**类 SSA(Static Single Assignment)** 的思路:以**虚拟寄存器**为中心组织数据流,配合**统一的操作码集(`IROpCode`)**、**访问者模式(`IRVisitor`)**与**构建器体系**,形成可扩展、可调试、且便于后续优化与代码生成的 IR 层。
+本 IR 模块采用**类 SSA(Static Single Assignment)** 的思路:以**虚拟寄存器**为中心组织数据流,配合*
+*统一的操作码集(`IROpCode`)**、**访问者模式(`IRVisitor`)**与**构建器体系**,形成可扩展、可调试、且便于后续优化与代码生成的
+IR 层。
## 核心功能
@@ -36,7 +38,8 @@
* **操作码与类型提升**
* `IROpCode` 定义全量操作码(整数/浮点不同位宽的算术、比较、转换,`LOAD/STORE/CONST`,`JUMP/LABEL/CALL/RET` 等)
- * `IROpCodeMappings`/`ExpressionUtils`/`ComparisonUtils` 负责从 AST 运算符与操作数类型推导到具体 IR 操作码,并进行必要的类型提升与比较归类
+ * `IROpCodeMappings`/`ExpressionUtils`/`ComparisonUtils` 负责从 AST 运算符与操作数类型推导到具体 IR
+ 操作码,并进行必要的类型提升与比较归类
* **IR 打印与调试支持**
* `IRPrinter`:基于访问者输出 IR(便于调试/测试)
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/instruction/BinaryOperationInstruction.java b/src/main/java/org/jcnc/snow/compiler/ir/instruction/BinaryOperationInstruction.java
index cd83ddec..11da45ad 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/instruction/BinaryOperationInstruction.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/instruction/BinaryOperationInstruction.java
@@ -17,16 +17,24 @@ import java.util.List;
*/
public final class BinaryOperationInstruction extends IRInstruction {
- /** 指令操作符,如 ADD_I32、SUB_I32 等,取自 IROpCode 枚举 */
+ /**
+ * 指令操作符,如 ADD_I32、SUB_I32 等,取自 IROpCode 枚举
+ */
private final IROpCode op;
- /** 运算结果将写入的目标虚拟寄存器 */
+ /**
+ * 运算结果将写入的目标虚拟寄存器
+ */
private final IRVirtualRegister dest;
- /** 运算的左操作数 */
+ /**
+ * 运算的左操作数
+ */
private final IRValue lhs;
- /** 运算的右操作数 */
+ /**
+ * 运算的右操作数
+ */
private final IRValue rhs;
/**
@@ -38,10 +46,10 @@ public final class BinaryOperationInstruction extends IRInstruction {
* @param rhs 右操作数
*/
public BinaryOperationInstruction(IROpCode op, IRVirtualRegister dest, IRValue lhs, IRValue rhs) {
- this.op = op;
+ this.op = op;
this.dest = dest;
- this.lhs = lhs;
- this.rhs = rhs;
+ this.lhs = lhs;
+ this.rhs = rhs;
}
/**
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/instruction/CallInstruction.java b/src/main/java/org/jcnc/snow/compiler/ir/instruction/CallInstruction.java
index dd963d97..b81856b4 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/instruction/CallInstruction.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/instruction/CallInstruction.java
@@ -19,11 +19,17 @@ import java.util.List;
* 并且不会参与寄存器分配。
*/
public class CallInstruction extends IRInstruction {
- /** 调用结果目标寄存器;void 返回时可为 null */
+ /**
+ * 调用结果目标寄存器;void 返回时可为 null
+ */
private final IRVirtualRegister dest;
- /** 被调用的函数名(含模块限定) */
+ /**
+ * 被调用的函数名(含模块限定)
+ */
private final String functionName;
- /** 实参列表 */
+ /**
+ * 实参列表
+ */
private final List arguments;
public CallInstruction(IRVirtualRegister dest,
@@ -40,13 +46,17 @@ public class CallInstruction extends IRInstruction {
return IROpCode.CALL;
}
- /** 仅在函数有返回值时才暴露目标寄存器 */
+ /**
+ * 仅在函数有返回值时才暴露目标寄存器
+ */
@Override
public IRVirtualRegister dest() {
return isVoidReturn() ? null : dest;
}
- /** 操作数列表: void 调用不包含 dest */
+ /**
+ * 操作数列表: void 调用不包含 dest
+ */
@Override
public List operands() {
List ops = new ArrayList<>();
@@ -71,7 +81,10 @@ public class CallInstruction extends IRInstruction {
}
// === 帮助方法 ===
- /** 判断被调函数是否返回 void */
+
+ /**
+ * 判断被调函数是否返回 void
+ */
private boolean isVoidReturn() {
return "void".equals(GlobalFunctionTable.getReturnType(functionName));
}
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/instruction/IRAddInstruction.java b/src/main/java/org/jcnc/snow/compiler/ir/instruction/IRAddInstruction.java
index 4df8d8dc..b5a61897 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/instruction/IRAddInstruction.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/instruction/IRAddInstruction.java
@@ -17,13 +17,19 @@ import java.util.List;
*/
public class IRAddInstruction extends IRInstruction {
- /** 运算结果存放的目标虚拟寄存器 */
+ /**
+ * 运算结果存放的目标虚拟寄存器
+ */
private final IRVirtualRegister dest;
- /** 左操作数 */
+ /**
+ * 左操作数
+ */
private final IRValue lhs;
- /** 右操作数 */
+ /**
+ * 右操作数
+ */
private final IRValue rhs;
/**
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/instruction/IRCompareJumpInstruction.java b/src/main/java/org/jcnc/snow/compiler/ir/instruction/IRCompareJumpInstruction.java
index 74d472db..6c9c8cf8 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/instruction/IRCompareJumpInstruction.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/instruction/IRCompareJumpInstruction.java
@@ -6,8 +6,8 @@ import org.jcnc.snow.compiler.ir.core.IRVisitor;
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
/**
- * “比较 + 条件跳转” 复合指令:
- * if ( left right ) jump targetLabel;
+ * “比较 + 条件跳转” 复合指令:
+ * if ( left right ) jump targetLabel;
*
* 其中 cmpOp 只能是 IROpCode.CMP_* 六种比较操作码。
*/
@@ -22,7 +22,7 @@ public final class IRCompareJumpInstruction extends IRInstruction {
IRVirtualRegister right,
String targetLabel) {
this.cmpOp = cmpOp;
- this.left = left;
+ this.left = left;
this.right = right;
this.targetLabel = targetLabel;
}
@@ -32,16 +32,26 @@ public final class IRCompareJumpInstruction extends IRInstruction {
return cmpOp;
}
- public IRVirtualRegister left() { return left; }
- public IRVirtualRegister right() { return right; }
- public String label() { return targetLabel; }
+ public IRVirtualRegister left() {
+ return left;
+ }
+
+ public IRVirtualRegister right() {
+ return right;
+ }
+
+ public String label() {
+ return targetLabel;
+ }
@Override
public String toString() {
return cmpOp + " " + left + ", " + right + " -> " + targetLabel;
}
- /** 暂无访问者实现,留空 */
+ /**
+ * 暂无访问者实现,留空
+ */
@Override
public void accept(IRVisitor visitor) { /* no-op */ }
}
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/instruction/IRJumpInstruction.java b/src/main/java/org/jcnc/snow/compiler/ir/instruction/IRJumpInstruction.java
index 96b83ce5..3112b9ec 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/instruction/IRJumpInstruction.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/instruction/IRJumpInstruction.java
@@ -12,7 +12,9 @@ import org.jcnc.snow.compiler.ir.core.IRVisitor;
*/
public class IRJumpInstruction extends IRInstruction {
- /** 跳转目标的标签名 */
+ /**
+ * 跳转目标的标签名
+ */
private final String label;
/**
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/instruction/IRLabelInstruction.java b/src/main/java/org/jcnc/snow/compiler/ir/instruction/IRLabelInstruction.java
index 8198b44d..e73262a3 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/instruction/IRLabelInstruction.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/instruction/IRLabelInstruction.java
@@ -31,7 +31,9 @@ public final class IRLabelInstruction extends IRInstruction {
return name + ":";
}
- /** 目前尚未对 Label 做访问者处理,空实现即可 */
+ /**
+ * 目前尚未对 Label 做访问者处理,空实现即可
+ */
@Override
public void accept(IRVisitor visitor) {
/* no-op */
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/instruction/IRReturnInstruction.java b/src/main/java/org/jcnc/snow/compiler/ir/instruction/IRReturnInstruction.java
index 0aa50715..3bdce77b 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/instruction/IRReturnInstruction.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/instruction/IRReturnInstruction.java
@@ -16,7 +16,9 @@ import java.util.List;
*/
public class IRReturnInstruction extends IRInstruction {
- /** 要返回的值,可以是常量、虚拟寄存器等 */
+ /**
+ * 要返回的值,可以是常量、虚拟寄存器等
+ */
private final IRValue returnValue;
/**
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/instruction/LoadConstInstruction.java b/src/main/java/org/jcnc/snow/compiler/ir/instruction/LoadConstInstruction.java
index 3ef925a7..c5409e80 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/instruction/LoadConstInstruction.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/instruction/LoadConstInstruction.java
@@ -17,10 +17,14 @@ import java.util.List;
*/
public final class LoadConstInstruction extends IRInstruction {
- /** 要加载的常量值,类型为 IRConstant */
+ /**
+ * 要加载的常量值,类型为 IRConstant
+ */
private final IRConstant k;
- /** 存放常量结果的目标虚拟寄存器 */
+ /**
+ * 存放常量结果的目标虚拟寄存器
+ */
private final IRVirtualRegister dest;
/**
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/instruction/ReturnInstruction.java b/src/main/java/org/jcnc/snow/compiler/ir/instruction/ReturnInstruction.java
index f689e995..351369e5 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/instruction/ReturnInstruction.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/instruction/ReturnInstruction.java
@@ -11,7 +11,7 @@ import java.util.List;
/**
* ReturnInstruction —— 表示函数返回指令,格式: RET 或 RET
*
- * 此类用于描述函数执行完毕后的返回操作。支持两种返回形式:
+ * 此类用于描述函数执行完毕后的返回操作。支持两种返回形式:
* - 无返回值(void): 生成无参的 RET 指令
* - 有返回值: 将指定虚拟寄存器中的值返回给调用者
*
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/instruction/UnaryOperationInstruction.java b/src/main/java/org/jcnc/snow/compiler/ir/instruction/UnaryOperationInstruction.java
index 0e02b764..06628f87 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/instruction/UnaryOperationInstruction.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/instruction/UnaryOperationInstruction.java
@@ -14,7 +14,7 @@ import java.util.List;
* 用于对单个操作数 val 执行指定的一元运算 OP(例如取负 NEG),
* 并将结果写入目标虚拟寄存器 dest。
*
- * 支持的操作由 {@link IROpCode} 定义,目前常见的一元操作包括:
+ * 支持的操作由 {@link IROpCode} 定义,目前常见的一元操作包括:
*
* - NEG_I32 —— 整数取负: dest = -val
* - (可扩展)逻辑非、按位非等
@@ -22,13 +22,19 @@ import java.util.List;
*/
public final class UnaryOperationInstruction extends IRInstruction {
- /** 一元运算操作符(如 NEG_I32) */
+ /**
+ * 一元运算操作符(如 NEG_I32)
+ */
private final IROpCode op;
- /** 运算结果写入的目标虚拟寄存器 */
+ /**
+ * 运算结果写入的目标虚拟寄存器
+ */
private final IRVirtualRegister dest;
- /** 被操作的值(唯一操作数) */
+ /**
+ * 被操作的值(唯一操作数)
+ */
private final IRValue val;
/**
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/utils/ComparisonUtils.java b/src/main/java/org/jcnc/snow/compiler/ir/utils/ComparisonUtils.java
index 75f388d6..c6c824e3 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/utils/ComparisonUtils.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/utils/ComparisonUtils.java
@@ -15,8 +15,8 @@ import java.util.Map;
* 该类主要用于根据左右操作数的静态类型,自动选择正确的 IR 层比较操作码。
* 支持自动类型提升,保证 int、long、float、double 等类型的比较均能得到正确的 IR 指令。
*
- *
- * 类型判定支持:
+ *
+ * 类型判定支持:
*
* - 字面量后缀: 支持 B/S/I/L/F/D(大小写均可)
* - 浮点数支持: 如无后缀但有小数点,视为 double
@@ -24,7 +24,8 @@ import java.util.Map;
*
*/
public final class ComparisonUtils {
- private ComparisonUtils() {}
+ private ComparisonUtils() {
+ }
/**
* 判断给定字符串是否为受支持的比较运算符(==, !=, <, >, <=, >=)。
@@ -39,14 +40,14 @@ public final class ComparisonUtils {
}
/**
- * 返回类型宽度优先级(越大代表类型越宽)。类型对应的优先级:
- * - D (double): 6
- * - F (float): 5
- * - L (long): 4
- * - I (int): 3
- * - S (short): 2
- * - B (byte): 1
- * - 未知类型: 0
+ * 返回类型宽度优先级(越大代表类型越宽)。类型对应的优先级:
+ * - D (double): 6
+ * - F (float): 5
+ * - L (long): 4
+ * - I (int): 3
+ * - S (short): 2
+ * - B (byte): 1
+ * - 未知类型: 0
*
* @param p 类型标记字符
* @return 类型优先级数值
@@ -129,12 +130,18 @@ public final class ComparisonUtils {
final String type = variables.get(name);
if (type != null) {
switch (type) {
- case "byte": return 'B';
- case "short": return 'S';
- case "int": return 'I';
- case "long": return 'L';
- case "float": return 'F';
- case "double": return 'D';
+ case "byte":
+ return 'B';
+ case "short":
+ return 'S';
+ case "int":
+ return 'I';
+ case "long":
+ return 'L';
+ case "float":
+ return 'F';
+ case "double":
+ return 'D';
}
}
}
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/utils/ExpressionUtils.java b/src/main/java/org/jcnc/snow/compiler/ir/utils/ExpressionUtils.java
index 43aa9767..8cebf624 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/utils/ExpressionUtils.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/utils/ExpressionUtils.java
@@ -15,34 +15,39 @@ import java.util.Map;
* 表达式分析与操作符选择工具类。
*
* 主要功能:
- * - 解析字面量常量,自动推断类型
- * - 自动匹配并选择适合的算术/比较操作码
- * - 表达式类型的合并与类型提升
- * - 支持线程隔离的函数级默认类型后缀
+ * - 解析字面量常量,自动推断类型
+ * - 自动匹配并选择适合的算术/比较操作码
+ * - 表达式类型的合并与类型提升
+ * - 支持线程隔离的函数级默认类型后缀
*/
public final class ExpressionUtils {
- private ExpressionUtils() {}
-
- // ───────────── 线程级默认类型后缀 ─────────────
-
/**
* 当前线程的默认类型后缀(如当前函数返回类型等),用于类型推断兜底。
*/
private static final ThreadLocal DEFAULT_SUFFIX =
ThreadLocal.withInitial(() -> '\0');
+ // ───────────── 线程级默认类型后缀 ─────────────
+
+ private ExpressionUtils() {
+ }
+
/**
* 设置当前线程的默认类型后缀。
*
* @param suffix 类型后缀字符(b/s/i/l/f/d),'\0'表示无
*/
- public static void setDefaultSuffix(char suffix) { DEFAULT_SUFFIX.set(suffix); }
+ public static void setDefaultSuffix(char suffix) {
+ DEFAULT_SUFFIX.set(suffix);
+ }
/**
* 清除当前线程的默认类型后缀,重置为无。
*/
- public static void clearDefaultSuffix() { DEFAULT_SUFFIX.set('\0'); }
+ public static void clearDefaultSuffix() {
+ DEFAULT_SUFFIX.set('\0');
+ }
// ───────────── 字面量常量解析 ─────────────
@@ -73,19 +78,19 @@ public final class ExpressionUtils {
: Character.toLowerCase(value.charAt(value.length() - 1));
String digits = switch (suffix) {
- case 'b','s','l','f','d' -> value.substring(0, value.length() - 1);
+ case 'b', 's', 'l', 'f', 'd' -> value.substring(0, value.length() - 1);
default -> {
// 无后缀,优先参考变量类型
if (ctx.getVarType() != null) {
String t = ctx.getVarType();
suffix = switch (t) {
- case "byte" -> 'b';
- case "short" -> 's';
- case "int" -> 'i';
- case "long" -> 'l';
- case "float" -> 'f';
+ case "byte" -> 'b';
+ case "short" -> 's';
+ case "int" -> 'i';
+ case "long" -> 'l';
+ case "float" -> 'f';
case "double" -> 'd';
- default -> '\0';
+ default -> '\0';
};
}
yield value;
@@ -99,7 +104,7 @@ public final class ExpressionUtils {
case 'l' -> new IRConstant(Long.parseLong(digits));
case 'f' -> new IRConstant(Float.parseFloat(digits));
case 'd' -> new IRConstant(Double.parseDouble(digits));
- default -> looksLikeFloat(digits)
+ default -> looksLikeFloat(digits)
? new IRConstant(Double.parseDouble(digits))
: new IRConstant(Integer.parseInt(digits));
};
@@ -121,7 +126,7 @@ public final class ExpressionUtils {
case 'l' -> IROpCode.NEG_L64;
case 'f' -> IROpCode.NEG_F32;
case 'd' -> IROpCode.NEG_D64;
- default -> IROpCode.NEG_I32; // 无法推断或为 int
+ default -> IROpCode.NEG_I32; // 无法推断或为 int
};
}
@@ -173,7 +178,7 @@ public final class ExpressionUtils {
if (node instanceof NumberLiteralNode(String value, NodeContext _)) {
char last = Character.toLowerCase(value.charAt(value.length() - 1));
return switch (last) {
- case 'b','s','i','l','f','d' -> last;
+ case 'b', 's', 'i', 'l', 'f', 'd' -> last;
default -> looksLikeFloat(value) ? 'd' : '\0';
};
}
@@ -236,7 +241,7 @@ public final class ExpressionUtils {
case 'l' -> IROpCodeMappings.OP_L64;
case 'f' -> IROpCodeMappings.OP_F32;
case 'd' -> IROpCodeMappings.OP_D64;
- default -> IROpCodeMappings.OP_I32;
+ default -> IROpCodeMappings.OP_I32;
};
return table.get(op);
}
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/value/IRVirtualRegister.java b/src/main/java/org/jcnc/snow/compiler/ir/value/IRVirtualRegister.java
index cb022f8e..942abc88 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/value/IRVirtualRegister.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/value/IRVirtualRegister.java
@@ -8,13 +8,13 @@ import org.jcnc.snow.compiler.ir.core.IRValue;
* 在 IR 系统中,虚拟寄存器用于存储每个中间计算结果,是 SSA(Static Single Assignment)形式的核心。
* 每个虚拟寄存器在程序中只被赋值一次,其值来源于一条明确的指令输出。
*
- * 特点:
+ * 特点:
*
* - 每个寄存器有唯一编号 {@code id},由 {@code IRFunction.newRegister()} 自动生成
* - 实现 {@link IRValue} 接口,可作为 IRInstruction 的操作数
* - 具备良好的打印与调试格式: %id
*
- *
+ *
* 适用于表达式求值、参数传递、函数返回值、临时变量等所有中间值场景。
*
* @param id 寄存器的唯一编号,通常从 0 开始递增
diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerContext.java b/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerContext.java
index 70cf64e0..8fbdcb5e 100644
--- a/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerContext.java
+++ b/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerContext.java
@@ -21,19 +21,29 @@ public class LexerContext {
/* ───────────────────────────────── 私有字段 ───────────────────────────────── */
- /** 源代码字符串(换行符已标准化为 \n) */
+ /**
+ * 源代码字符串(换行符已标准化为 \n)
+ */
private final String source;
- /** 当前扫描位置(自 0 起算的全局偏移量) */
+ /**
+ * 当前扫描位置(自 0 起算的全局偏移量)
+ */
private int pos = 0;
- /** 当前行号(从 1 开始) */
+ /**
+ * 当前行号(从 1 开始)
+ */
private int line = 1;
- /** 当前列号(从 1 开始) */
+ /**
+ * 当前列号(从 1 开始)
+ */
private int col = 1;
- /** 上一个字符对应的列号(用于异常定位) */
+ /**
+ * 上一个字符对应的列号(用于异常定位)
+ */
private int lastCol = 1;
/* ──────────────────────────────── 构造 & 基本信息 ─────────────────────────────── */
@@ -122,15 +132,31 @@ public class LexerContext {
/* ──────────────────────────────── 坐标查询 ─────────────────────────────── */
- /** @return 当前行号 (1-based) */
- public int getLine() { return line; }
+ /**
+ * @return 当前行号 (1-based)
+ */
+ public int getLine() {
+ return line;
+ }
- /** @return 当前列号 (1-based) */
- public int getCol() { return col; }
+ /**
+ * @return 当前列号 (1-based)
+ */
+ public int getCol() {
+ return col;
+ }
- /** @return 上一个字符的列号 */
- public int getLastCol() { return lastCol; }
+ /**
+ * @return 上一个字符的列号
+ */
+ public int getLastCol() {
+ return lastCol;
+ }
- /** @return 当前指针在源文件中的全局偏移 (0-based) */
- public int getPos() { return pos; }
+ /**
+ * @return 当前指针在源文件中的全局偏移 (0-based)
+ */
+ public int getPos() {
+ return pos;
+ }
}
diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerEngine.java b/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerEngine.java
index 6b5c3ba5..0984c983 100644
--- a/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerEngine.java
+++ b/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerEngine.java
@@ -1,11 +1,9 @@
package org.jcnc.snow.compiler.lexer.core;
-import org.jcnc.snow.common.SnowConfig;
import org.jcnc.snow.compiler.lexer.base.TokenScanner;
import org.jcnc.snow.compiler.lexer.scanners.*;
import org.jcnc.snow.compiler.lexer.token.Token;
import org.jcnc.snow.compiler.lexer.token.TokenType;
-import org.jcnc.snow.compiler.lexer.utils.TokenPrinter;
import java.io.File;
import java.util.ArrayList;
diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/core/LexicalException.java b/src/main/java/org/jcnc/snow/compiler/lexer/core/LexicalException.java
index 1518a70c..757e3078 100644
--- a/src/main/java/org/jcnc/snow/compiler/lexer/core/LexicalException.java
+++ b/src/main/java/org/jcnc/snow/compiler/lexer/core/LexicalException.java
@@ -10,29 +10,36 @@ package org.jcnc.snow.compiler.lexer.core;
*
- 完全禁止 Java 堆栈信息输出,使命令行输出保持整洁。
*
- * 例: + * 例: * Main.snow: 行 7, 列 20: 词法错误: 非法字符序列 '@' **/ public class LexicalException extends RuntimeException { - /** 错误发生的行号(从1开始) */ + /** + * 错误发生的行号(从1开始) + */ private final int line; - /** 错误发生的列号(从1开始) */ + /** + * 错误发生的列号(从1开始) + */ private final int column; - /** 错误原因 */ + /** + * 错误原因 + */ private final String reason; /** * 构造词法异常 - * @param reason 错误原因(如: 非法字符描述) - * @param line 出错行号 - * @param column 出错列号 + * + * @param reason 错误原因(如: 非法字符描述) + * @param line 出错行号 + * @param column 出错列号 */ public LexicalException(String reason, int line, int column) { // 错误描述直接为 reason,禁止异常堆栈打印 super(reason, null, false, false); this.reason = reason; - this.line = line; + this.line = line; this.column = column; } @@ -40,23 +47,34 @@ public class LexicalException extends RuntimeException { * 屏蔽异常堆栈填充(始终不打印堆栈信息) */ @Override - public synchronized Throwable fillInStackTrace() { return this; } + public synchronized Throwable fillInStackTrace() { + return this; + } /** * 获取出错的行号 + * * @return 行号 */ - public int getLine() { return line; } + public int getLine() { + return line; + } /** * 获取出错的列号 + * * @return 列号 */ - public int getColumn() { return column; } + public int getColumn() { + return column; + } /** * 获取出错的描述 + * * @return 出错描述 */ - public String getReason() { return reason; } + public String getReason() { + return reason; + } } diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/AbstractTokenScanner.java b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/AbstractTokenScanner.java index a5397444..ac8ec112 100644 --- a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/AbstractTokenScanner.java +++ b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/AbstractTokenScanner.java @@ -1,7 +1,7 @@ package org.jcnc.snow.compiler.lexer.scanners; -import org.jcnc.snow.compiler.lexer.core.LexerContext; import org.jcnc.snow.compiler.lexer.base.TokenScanner; +import org.jcnc.snow.compiler.lexer.core.LexerContext; import org.jcnc.snow.compiler.lexer.token.Token; import java.util.List; diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/SymbolTokenScanner.java b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/SymbolTokenScanner.java index 3810de8a..d4d51c40 100644 --- a/src/main/java/org/jcnc/snow/compiler/lexer/scanners/SymbolTokenScanner.java +++ b/src/main/java/org/jcnc/snow/compiler/lexer/scanners/SymbolTokenScanner.java @@ -7,7 +7,7 @@ import org.jcnc.snow.compiler.lexer.token.TokenType; /** * 符号扫描器: 识别常见的单字符符号,如冒号、逗号、括号和算术符号。 *
- * 支持的符号包括: + * 支持的符号包括: *
- * 输出格式: + * 输出格式: *
* line col type lexeme
* ----------------------------------------------------
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/AssignmentNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/AssignmentNode.java
index 34b387c0..c4384c6e 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/ast/AssignmentNode.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/AssignmentNode.java
@@ -1,8 +1,8 @@
package org.jcnc.snow.compiler.parser.ast;
import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
-import org.jcnc.snow.compiler.parser.ast.base.StatementNode;
import org.jcnc.snow.compiler.parser.ast.base.NodeContext;
+import org.jcnc.snow.compiler.parser.ast.base.StatementNode;
/**
* {@code AssignmentNode} 表示抽象语法树(AST)中的赋值语句节点。
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/DeclarationNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/DeclarationNode.java
index af2cdae6..52a005e3 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/ast/DeclarationNode.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/DeclarationNode.java
@@ -1,8 +1,8 @@
package org.jcnc.snow.compiler.parser.ast;
import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
-import org.jcnc.snow.compiler.parser.ast.base.StatementNode;
import org.jcnc.snow.compiler.parser.ast.base.NodeContext;
+import org.jcnc.snow.compiler.parser.ast.base.StatementNode;
import java.util.Optional;
@@ -14,13 +14,19 @@ import java.util.Optional;
*/
public class DeclarationNode implements StatementNode {
- /** 声明的变量名称。 */
+ /**
+ * 声明的变量名称。
+ */
private final String name;
- /** 变量的数据类型(如 "int", "string")。 */
+ /**
+ * 变量的数据类型(如 "int", "string")。
+ */
private final String type;
- /** 是否为常量声明(true 表示 const 变量,false 表示普通变量)。 */
+ /**
+ * 是否为常量声明(true 表示 const 变量,false 表示普通变量)。
+ */
private final boolean isConst;
/**
@@ -29,7 +35,9 @@ public class DeclarationNode implements StatementNode {
*/
private final Optional initializer;
- /** 节点上下文信息(如源码中的行号、列号等)。 */
+ /**
+ * 节点上下文信息(如源码中的行号、列号等)。
+ */
private final NodeContext context;
/**
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/ExpressionStatementNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/ExpressionStatementNode.java
index 7a52cc42..8adb78ad 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/ast/ExpressionStatementNode.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/ExpressionStatementNode.java
@@ -1,8 +1,8 @@
package org.jcnc.snow.compiler.parser.ast;
import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
-import org.jcnc.snow.compiler.parser.ast.base.StatementNode;
import org.jcnc.snow.compiler.parser.ast.base.NodeContext;
+import org.jcnc.snow.compiler.parser.ast.base.StatementNode;
/**
* {@code ExpressionStatementNode} 表示抽象语法树(AST)中的表达式语句节点。
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/IfNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/IfNode.java
index ecc0dd10..6490e61c 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/ast/IfNode.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/IfNode.java
@@ -1,8 +1,8 @@
package org.jcnc.snow.compiler.parser.ast;
import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
-import org.jcnc.snow.compiler.parser.ast.base.StatementNode;
import org.jcnc.snow.compiler.parser.ast.base.NodeContext;
+import org.jcnc.snow.compiler.parser.ast.base.StatementNode;
import java.util.List;
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/ImportNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/ImportNode.java
index ab4bb90b..8131d38b 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/ast/ImportNode.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/ImportNode.java
@@ -6,7 +6,7 @@ import org.jcnc.snow.compiler.parser.ast.base.NodeContext;
/**
* {@code ImportNode} 表示抽象语法树(AST)中的 import 语句节点。
*
- * import 语句用于引入外部模块或库文件,其语法形式一般为:
+ * import 语句用于引入外部模块或库文件,其语法形式一般为:
* {@code import my.module;}
*
*
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/IndexExpressionNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/IndexExpressionNode.java
index a33caa90..fc67ae53 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/ast/IndexExpressionNode.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/IndexExpressionNode.java
@@ -32,6 +32,7 @@ public record IndexExpressionNode(
/**
* 返回形如 "arr[i]" 的字符串表示。
+ *
* @return 表达式的字符串形式
*/
@Override
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/MemberExpressionNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/MemberExpressionNode.java
index 8ab233bf..b9c56340 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/ast/MemberExpressionNode.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/MemberExpressionNode.java
@@ -10,9 +10,9 @@ import org.jcnc.snow.compiler.parser.ast.base.NodeContext;
* 成员访问常见于结构体、模块、对象导入等上下文中,是表达式链中常见的构件之一。
*
*
- * @param object 左侧对象表达式,表示成员所属的作用域或容器
- * @param member 要访问的成员名称(字段名或方法名)
- * @param context 节点上下文信息(包含行号、列号等)
+ * @param object 左侧对象表达式,表示成员所属的作用域或容器
+ * @param member 要访问的成员名称(字段名或方法名)
+ * @param context 节点上下文信息(包含行号、列号等)
*/
public record MemberExpressionNode(
ExpressionNode object,
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/ModuleNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/ModuleNode.java
index 836c547b..9924f462 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/ast/ModuleNode.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/ModuleNode.java
@@ -38,7 +38,7 @@ public record ModuleNode(
* 列出模块名、导入、全局变量、结构体、函数等简明内容。
*
* @return 字符串形式,如
- * Module(name=main, imports=[math], globals=[int x], structs=[Foo], functions=[bar])
+ * Module(name=main, imports=[math], globals=[int x], structs=[Foo], functions=[bar])
*/
@Override
public String toString() {
@@ -59,10 +59,10 @@ public record ModuleNode(
functions.forEach(f -> funcJ.add(f.name()));
// 5) 综合输出
- return "Module(name=" + name +
- ", imports=[" + impJ + "]" +
- ", globals=[" + globJ + "]" +
- ", structs=[" + structJ + "]" +
- ", functions=[" + funcJ + "])";
+ return "Module(name=" + name +
+ ", imports=[" + impJ + "]" +
+ ", globals=[" + globJ + "]" +
+ ", structs=[" + structJ + "]" +
+ ", functions=[" + funcJ + "])";
}
}
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/NumberLiteralNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/NumberLiteralNode.java
index 6806112d..f0d6beb1 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/ast/NumberLiteralNode.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/NumberLiteralNode.java
@@ -11,8 +11,8 @@ import org.jcnc.snow.compiler.parser.ast.base.NodeContext;
* 在语义分析或类型推导阶段再行解析为具体数值类型。
*
*
- * @param value 数字字面量的原始字符串表示
- * @param context 节点上下文信息(包含行号、列号等)
+ * @param value 数字字面量的原始字符串表示
+ * @param context 节点上下文信息(包含行号、列号等)
*/
public record NumberLiteralNode(
String value,
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/ReturnNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/ReturnNode.java
index 15d6297e..eeb18eab 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/ast/ReturnNode.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/ReturnNode.java
@@ -1,8 +1,8 @@
package org.jcnc.snow.compiler.parser.ast;
import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
-import org.jcnc.snow.compiler.parser.ast.base.StatementNode;
import org.jcnc.snow.compiler.parser.ast.base.NodeContext;
+import org.jcnc.snow.compiler.parser.ast.base.StatementNode;
import java.util.Optional;
@@ -12,7 +12,7 @@ import java.util.Optional;
* return 语句用于从当前函数中返回控制权,并可携带一个可选的返回值表达式。
*
*
- * 示例:
+ * 示例:
*
* - {@code return;}
* - {@code return x + 1;}
@@ -21,10 +21,14 @@ import java.util.Optional;
*/
public class ReturnNode implements StatementNode {
- /** 可选的返回值表达式 */
+ /**
+ * 可选的返回值表达式
+ */
private final Optional expression;
- /** 节点上下文信息(包含行号、列号等) */
+ /**
+ * 节点上下文信息(包含行号、列号等)
+ */
private final NodeContext context;
/**
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/StringLiteralNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/StringLiteralNode.java
index dd0e61fc..9f264231 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/ast/StringLiteralNode.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/StringLiteralNode.java
@@ -10,8 +10,8 @@ import org.jcnc.snow.compiler.parser.ast.base.NodeContext;
* 节点内部仅保存不带引号的字符串内容,便于后续语义处理或编码。
*
*
- * @param value 字符串常量的内容,原始值中不包含双引号
- * @param context 节点上下文信息(包含行号、列号等)
+ * @param value 字符串常量的内容,原始值中不包含双引号
+ * @param context 节点上下文信息(包含行号、列号等)
*/
public record StringLiteralNode(
String value,
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/StructNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/StructNode.java
index b5581575..81bd10ae 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/ast/StructNode.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/StructNode.java
@@ -20,7 +20,7 @@ import java.util.StringJoiner;
* @param name 结构体名称
* @param parent 父类名称(无继承时为 {@code null})
* @param fields 字段声明列表
- * @param inits 构造函数(可为 null)
+ * @param inits 构造函数(可为 null)
* @param methods 方法列表
* @param context 源码位置信息
*/
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/UnaryExpressionNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/UnaryExpressionNode.java
index c30d7ed2..4111f759 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/ast/UnaryExpressionNode.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/UnaryExpressionNode.java
@@ -6,12 +6,12 @@ import org.jcnc.snow.compiler.parser.ast.base.NodeContext;
/**
* {@code UnaryExpressionNode} —— 前缀一元运算 AST 节点。
*
- * 代表两种受支持的一元前缀表达式:
+ *
代表两种受支持的一元前缀表达式:
*
* - 取负: {@code -x}
* - 逻辑非: {@code !x}
*
- *
+ *
* {@link #equals(Object)}、{@link #hashCode()} 等方法。
*
* @param operator 一元运算符(仅 "-" 或 "!")
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/base/ExpressionNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/base/ExpressionNode.java
index e8db6452..52949231 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/ast/base/ExpressionNode.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/base/ExpressionNode.java
@@ -11,4 +11,5 @@ package org.jcnc.snow.compiler.parser.ast.base;
* 所有实现此接口的节点可参与表达式求值、语义分析、类型检查与中间代码生成等处理流程。
*
*/
-public interface ExpressionNode extends Node {}
\ No newline at end of file
+public interface ExpressionNode extends Node {
+}
\ No newline at end of file
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/base/Node.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/base/Node.java
index e5d33eb8..794e3780 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/ast/base/Node.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/base/Node.java
@@ -4,7 +4,7 @@ package org.jcnc.snow.compiler.parser.ast.base;
* {@code Node} 是抽象语法树(AST)中所有语法节点的统一根接口。
*
* 作为标记接口(Marker Interface),该接口定义 3 个方法: line()、column() 和 file() 用于定位错误,
- * 主要用于统一标识并组织 AST 体系中的各种语法构件节点,包括:
+ * 主要用于统一标识并组织 AST 体系中的各种语法构件节点,包括:
*
*
* - {@link ExpressionNode}: 表达式节点,如常量、变量引用、函数调用等
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/base/StatementNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/base/StatementNode.java
index b4db2cb3..f1dbee85 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/ast/base/StatementNode.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/base/StatementNode.java
@@ -8,4 +8,5 @@ package org.jcnc.snow.compiler.parser.ast.base;
* 实现此接口的类应表示程序在运行时执行的具体语法行为。
*
*/
-public interface StatementNode extends Node {}
+public interface StatementNode extends Node {
+}
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/context/ParseError.java b/src/main/java/org/jcnc/snow/compiler/parser/context/ParseError.java
index c32d95ea..af906d80 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/context/ParseError.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/context/ParseError.java
@@ -9,13 +9,21 @@ package org.jcnc.snow.compiler.parser.context;
*/
public class ParseError {
- /** 出错的文件名 */
+ /**
+ * 出错的文件名
+ */
private final String file;
- /** 出错的行号 */
+ /**
+ * 出错的行号
+ */
private final int line;
- /** 出错的列号 */
+ /**
+ * 出错的列号
+ */
private final int column;
- /** 错误信息描述 */
+ /**
+ * 错误信息描述
+ */
private final String message;
/**
@@ -27,9 +35,9 @@ public class ParseError {
* @param message 错误信息描述
*/
public ParseError(String file, int line, int column, String message) {
- this.file = file;
- this.line = line;
- this.column = column;
+ this.file = file;
+ this.line = line;
+ this.column = column;
this.message = message;
}
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/context/ParseException.java b/src/main/java/org/jcnc/snow/compiler/parser/context/ParseException.java
index 97ceb330..7c7b09e5 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/context/ParseException.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/context/ParseException.java
@@ -14,25 +14,31 @@ package org.jcnc.snow.compiler.parser.context;
public sealed class ParseException extends RuntimeException
permits MissingToken, UnexpectedToken, UnsupportedFeature {
- /** 出错行号(从 1 开始) */
+ /**
+ * 出错行号(从 1 开始)
+ */
private final int line;
- /** 出错列号(从 1 开始) */
+ /**
+ * 出错列号(从 1 开始)
+ */
private final int column;
- /** 错误原因描述 */
+ /**
+ * 错误原因描述
+ */
private final String reason;
/**
* 构造语法分析异常。
*
- * @param reason 错误原因描述
- * @param line 出错行号(从 1 开始)
- * @param column 出错列号(从 1 开始)
+ * @param reason 错误原因描述
+ * @param line 出错行号(从 1 开始)
+ * @param column 出错列号(从 1 开始)
*/
public ParseException(String reason, int line, int column) {
// 禁用 cause / suppression / stackTrace,确保 CLI 输出简洁
super(reason, null, false, false);
this.reason = reason;
- this.line = line;
+ this.line = line;
this.column = column;
}
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/ArrayLiteralParselet.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/ArrayLiteralParselet.java
index 6a9a483b..e46d2e5f 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/expression/ArrayLiteralParselet.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/ArrayLiteralParselet.java
@@ -25,6 +25,17 @@ import java.util.List;
*/
public class ArrayLiteralParselet implements PrefixParselet {
+ /**
+ * 跳过词法流中连续的换行符,允许数组元素跨多行书写。
+ *
+ * @param ts 词法流
+ */
+ private static void skipNewlines(TokenStream ts) {
+ while (ts.peek().getType() == TokenType.NEWLINE) {
+ ts.next();
+ }
+ }
+
/**
* 解析数组字面量表达式。
*
@@ -36,7 +47,7 @@ public class ArrayLiteralParselet implements PrefixParselet {
public ExpressionNode parse(ParserContext ctx, Token token) {
// token 为已消费的 LBRACKET,使用其位置生成 NodeContext
int line = token.getLine();
- int col = token.getCol();
+ int col = token.getCol();
String file = ctx.getSourceName();
TokenStream ts = ctx.getTokens();
@@ -66,15 +77,4 @@ public class ArrayLiteralParselet implements PrefixParselet {
ts.expectType(TokenType.RBRACKET);
return new ArrayLiteralNode(elements, new NodeContext(line, col, file));
}
-
- /**
- * 跳过词法流中连续的换行符,允许数组元素跨多行书写。
- *
- * @param ts 词法流
- */
- private static void skipNewlines(TokenStream ts) {
- while (ts.peek().getType() == TokenType.NEWLINE) {
- ts.next();
- }
- }
}
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/PrattExpressionParser.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/PrattExpressionParser.java
index 3fa483c1..62dd5c1f 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/expression/PrattExpressionParser.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/PrattExpressionParser.java
@@ -48,19 +48,19 @@ public class PrattExpressionParser implements ExpressionParser {
// ----------------- 前缀解析器注册 -----------------
// 各种字面量/标识符
prefixes.put(TokenType.NUMBER_LITERAL.name(), new NumberLiteralParselet());
- prefixes.put(TokenType.IDENTIFIER.name(), new IdentifierParselet());
+ prefixes.put(TokenType.IDENTIFIER.name(), new IdentifierParselet());
prefixes.put(TokenType.STRING_LITERAL.name(), new StringLiteralParselet());
- prefixes.put(TokenType.BOOL_LITERAL.name(), new BoolLiteralParselet());
+ prefixes.put(TokenType.BOOL_LITERAL.name(), new BoolLiteralParselet());
// 分组与数组字面量(两种索引方式)
- prefixes.put(TokenType.LPAREN.name(), new GroupingParselet());
+ prefixes.put(TokenType.LPAREN.name(), new GroupingParselet());
prefixes.put(TokenType.LBRACKET.name(), new ArrayLiteralParselet());
prefixes.put("(", new GroupingParselet());
prefixes.put("[", new ArrayLiteralParselet());
// 一元前缀运算符(如负号、逻辑非),同样用两种方式注册
prefixes.put(TokenType.MINUS.name(), new UnaryOperatorParselet());
- prefixes.put(TokenType.NOT.name(), new UnaryOperatorParselet());
+ prefixes.put(TokenType.NOT.name(), new UnaryOperatorParselet());
prefixes.put("-", new UnaryOperatorParselet());
prefixes.put("!", new UnaryOperatorParselet());
@@ -69,14 +69,14 @@ public class PrattExpressionParser implements ExpressionParser {
// ----------------- 中缀解析器注册 -----------------
// 常见二元算数运算符
- infixes.put("+", new BinaryOperatorParselet(Precedence.SUM, true));
- infixes.put("-", new BinaryOperatorParselet(Precedence.SUM, true));
- infixes.put("*", new BinaryOperatorParselet(Precedence.PRODUCT, true));
- infixes.put("/", new BinaryOperatorParselet(Precedence.PRODUCT, true));
- infixes.put("%", new BinaryOperatorParselet(Precedence.PRODUCT, true));
+ infixes.put("+", new BinaryOperatorParselet(Precedence.SUM, true));
+ infixes.put("-", new BinaryOperatorParselet(Precedence.SUM, true));
+ infixes.put("*", new BinaryOperatorParselet(Precedence.PRODUCT, true));
+ infixes.put("/", new BinaryOperatorParselet(Precedence.PRODUCT, true));
+ infixes.put("%", new BinaryOperatorParselet(Precedence.PRODUCT, true));
// 比较运算符
- infixes.put(">", new BinaryOperatorParselet(Precedence.COMPARISON, true));
- infixes.put("<", new BinaryOperatorParselet(Precedence.COMPARISON, true));
+ infixes.put(">", new BinaryOperatorParselet(Precedence.COMPARISON, true));
+ infixes.put("<", new BinaryOperatorParselet(Precedence.COMPARISON, true));
infixes.put(">=", new BinaryOperatorParselet(Precedence.COMPARISON, true));
infixes.put("<=", new BinaryOperatorParselet(Precedence.COMPARISON, true));
// 相等性判断
@@ -84,7 +84,7 @@ public class PrattExpressionParser implements ExpressionParser {
infixes.put("!=", new BinaryOperatorParselet(Precedence.EQUALITY, true));
// 逻辑运算
infixes.put("&&", new BinaryOperatorParselet(Precedence.AND, true));
- infixes.put("||", new BinaryOperatorParselet(Precedence.OR, true));
+ infixes.put("||", new BinaryOperatorParselet(Precedence.OR, true));
// 函数调用、数组下标、成员访问
infixes.put("(", new CallParselet());
infixes.put("[", new IndexParselet());
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/Precedence.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/Precedence.java
index e47a5aa6..0d818842 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/expression/Precedence.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/Precedence.java
@@ -9,30 +9,48 @@ package org.jcnc.snow.compiler.parser.expression;
*/
public enum Precedence {
- /** 最低优先级,通常用于整个表达式解析的起始入口。 */
+ /**
+ * 最低优先级,通常用于整个表达式解析的起始入口。
+ */
LOWEST,
- /** 逻辑或(||) */
+ /**
+ * 逻辑或(||)
+ */
OR,
- /** 逻辑与(&&) */
+ /**
+ * 逻辑与(&&)
+ */
AND,
- /** 相等/不等(==, !=) */
+ /**
+ * 相等/不等(==, !=)
+ */
EQUALITY,
- /** 大小比较(<, >, <=, >=) */
+ /**
+ * 大小比较(<, >, <=, >=)
+ */
COMPARISON,
- /** 加法和减法(+、-) */
+ /**
+ * 加法和减法(+、-)
+ */
SUM,
- /** 乘法、除法、取模(*、/、%) */
+ /**
+ * 乘法、除法、取模(*、/、%)
+ */
PRODUCT,
- /** 一元前缀(-x !x) */
+ /**
+ * 一元前缀(-x !x)
+ */
UNARY,
- /** 函数调用、成员访问等最强绑定(foo()、obj.prop) */
+ /**
+ * 函数调用、成员访问等最强绑定(foo()、obj.prop)
+ */
CALL
}
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/StringLiteralParselet.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/StringLiteralParselet.java
index b4d417c1..77e7a340 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/expression/StringLiteralParselet.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/StringLiteralParselet.java
@@ -2,8 +2,8 @@ package org.jcnc.snow.compiler.parser.expression;
import org.jcnc.snow.common.StringEscape;
import org.jcnc.snow.compiler.lexer.token.Token;
-import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
import org.jcnc.snow.compiler.parser.ast.StringLiteralNode;
+import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
import org.jcnc.snow.compiler.parser.ast.base.NodeContext;
import org.jcnc.snow.compiler.parser.context.ParserContext;
import org.jcnc.snow.compiler.parser.expression.base.PrefixParselet;
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/UnaryOperatorParselet.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/UnaryOperatorParselet.java
index 00382b34..954790e0 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/expression/UnaryOperatorParselet.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/UnaryOperatorParselet.java
@@ -10,12 +10,12 @@ import org.jcnc.snow.compiler.parser.expression.base.PrefixParselet;
/**
* {@code UnaryOperatorParselet} —— 前缀一元运算符的 Pratt 解析器。
*
- * 当前 parselet 负责解析两种前缀运算:
+ *
当前 parselet 负责解析两种前缀运算:
*
* - 取负: {@code -x}
* - 逻辑非: {@code !x}
*
- *
+ *
* 解析过程:
*
*
@@ -25,7 +25,7 @@ import org.jcnc.snow.compiler.parser.expression.base.PrefixParselet;
* - 最终生成 {@link UnaryExpressionNode} AST 节点,记录运算符与操作数。
*
*
- * 此类仅负责语法结构的构建:
+ *
此类仅负责语法结构的构建:
*
* - 类型正确性在 {@code UnaryExpressionAnalyzer} 中校验;
* - IR 生成在 {@code ExpressionBuilder.buildUnary} 中完成。
@@ -38,7 +38,7 @@ public class UnaryOperatorParselet implements PrefixParselet {
*
* @param ctx 当前解析上下文
* @param token 已被消费的运算符 Token(字面值应为 {@code "-" 或 "!"})
- * @return 构建出的 {@link UnaryExpressionNode}
+ * @return 构建出的 {@link UnaryExpressionNode}
*/
@Override
public ExpressionNode parse(ParserContext ctx, Token token) {
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/base/ExpressionParser.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/base/ExpressionParser.java
index fd388fd6..6ce6614d 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/expression/base/ExpressionParser.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/base/ExpressionParser.java
@@ -10,7 +10,7 @@ import org.jcnc.snow.compiler.parser.context.ParserContext;
* 构建一个有效的 {@link ExpressionNode} 抽象语法树结构。
*
*
- * 不同的实现可以采用不同的解析技术:
+ * 不同的实现可以采用不同的解析技术:
*
* - 递归下降(Recursive Descent)
* - Pratt Parser(前缀/中缀优先级驱动)
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/base/InfixParselet.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/base/InfixParselet.java
index 7ced99b9..c9365900 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/expression/base/InfixParselet.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/base/InfixParselet.java
@@ -11,7 +11,7 @@ import org.jcnc.snow.compiler.parser.expression.Precedence;
* 是 Pratt 解析器架构中处理中缀操作的关键组件。
*
*
- * 每个中缀解析器负责:
+ * 每个中缀解析器负责:
*
* - 根据左侧已解析的表达式,结合当前运算符继续解析右侧部分
* - 提供运算符优先级,用于判断是否继续嵌套解析
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/base/PrefixParselet.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/base/PrefixParselet.java
index 0864edae..73563092 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/expression/base/PrefixParselet.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/base/PrefixParselet.java
@@ -1,8 +1,8 @@
package org.jcnc.snow.compiler.parser.expression.base;
+import org.jcnc.snow.compiler.lexer.token.Token;
import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
import org.jcnc.snow.compiler.parser.context.ParserContext;
-import org.jcnc.snow.compiler.lexer.token.Token;
/**
* {@code PrefixParselet} 是用于解析前缀表达式的通用接口。
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/factory/StatementParserFactory.java b/src/main/java/org/jcnc/snow/compiler/parser/factory/StatementParserFactory.java
index 640db1bb..f8f1396d 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/factory/StatementParserFactory.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/factory/StatementParserFactory.java
@@ -2,8 +2,8 @@ package org.jcnc.snow.compiler.parser.factory;
import org.jcnc.snow.compiler.parser.statement.*;
-import java.util.Map;
import java.util.HashMap;
+import java.util.Map;
/**
* {@code StatementParserFactory} 是一个语句解析器工厂类,
@@ -18,20 +18,22 @@ import java.util.HashMap;
*/
public class StatementParserFactory {
- /** 注册表: 语句关键字 -> 对应语句解析器 */
+ /**
+ * 注册表: 语句关键字 -> 对应语句解析器
+ */
private static final Map registry = new HashMap<>();
static {
// 注册各类语句解析器
registry.put("declare", new DeclarationStatementParser());
- registry.put("if", new IfStatementParser());
- registry.put("loop", new LoopStatementParser());
- registry.put("return", new ReturnStatementParser());
- registry.put("break", new BreakStatementParser());
- registry.put("continue",new ContinueStatementParser());
+ registry.put("if", new IfStatementParser());
+ registry.put("loop", new LoopStatementParser());
+ registry.put("return", new ReturnStatementParser());
+ registry.put("break", new BreakStatementParser());
+ registry.put("continue", new ContinueStatementParser());
// 默认处理器: 表达式语句
- registry.put("", new ExpressionStatementParser());
+ registry.put("", new ExpressionStatementParser());
}
/**
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/factory/TopLevelParserFactory.java b/src/main/java/org/jcnc/snow/compiler/parser/factory/TopLevelParserFactory.java
index eb838bef..7b189e7b 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/factory/TopLevelParserFactory.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/factory/TopLevelParserFactory.java
@@ -1,12 +1,12 @@
package org.jcnc.snow.compiler.parser.factory;
import org.jcnc.snow.compiler.parser.base.TopLevelParser;
-import org.jcnc.snow.compiler.parser.module.ModuleParser;
import org.jcnc.snow.compiler.parser.function.FunctionParser;
+import org.jcnc.snow.compiler.parser.module.ModuleParser;
import org.jcnc.snow.compiler.parser.top.ScriptTopLevelParser;
-import java.util.Map;
import java.util.HashMap;
+import java.util.Map;
/**
* {@code TopLevelParserFactory} 用于根据源码中顶层关键字取得对应的解析器。
@@ -15,15 +15,19 @@ import java.util.HashMap;
*/
public class TopLevelParserFactory {
- /** 关键字 → 解析器注册表 */
+ /**
+ * 关键字 → 解析器注册表
+ */
private static final Map registry = new HashMap<>();
- /** 缺省解析器: 脚本模式(单条语句可执行) */
+ /**
+ * 缺省解析器: 脚本模式(单条语句可执行)
+ */
private static final TopLevelParser DEFAULT = new ScriptTopLevelParser();
static {
// 在此注册所有受支持的顶层结构关键字
- registry.put("module", new ModuleParser());
+ registry.put("module", new ModuleParser());
registry.put("function", new FunctionParser());
// 若未来新增顶层结构,可继续在此处注册
}
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/module/ImportParser.java b/src/main/java/org/jcnc/snow/compiler/parser/module/ImportParser.java
index d46abd32..722cce5e 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/module/ImportParser.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/module/ImportParser.java
@@ -1,9 +1,9 @@
package org.jcnc.snow.compiler.parser.module;
import org.jcnc.snow.compiler.lexer.token.TokenType;
+import org.jcnc.snow.compiler.parser.ast.ImportNode;
import org.jcnc.snow.compiler.parser.ast.base.NodeContext;
import org.jcnc.snow.compiler.parser.context.ParserContext;
-import org.jcnc.snow.compiler.parser.ast.ImportNode;
import java.util.ArrayList;
import java.util.List;
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/statement/DeclarationStatementParser.java b/src/main/java/org/jcnc/snow/compiler/parser/statement/DeclarationStatementParser.java
index 4a9d3df3..354000d9 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/statement/DeclarationStatementParser.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/statement/DeclarationStatementParser.java
@@ -30,7 +30,7 @@ public class DeclarationStatementParser implements StatementParser {
var tokens = ctx.getTokens(); // 获取词法单元流
// 记录声明语句在源码中的位置信息(行、列、文件名)
- int line = tokens.peek().getLine();
+ int line = tokens.peek().getLine();
int column = tokens.peek().getCol();
String file = ctx.getSourceName();
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/statement/ExpressionStatementParser.java b/src/main/java/org/jcnc/snow/compiler/parser/statement/ExpressionStatementParser.java
index 766f53d4..774c10bd 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/statement/ExpressionStatementParser.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/statement/ExpressionStatementParser.java
@@ -20,7 +20,7 @@ import org.jcnc.snow.compiler.parser.expression.PrattExpressionParser;
* doSomething() // 一般表达式语句
* this.name = n // 将 this.name 赋值语法糖为对 name 的赋值
* }
- *
+ *
* - 以标识符开头且后接 '=' 时,解析为 {@link AssignmentNode}。
* - 否则先解析为一般表达式;若后续遇到 '=',则回退为“
- * 本解析器支持以下结构的条件语法:
+ * 本解析器支持以下结构的条件语法:
*
- * 该语法结构参考了传统的 for-loop,并将其拆解为命名的语义区块:
+ * 该语法结构参考了传统的 for-loop,并将其拆解为命名的语义区块:
*
+ * 各区块说明:
*
- * 本方法会按顺序检查各个命名区块(可乱序书写),并分别绑定其对应语义解析器:
+ * 本方法会按顺序检查各个命名区块(可乱序书写),并分别绑定其对应语义解析器:
*
- * 支持以下两种 return 语句形式:
+ * 支持以下两种 return 语句形式:
*
- * 解析逻辑如下:
+ * 解析逻辑如下:
* {@code
* if
- * 其中:
+ * 其中:
*
*
{@code
* loop:
* init:
@@ -35,8 +35,8 @@ import java.util.Map;
* end body
* end loop
* }
- *
- * 各区块说明:
+ *
*
*
{@code
* return // 无返回值
* return expression // 带返回值
@@ -23,7 +23,7 @@ public class ReturnStatementParser implements StatementParser {
/**
* 解析一条 return 语句,并返回对应的 {@link ReturnNode} 抽象语法树节点。
*
*
- * 典型用途包括: + * 典型用途包括: *
{@code
* {"a":1,"b":[2,3]} →
* {
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/utils/ParserUtils.java b/src/main/java/org/jcnc/snow/compiler/parser/utils/ParserUtils.java
index cce7a9a7..5c1ec5be 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/utils/ParserUtils.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/utils/ParserUtils.java
@@ -9,7 +9,7 @@ import org.jcnc.snow.compiler.parser.context.TokenStream;
* 提供一系列静态方法用于标准语法结构(如结构头、结构尾)的匹配校验,以及常用的容错处理操作。
* 这些方法可在函数定义、模块定义、循环、条件语句等语法块中复用,有效减少冗余代码,提高解析器稳定性。
*
- * 主要功能包括:
+ *
主要功能包括:
*
- * 支持特性:
+ * 支持特性:
* 1. 字符串拼接「+」
* 2. 数值运算与自动宽化
* 3. 比较 / 关系运算
@@ -34,7 +34,7 @@ public class BinaryExpressionAnalyzer implements ExpressionAnalyzer 目前实现两种一元运算:
+ * 目前实现两种一元运算:
* 分析流程:
+ * 分析流程:
*
* 任何不满足条件的情况都会向 {@link Context#getErrors()} 记录 {@link SemanticError}。
*/
public class AssignmentAnalyzer implements StatementAnalyzer
- * 它负责处理类似 {@code int x = 10;} 的声明语句,具体分析内容包括:
+ * 它负责处理类似 {@code int x = 10;} 的声明语句,具体分析内容包括:
*
- * 主要职责如下:
+ * 主要职责如下:
*
- * 它负责检查函数中的 return 语句是否与函数定义的返回类型匹配。分析流程包括:
+ * 它负责检查函数中的 return 语句是否与函数定义的返回类型匹配。分析流程包括:
*
- * 语义分析流程分为三个阶段:
+ * 语义分析流程分为三个阶段:
*
- * 内部使用组件:
+ * 内部使用组件:
*
- * 功能职责:
+ * 功能职责:
*
- * 推荐使用方式:
+ * 推荐使用方式:
*
* 符号是语义分析中的基础单元,通常用于表示变量、函数、参数等具名元素。
- * 每个符号具备以下三个核心属性:
+ * 每个符号具备以下三个核心属性:
* 核心特性包括:
+ * 核心特性包括:
* 查找策略:
+ * 查找策略:
* 支持的类型包括:
+ * 支持的类型包括:
* 每个枚举实例实现了 {@link Type} 接口,提供以下语义特性:
+ * 每个枚举实例实现了 {@link Type} 接口,提供以下语义特性:
*
- * 兼容判断规则:
+ * 兼容判断规则:
*
- * 数值类型包括:
+ * 数值类型包括:
* {@link #BYTE}、{@link #SHORT}、{@link #INT}、{@link #LONG}、
* {@link #FLOAT}、{@link #DOUBLE}。
*
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/type/FunctionType.java b/src/main/java/org/jcnc/snow/compiler/semantic/type/FunctionType.java
index e3c38800..05eb3931 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/type/FunctionType.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/type/FunctionType.java
@@ -8,12 +8,12 @@ import java.util.Objects;
*
* 适用于函数声明、函数调用、类型检查等语义分析场景。
*
- * 例如,一个函数接受两个 {@code int} 参数并返回 {@code string},其函数类型为:
+ * 例如,一个函数接受两个 {@code int} 参数并返回 {@code string},其函数类型为:
* 该类使用 Java 16+ {@code record} 语法定义,自动提供:
+ * 该类使用 Java 16+ {@code record} 语法定义,自动提供:
*
- * 兼容条件:
+ * 兼容条件:
*
- * 格式为:
+ * 格式为:
*
- * 相等条件为:
+ * 相等条件为:
*
- * 默认实现返回 false,BuiltinType 会覆盖此方法。
- *
- * @return 如果是数值类型则返回 true,否则返回 false
- */
- default boolean isNumeric() {
- return false;
- }
-
/**
* 对两个数值类型执行宽化转换,返回“更宽”的那个类型。
*
@@ -47,6 +28,30 @@ public interface Type {
int ia = order.indexOf(a), ib = order.indexOf(b);
return order.get(Math.max(ia, ib));
}
- /** 类型名字符串(如 int、double[]) */
- default String name() { return toString(); }
+
+ /**
+ * 判断当前类型是否与另一个类型兼容。
+ *
+ * @param other 要检查兼容性的另一个类型
+ * @return 如果兼容则返回 true,否则返回 false
+ */
+ boolean isCompatible(Type other);
+
+ /**
+ * 判断当前类型是否为数值类型(byte/short/int/long/float/double)。
+ *
+ * 默认实现返回 false,BuiltinType 会覆盖此方法。
+ *
+ * @return 如果是数值类型则返回 true,否则返回 false
+ */
+ default boolean isNumeric() {
+ return false;
+ }
+
+ /**
+ * 类型名字符串(如 int、double[])
+ */
+ default String name() {
+ return toString();
+ }
}
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/utils/SemanticAnalysisReporter.java b/src/main/java/org/jcnc/snow/compiler/semantic/utils/SemanticAnalysisReporter.java
index eb332b81..477fc7df 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/utils/SemanticAnalysisReporter.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/utils/SemanticAnalysisReporter.java
@@ -9,7 +9,7 @@ import static org.jcnc.snow.common.SnowConfig.print;
/**
* {@code SemanticAnalysisReporter} 用于在语义分析结束后汇总并打印所有收集到的
* {@link SemanticError}。为了同时满足“完整错误收集”与“按需快速失败”两种使用场景,
- * 现在提供两个公共 API:
+ * 现在提供两个公共 API:
*
*
*
*
- *
*
*
- *
+ * int → double)。
*
*
*
*
*
*
*
*
* SemanticAnalyzerRunner.runSemanticAnalysis(ast, true);
*
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/doc/README.md b/src/main/java/org/jcnc/snow/compiler/semantic/doc/README.md
index baabb819..5dcc5a77 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/doc/README.md
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/doc/README.md
@@ -5,9 +5,11 @@
## 项目简介
**语义分析(Semantic Analysis)** 是 Snow 编译器在语法之后、IR 之前的关键阶段。
-该模块在遍历 AST 的同时,完成**类型推断与检查**、**符号与作用域解析**、**模块/结构体/函数签名登记**、以及**错误汇总与报告**,为后续 IR 生成与优化提供可靠、结构化的类型与符号信息。
+该模块在遍历 AST 的同时,完成**类型推断与检查**、**符号与作用域解析**、**模块/结构体/函数签名登记**、以及**错误汇总与报告**
+,为后续 IR 生成与优化提供可靠、结构化的类型与符号信息。
-语义层采用“**注册表 + 访问器接口 + 分析器实现**”的可插拔设计:以 `AnalyzerRegistry` 为分发中心、`ExpressionAnalyzer`/`StatementAnalyzer` 为契约、配套 **模块/函数签名三阶段流程** 与 **类型系统**,形成清晰、易扩展、便于调试的语义分析框架。
+语义层采用“**注册表 + 访问器接口 + 分析器实现**”的可插拔设计:以 `AnalyzerRegistry` 为分发中心、`ExpressionAnalyzer`/
+`StatementAnalyzer` 为契约、配套 **模块/函数签名三阶段流程** 与 **类型系统**,形成清晰、易扩展、便于调试的语义分析框架。
## 核心功能
@@ -49,7 +51,8 @@
* **类型系统与类型提升**
* 核心接口:`Type`(`isCompatible`/`isNumeric`/`name`/`widen`)
- * 具体类型:`BuiltinType`(byte/short/int/long/float/double/string/boolean/void)、`ArrayType`、`FunctionType`、`StructType`
+ * 具体类型:`BuiltinType`(byte/short/int/long/float/double/string/boolean/void)、`ArrayType`、`FunctionType`、
+ `StructType`
* 内建注册:`BuiltinTypeRegistry`(注册所有内置基本类型;示例内置模块 `os` 及函数 `syscall(string,int):void`)
* 类型解析:`Context#parseType` 支持 **多维数组**(如 `int[][]`)、**结构体类型**(`模块.结构体`)
* 数值宽化:在声明/赋值/调用/构造场景支持 **数值类型自动宽化**(`Type.widen`)
@@ -144,7 +147,8 @@ semantic/
* **阶段化**:将“全局签名收集”和“函数体检查”解耦,避免前向引用/跨模块依赖导致的顺序问题。
* **作用域安全**:`SymbolTable` 通过父指针实现块级/函数级/模块级多层作用域;`If`/`Loop` 分支各自使用独立作用域。
* **解析顺序**:成员与调用遵循“先模块、后结构体、再本地符号”的解析策略,结合 `imports` 做跨模块访问控制。
-* **类型宽化**:对数值类型在声明/赋值/调用/构造时按 `Type.widen` 进行安全宽化;字符串调用形参支持从数值到 string 的隐式接收(见 `CallExpressionAnalyzer`)。
+* **类型宽化**:对数值类型在声明/赋值/调用/构造时按 `Type.widen` 进行安全宽化;字符串调用形参支持从数值到 string 的隐式接收(见
+ `CallExpressionAnalyzer`)。
## 扩展
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/error/SemanticError.java b/src/main/java/org/jcnc/snow/compiler/semantic/error/SemanticError.java
index c43e6c94..7c185da4 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/error/SemanticError.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/error/SemanticError.java
@@ -26,7 +26,7 @@ import org.jcnc.snow.compiler.parser.ast.base.Node;
public record SemanticError(Node node, String message) {
/**
- * 返回该语义错误的字符串描述,格式如下:
+ * 返回该语义错误的字符串描述,格式如下:
*
* [文件绝对路径: ]行 X, 列 Y: [错误信息]
*
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/symbol/Symbol.java b/src/main/java/org/jcnc/snow/compiler/semantic/symbol/Symbol.java
index 45fa4828..fa79f2db 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/symbol/Symbol.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/symbol/Symbol.java
@@ -6,7 +6,7 @@ import org.jcnc.snow.compiler.semantic.type.Type;
* {@code Symbol} 表示符号表中的一条符号记录,描述语言中命名实体的语义信息。
*
*
*
*
*
*
- *
*
*
* (int, int) -> string
*
*
- *
*
*
* (param1, param2, ...) -> returnType
*
@@ -78,7 +78,7 @@ public record FunctionType(List
*
*
- * 示例用法:
+ * 示例用法:
* Dependency dep = Dependency.fromString(
* "core", "com.example:core:@{version}",
* Map.of("version", "1.2.3")
@@ -30,7 +30,9 @@ public record Dependency(
String version
) {
- /** 匹配 group:artifact:version 格式的正则表达式。 */
+ /**
+ * 匹配 group:artifact:version 格式的正则表达式。
+ */
private static final Pattern GAV = Pattern.compile("([^:]+):([^:]+):(.+)");
/**
diff --git a/src/main/java/org/jcnc/snow/pkg/model/Project.java b/src/main/java/org/jcnc/snow/pkg/model/Project.java
index a46aa19b..13254950 100644
--- a/src/main/java/org/jcnc/snow/pkg/model/Project.java
+++ b/src/main/java/org/jcnc/snow/pkg/model/Project.java
@@ -19,28 +19,50 @@ import java.util.Map;
*/
public final class Project {
- /** 组织/分组名(如 com.example) */
+ /**
+ * 组织/分组名(如 com.example)
+ */
private final String group;
- /** 构件/模块名(如 app-core) */
+ /**
+ * 构件/模块名(如 app-core)
+ */
private final String artifact;
- /** 项目展示名称 */
+ /**
+ * 项目展示名称
+ */
private final String name;
- /** 版本号(如 1.0.0) */
+ /**
+ * 版本号(如 1.0.0)
+ */
private final String version;
- /** 项目描述 */
+ /**
+ * 项目描述
+ */
private final String description;
- /** 许可证标识 */
+ /**
+ * 许可证标识
+ */
private final String license;
- /** 项目主页 URL */
+ /**
+ * 项目主页 URL
+ */
private final String homepage;
- /** 额外属性(不影响主字段,可用于模板/占位符) */
+ /**
+ * 额外属性(不影响主字段,可用于模板/占位符)
+ */
private final Map properties;
- /** 仓库列表(仓库 ID -> 仓库对象) */
+ /**
+ * 仓库列表(仓库 ID -> 仓库对象)
+ */
private final Map repositories;
- /** 依赖列表 */
+ /**
+ * 依赖列表
+ */
private final List dependencies;
- /** 构建配置 */
+ /**
+ * 构建配置
+ */
private final BuildConfiguration build;
/**
@@ -73,7 +95,7 @@ public final class Project {
}
/**
- * 通过扁平 Map 创建 Project 实例。key 格式约定如下:
+ * 通过扁平 Map 创建 Project 实例。key 格式约定如下:
*
* - project.* —— 项目元数据
* - properties.* —— 额外属性
@@ -133,57 +155,79 @@ public final class Project {
return new Project(group, artifact, name, version, description, license, homepage, props, repos, deps, buildCfg);
}
- /** @return 组织/分组名 */
+ /**
+ * @return 组织/分组名
+ */
public String getGroup() {
return group;
}
- /** @return 构件/模块名 */
+ /**
+ * @return 构件/模块名
+ */
public String getArtifact() {
return artifact;
}
- /** @return 项目名称 */
+ /**
+ * @return 项目名称
+ */
public String getName() {
return name;
}
- /** @return 版本号 */
+ /**
+ * @return 版本号
+ */
public String getVersion() {
return version;
}
- /** @return 项目描述 */
+ /**
+ * @return 项目描述
+ */
public String getDescription() {
return description;
}
- /** @return 许可证标识 */
+ /**
+ * @return 许可证标识
+ */
public String getLicense() {
return license;
}
- /** @return 项目主页 URL */
+ /**
+ * @return 项目主页 URL
+ */
public String getHomepage() {
return homepage;
}
- /** @return 额外属性映射 */
+ /**
+ * @return 额外属性映射
+ */
public Map getProperties() {
return properties;
}
- /** @return 仓库映射 */
+ /**
+ * @return 仓库映射
+ */
public Map getRepositories() {
return repositories;
}
- /** @return 依赖列表 */
+ /**
+ * @return 依赖列表
+ */
public List getDependencies() {
return dependencies;
}
- /** @return 构建配置 */
+ /**
+ * @return 构建配置
+ */
public BuildConfiguration getBuild() {
return build;
}
diff --git a/src/main/java/org/jcnc/snow/pkg/resolver/DependencyResolver.java b/src/main/java/org/jcnc/snow/pkg/resolver/DependencyResolver.java
index 7c9dcf83..d0e0f47d 100644
--- a/src/main/java/org/jcnc/snow/pkg/resolver/DependencyResolver.java
+++ b/src/main/java/org/jcnc/snow/pkg/resolver/DependencyResolver.java
@@ -22,7 +22,9 @@ import java.util.Optional;
*/
public final class DependencyResolver {
- /** 本地缓存目录 */
+ /**
+ * 本地缓存目录
+ */
private final Path localCache;
/**
diff --git a/src/main/java/org/jcnc/snow/pkg/tasks/CleanTask.java b/src/main/java/org/jcnc/snow/pkg/tasks/CleanTask.java
index c21b1ade..5bc22a4e 100644
--- a/src/main/java/org/jcnc/snow/pkg/tasks/CleanTask.java
+++ b/src/main/java/org/jcnc/snow/pkg/tasks/CleanTask.java
@@ -46,7 +46,7 @@ public final class CleanTask implements Task {
* 内部使用 try-with-resources 保证文件流自动关闭,避免资源泄漏。
*
*
- * @param dir 需要删除的目录路径
+ * @param dir 需要删除的目录路径
* @param containSelf 是否删除指定目录本身
* @throws IOException 删除目录或文件过程中发生 IO 错误时抛出
*/
diff --git a/src/main/java/org/jcnc/snow/pkg/tasks/PackageTask.java b/src/main/java/org/jcnc/snow/pkg/tasks/PackageTask.java
index a04dcf0e..bfe50ecc 100644
--- a/src/main/java/org/jcnc/snow/pkg/tasks/PackageTask.java
+++ b/src/main/java/org/jcnc/snow/pkg/tasks/PackageTask.java
@@ -20,7 +20,9 @@ import java.util.zip.ZipOutputStream;
*/
public final class PackageTask implements Task {
- /** 目标项目元数据 */
+ /**
+ * 目标项目元数据
+ */
private final Project project;
/**
diff --git a/src/main/java/org/jcnc/snow/pkg/tasks/PublishTask.java b/src/main/java/org/jcnc/snow/pkg/tasks/PublishTask.java
index 310b8fa4..58c857a9 100644
--- a/src/main/java/org/jcnc/snow/pkg/tasks/PublishTask.java
+++ b/src/main/java/org/jcnc/snow/pkg/tasks/PublishTask.java
@@ -11,7 +11,9 @@ import org.jcnc.snow.pkg.model.Project;
*/
public final class PublishTask implements Task {
- /** 目标项目元数据 */
+ /**
+ * 目标项目元数据
+ */
private final Project project;
/**
diff --git a/src/main/java/org/jcnc/snow/vm/VMInitializer.java b/src/main/java/org/jcnc/snow/vm/VMInitializer.java
index ca11e3bf..835db8d9 100644
--- a/src/main/java/org/jcnc/snow/vm/VMInitializer.java
+++ b/src/main/java/org/jcnc/snow/vm/VMInitializer.java
@@ -1,9 +1,9 @@
package org.jcnc.snow.vm;
import org.jcnc.snow.common.Mode;
-import org.jcnc.snow.vm.execution.CommandLoader;
import org.jcnc.snow.vm.engine.VMCommandExecutor;
import org.jcnc.snow.vm.engine.VirtualMachineEngine;
+import org.jcnc.snow.vm.execution.CommandLoader;
import org.jcnc.snow.vm.io.FilePathResolver;
import org.jcnc.snow.vm.utils.VMStateLogger;
diff --git a/src/main/java/org/jcnc/snow/vm/commands/flow/control/CallCommand.java b/src/main/java/org/jcnc/snow/vm/commands/flow/control/CallCommand.java
index c46571cb..c5839629 100644
--- a/src/main/java/org/jcnc/snow/vm/commands/flow/control/CallCommand.java
+++ b/src/main/java/org/jcnc/snow/vm/commands/flow/control/CallCommand.java
@@ -1,6 +1,5 @@
package org.jcnc.snow.vm.commands.flow.control;
-import org.jcnc.snow.common.Mode;
import org.jcnc.snow.vm.interfaces.Command;
import org.jcnc.snow.vm.module.*;
@@ -61,7 +60,7 @@ public class CallCommand implements Command {
/* ----------- Parse target address / method signature ----------- */
final String targetToken = parts[1]; // Can be a numeric address or "@Class::method"
- final int nArgs = Integer.parseInt(parts[2]);
+ final int nArgs = Integer.parseInt(parts[2]);
/* ----------- Build callee's local variable store ----------- */
LocalVariableStore calleeLVS = new LocalVariableStore();
diff --git a/src/main/java/org/jcnc/snow/vm/commands/flow/control/JumpCommand.java b/src/main/java/org/jcnc/snow/vm/commands/flow/control/JumpCommand.java
index 7f538908..b570ae41 100644
--- a/src/main/java/org/jcnc/snow/vm/commands/flow/control/JumpCommand.java
+++ b/src/main/java/org/jcnc/snow/vm/commands/flow/control/JumpCommand.java
@@ -1,10 +1,10 @@
package org.jcnc.snow.vm.commands.flow.control;
import org.jcnc.snow.vm.interfaces.Command;
-import org.jcnc.snow.vm.utils.LoggingUtils;
import org.jcnc.snow.vm.module.CallStack;
import org.jcnc.snow.vm.module.LocalVariableStore;
import org.jcnc.snow.vm.module.OperandStack;
+import org.jcnc.snow.vm.utils.LoggingUtils;
/**
* The JumpCommand class implements the {@link Command} interface and represents an unconditional jump instruction in the virtual machine.
diff --git a/src/main/java/org/jcnc/snow/vm/commands/ref/control/RLoadCommand.java b/src/main/java/org/jcnc/snow/vm/commands/ref/control/RLoadCommand.java
index d7e314d7..85693ac4 100644
--- a/src/main/java/org/jcnc/snow/vm/commands/ref/control/RLoadCommand.java
+++ b/src/main/java/org/jcnc/snow/vm/commands/ref/control/RLoadCommand.java
@@ -33,10 +33,10 @@ public final class RLoadCommand implements Command {
* Executes the {@code R_LOAD} instruction, loading a reference from the local variable table and pushing it onto the operand stack.
*
* @param parts The instruction parameters. {@code parts[0]} is the operator ("R_LOAD"), {@code parts[1]} is the slot index.
- * @param pc The current program counter value, indicating the instruction address being executed.
+ * @param pc The current program counter value, indicating the instruction address being executed.
* @param stack The operand stack manager. The loaded reference will be pushed onto this stack.
- * @param lvs The local variable store. (Not used directly, as this command uses the store from the current stack frame.)
- * @param cs The call stack manager. The reference will be loaded from the local variable store of the top stack frame.
+ * @param lvs The local variable store. (Not used directly, as this command uses the store from the current stack frame.)
+ * @param cs The call stack manager. The reference will be loaded from the local variable store of the top stack frame.
* @return The next program counter value ({@code pc + 1}), pointing to the next instruction.
* @throws NumberFormatException if the slot parameter cannot be parsed as an integer.
*/
diff --git a/src/main/java/org/jcnc/snow/vm/commands/ref/control/RPushCommand.java b/src/main/java/org/jcnc/snow/vm/commands/ref/control/RPushCommand.java
index 228f957d..741fc928 100644
--- a/src/main/java/org/jcnc/snow/vm/commands/ref/control/RPushCommand.java
+++ b/src/main/java/org/jcnc/snow/vm/commands/ref/control/RPushCommand.java
@@ -38,107 +38,9 @@ import java.util.List;
*/
public class RPushCommand implements Command {
- /**
- * Executes the {@code R_PUSH} instruction. Parses the given literal parameter and pushes it onto the operand stack.
- *
- * Handles:
- *
- * - Array literals (e.g., {@code [1, 2, "a"]}), parsed recursively as mutable ArrayLists
- * - Quoted string literals (e.g., {@code "abc\n"}), parsed with escape sequence support
- * - Unquoted raw strings, numbers, and atoms
- *
- *
- * @param parts The instruction split into parts (opcode and arguments)
- * @param pc The current program counter
- * @param stack The operand stack to push the value onto
- * @param local The local variable store (unused)
- * @param callStack The call stack (unused)
- * @return The next program counter (pc + 1)
- * @throws IllegalStateException if the R_PUSH parameter is missing or parsing fails
- */
- @Override
- public int execute(String[] parts, int pc, OperandStack stack, LocalVariableStore local, CallStack callStack) {
- if (parts.length < 2)
- throw new IllegalStateException("R_PUSH missing parameter");
-
- // Join all arguments into a complete literal string
- StringBuilder sb = new StringBuilder();
- for (int i = 1; i < parts.length; i++) {
- if (i > 1) sb.append(' ');
- sb.append(parts[i]);
- }
- String literal = sb.toString().trim();
-
- // Handle array literal
- if (literal.startsWith("[") && literal.endsWith("]")) {
- Object parsed = parseValue(new Cursor(literal));
- if (!(parsed instanceof List> list)) {
- stack.push(parsed);
- } else {
- stack.push(deepMutable(list));
- }
- }
- // String literal with quotes and escapes
- else if (literal.length() >= 2 && literal.startsWith("\"") && literal.endsWith("\"")) {
- String decoded = parseQuoted(new Cursor(literal));
- stack.push(decoded);
- }
- // Raw atom or string
- else {
- stack.push(literal);
- }
- return pc + 1;
- }
-
- /**
- * Utility class for string parsing, used by the array and string literal parsers.
- */
- static class Cursor {
- final String s;
- int i;
-
- /**
- * Constructs a cursor over the provided string.
- * @param s the input string to parse
- */
- Cursor(String s) { this.s = s; this.i = 0; }
-
- /**
- * Advances the cursor by one character.
- */
- void skip() { i++; }
-
- /**
- * Returns true if the cursor has reached the end of the string.
- * @return true if end of string
- */
- boolean end() { return i >= s.length(); }
-
- /**
- * Returns the current character at the cursor position.
- * @return the current character
- */
- char ch() { return s.charAt(i); }
- }
-
- /**
- * Parses a value from the current cursor position.
- * Supports arrays, quoted strings, or atoms.
- *
- * @param c the parsing cursor
- * @return the parsed object (List, String, Number, Boolean, or String fallback)
- */
- Object parseValue(Cursor c) {
- skipWs(c);
- if (c.end()) return "";
- char ch = c.ch();
- if (ch == '[') return parseArray(c);
- if (ch == '\"') return parseQuoted(c);
- return parseAtom(c);
- }
-
/**
* Skips whitespace characters at the cursor.
+ *
* @param c the parsing cursor
*/
private static void skipWs(Cursor c) {
@@ -149,33 +51,6 @@ public class RPushCommand implements Command {
}
}
- /**
- * Parses an array literal of the form [elem1, elem2, ...] (may be nested).
- * Recursively parses elements using {@link #parseValue(Cursor)}.
- *
- * @param c the parsing cursor
- * @return a List of parsed elements
- */
- private Object parseArray(Cursor c) {
- c.skip(); // skip '['
- List
- *
+ *
* Root-frame contract:
*
* A root stack frame is pushed once via
@@ -31,10 +31,14 @@ public class VirtualMachineEngine {
/* ---------- Constants ---------- */
- /** Sentinel PC value that signals “terminate program gracefully”. */
+ /**
+ * Sentinel PC value that signals “terminate program gracefully”.
+ */
private static final int PROGRAM_END = Integer.MAX_VALUE;
- /** Sentinel returned by {@link CommandExecutionHandler#handle} to halt immediately. */
+ /**
+ * Sentinel returned by {@link CommandExecutionHandler#handle} to halt immediately.
+ */
private static final int HALT = -1;
/* ---------- Runtime state ---------- */
@@ -52,8 +56,8 @@ public class VirtualMachineEngine {
* Builds a VM engine with fresh runtime structures.
*/
public VirtualMachineEngine() {
- this.operandStack = new OperandStack();
- this.callStack = new CallStack();
+ this.operandStack = new OperandStack();
+ this.callStack = new CallStack();
this.localVariableStore = new LocalVariableStore(); // shared with root frame
this.commandExecutionHandler =
new CommandExecutionHandler(operandStack, localVariableStore, callStack);
@@ -61,7 +65,9 @@ public class VirtualMachineEngine {
}
/* package-private accessor used by debug helpers */
- CallStack getCallStack() { return callStack; }
+ CallStack getCallStack() {
+ return callStack;
+ }
/* ---------- Execution ---------- */
@@ -144,19 +150,23 @@ public class VirtualMachineEngine {
/* The returnAddress of the root frame must be PROGRAM_END so that the main loop can exit correctly when the root function RETs.*/
MethodContext rootCtx = new MethodContext("root", null);
- StackFrame rootFrame = new StackFrame(PROGRAM_END, localVariableStore, rootCtx);
+ StackFrame rootFrame = new StackFrame(PROGRAM_END, localVariableStore, rootCtx);
callStack.pushFrame(rootFrame);
}
/* ---------- Debug helpers ---------- */
- /** Prints operand stack + call-stack snapshot. */
+ /**
+ * Prints operand stack + call-stack snapshot.
+ */
public void printStack() {
operandStack.printOperandStack();
callStack.printCallStack();
}
- /** Prints the local-variable table of the current top frame. */
+ /**
+ * Prints the local-variable table of the current top frame.
+ */
public void printLocalVariables() {
if (callStack.isEmpty()) {
System.out.println("Local variable table is empty");
@@ -167,7 +177,9 @@ public class VirtualMachineEngine {
/* ---------- Utility ---------- */
- /** Parses textual opcode to integer. */
+ /**
+ * Parses textual opcode to integer.
+ */
private int parseOpCode(String opCodeStr) {
try {
return Integer.parseInt(opCodeStr);
diff --git a/src/main/java/org/jcnc/snow/vm/execution/CommandLoader.java b/src/main/java/org/jcnc/snow/vm/execution/CommandLoader.java
index 70d6c9b0..afe4a31e 100644
--- a/src/main/java/org/jcnc/snow/vm/execution/CommandLoader.java
+++ b/src/main/java/org/jcnc/snow/vm/execution/CommandLoader.java
@@ -1,9 +1,8 @@
package org.jcnc.snow.vm.execution;
-
-import org.jcnc.snow.vm.utils.LoggingUtils;
import org.jcnc.snow.vm.io.FileIOUtils;
+import org.jcnc.snow.vm.utils.LoggingUtils;
import java.util.List;
diff --git a/src/main/java/org/jcnc/snow/vm/io/FDTable.java b/src/main/java/org/jcnc/snow/vm/io/FDTable.java
index 0cd40b0e..1293e4d9 100644
--- a/src/main/java/org/jcnc/snow/vm/io/FDTable.java
+++ b/src/main/java/org/jcnc/snow/vm/io/FDTable.java
@@ -3,7 +3,8 @@ package org.jcnc.snow.vm.io;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
-import java.nio.channels.*;
+import java.nio.channels.Channel;
+import java.nio.channels.Channels;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
@@ -19,11 +20,13 @@ import java.util.concurrent.atomic.AtomicInteger;
*/
public final class FDTable {
- private FDTable() {}
-
- /** Next available fd (0‒2 are reserved for standard streams) */
+ /**
+ * Next available fd (0‒2 are reserved for standard streams)
+ */
private static final AtomicInteger NEXT_FD = new AtomicInteger(3);
- /** Main mapping table: fd → Channel */
+ /**
+ * Main mapping table: fd → Channel
+ */
private static final ConcurrentHashMap MAP = new ConcurrentHashMap<>();
static {
@@ -33,8 +36,12 @@ public final class FDTable {
MAP.put(2, Channels.newChannel(new BufferedOutputStream(System.err)));
}
+ private FDTable() {
+ }
+
/**
* Register a new Channel, returning the allocated virtual fd.
+ *
* @param ch Channel to register
* @return allocated fd
*/
@@ -46,6 +53,7 @@ public final class FDTable {
/**
* Retrieve the Channel by fd; returns null if fd does not exist.
+ *
* @param fd file descriptor
* @return Channel or null if not found
*/
@@ -55,6 +63,7 @@ public final class FDTable {
/**
* Close and remove the fd (0‒2 are ignored).
+ *
* @param fd file descriptor to close
* @throws IOException if an I/O error occurs
*/
@@ -66,6 +75,7 @@ public final class FDTable {
/**
* Similar to dup(oldfd) — returns a new fd referring to the same Channel.
+ *
* @param oldfd old file descriptor to duplicate
* @return new fd referring to the same Channel
* @throws IllegalArgumentException if fd does not exist
diff --git a/src/main/java/org/jcnc/snow/vm/module/CallStack.java b/src/main/java/org/jcnc/snow/vm/module/CallStack.java
index cd982d38..473a34bd 100644
--- a/src/main/java/org/jcnc/snow/vm/module/CallStack.java
+++ b/src/main/java/org/jcnc/snow/vm/module/CallStack.java
@@ -11,6 +11,7 @@ import java.util.Deque;
public class CallStack {
private static final int MAX_STACK_DEPTH = 1024; // Stack overflow protection
private final Deque stack = new ArrayDeque<>();
+
/**
* Default constructor for creating an instance of CallStack.
* This constructor is empty as no specific initialization is required.
diff --git a/src/main/java/org/jcnc/snow/vm/module/Instance.java b/src/main/java/org/jcnc/snow/vm/module/Instance.java
index 04c94513..87412e82 100644
--- a/src/main/java/org/jcnc/snow/vm/module/Instance.java
+++ b/src/main/java/org/jcnc/snow/vm/module/Instance.java
@@ -25,10 +25,14 @@ import java.util.Map;
*/
public final class Instance {
- /** The virtual table associated with this instance (immutable). */
+ /**
+ * The virtual table associated with this instance (immutable).
+ */
private final VirtualTable vtable;
- /** A mapping of field names to their runtime values. */
+ /**
+ * A mapping of field names to their runtime values.
+ */
private final Map fields = new HashMap<>();
/**
diff --git a/src/main/java/org/jcnc/snow/vm/module/StackFrame.java b/src/main/java/org/jcnc/snow/vm/module/StackFrame.java
index 39e708c8..4def3341 100644
--- a/src/main/java/org/jcnc/snow/vm/module/StackFrame.java
+++ b/src/main/java/org/jcnc/snow/vm/module/StackFrame.java
@@ -1,7 +1,5 @@
package org.jcnc.snow.vm.module;
-import org.jcnc.snow.vm.utils.LoggingUtils;
-
/**
* The {@code StackFrame} class represents a single frame in the call stack during program execution.
* It holds the execution context for a method invocation, including information such as the return
diff --git a/src/main/java/org/jcnc/snow/vm/module/VirtualTable.java b/src/main/java/org/jcnc/snow/vm/module/VirtualTable.java
index f7e0fe6a..7ecda570 100644
--- a/src/main/java/org/jcnc/snow/vm/module/VirtualTable.java
+++ b/src/main/java/org/jcnc/snow/vm/module/VirtualTable.java
@@ -22,7 +22,9 @@ import java.util.Map;
*/
public final class VirtualTable {
- /** Mapping from method signature to its entry address in the VM code segment. */
+ /**
+ * Mapping from method signature to its entry address in the VM code segment.
+ */
private final Map table = new HashMap<>();
/**
--
Gitee
From d1d30968e93576affe21557b57b77d9b178a740d Mon Sep 17 00:00:00 2001
From: Luke
Date: Wed, 10 Sep 2025 09:29:48 +0800
Subject: [PATCH 06/19] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=E5=8F=98?=
=?UTF-8?q?=E9=87=8F=E5=A3=B0=E6=98=8E=E4=B8=AD=E7=9A=84=E7=B1=BB=E5=9E=8B?=
=?UTF-8?q?=E6=8F=90=E5=8D=87?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../handlers/DeclarationHandler.java | 106 +++++++++++++-----
1 file changed, 79 insertions(+), 27 deletions(-)
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/builder/statement/handlers/DeclarationHandler.java b/src/main/java/org/jcnc/snow/compiler/ir/builder/statement/handlers/DeclarationHandler.java
index 4b5e9db8..5367d05a 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/builder/statement/handlers/DeclarationHandler.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/builder/statement/handlers/DeclarationHandler.java
@@ -1,24 +1,68 @@
package org.jcnc.snow.compiler.ir.builder.statement.handlers;
+import org.jcnc.snow.compiler.ir.builder.core.IRBuilderScope;
import org.jcnc.snow.compiler.ir.builder.statement.IStatementHandler;
import org.jcnc.snow.compiler.ir.builder.statement.StatementBuilderContext;
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
import org.jcnc.snow.compiler.parser.ast.DeclarationNode;
+import org.jcnc.snow.compiler.parser.ast.NewExpressionNode;
+import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
import org.jcnc.snow.compiler.parser.ast.base.StatementNode;
/**
- * 变量声明语句处理器。
+ * 变量声明语句处理器(Declaration Statement Handler)。
*
- * 负责将AST中的DeclarationNode节点(如“int a = 1;”)编译为IR层的变量声明和初始化指令。
- * 支持带初始化器与不带初始化器两种情况,并自动管理常量传播和作用域绑定。
+ * 负责将 AST 层的 {@link DeclarationNode}(如 {@code int a = 1;} 或 {@code Person p = new Student(...);})
+ * 编译为中间表示(IR)的变量声明、初始化、类型绑定、作用域注册等。
+ * 支持带初始化器和不带初始化器两种声明,并自动实现常量传播优化及多态类型推导。
*
+ * 多态类型推导的核心实现:
+ *
+ * 针对如 {@code declare x: Base = new Sub(...);} 这种父类变量直接赋 new 子类对象的情形,
+ * 若 {@code Sub} 确实继承自 {@code Base},则在当前作用域内注册变量时,将类型由 Base 升级为 Sub。
+ * 这样后续所有基于该变量的成员方法调用(如 x.getName())都能静态绑定到子类重写实现(静态多态)。
+ *
+ * 处理流程:
+ *
+ * - 如有初始化器,先记录变量声明类型并分配寄存器,生成初始化表达式指令。
+ * - 尝试常量折叠,注册或清理常量绑定。
+ * - 如初始化器为 new 子类(...),且子类继承自声明类型,则变量类型提升为子类。
+ * - 最终在作用域注册变量名、类型(可能提升)、寄存器绑定。
+ * - 如无初始化器,仅做类型和符号表注册,并清空常量绑定。
+ *
+ *
+ * 注意事项:
+ *
+ * - 本实现不会影响已有运行时结构,适用于现有虚拟机/IR,不依赖对象 vtable 派发。
+ * - 如需支持运行时真正多态,请在对象结构及方法调用指令层面额外设计。
+ *
*/
public class DeclarationHandler implements IStatementHandler {
+
/**
- * 判断是否可以处理给定的语句节点。
+ * 判断类型 child 是否是 parent 的子类(包含多级继承)。
+ * 依赖 IRBuilderScope 注册的 STRUCT_PARENTS。
*
- * @param stmt AST语句节点
- * @return 若为DeclarationNode类型则返回true,否则返回false
+ * @param child 子类名
+ * @param parent 父类名
+ * @return 若 child 继承自 parent,返回 true,否则 false
+ */
+ private static boolean isSubclassOf(String child, String parent) {
+ if (child == null || parent == null) return false;
+ if (child.equals(parent)) return true;
+ String t = child;
+ while (t != null) {
+ if (t.equals(parent)) return true;
+ t = IRBuilderScope.getStructParent(t);
+ }
+ return false;
+ }
+
+ /**
+ * 判断当前 Handler 是否可处理给定 AST 语句节点。
+ *
+ * @param stmt AST 语句节点
+ * @return 若为 DeclarationNode 类型则返回 true,否则返回 false
*/
@Override
public boolean canHandle(StatementNode stmt) {
@@ -26,18 +70,9 @@ public class DeclarationHandler implements IStatementHandler {
}
/**
- * 处理变量声明节点,生成变量声明与初始化的IR指令。
- *
- * 处理流程:
- *
- * - 若有初始化器,先记录类型,生成目标寄存器,并对初始化表达式赋值。
- * - 尝试常量折叠,若为常量则注册为常量变量,否则清除常量绑定。
- * - 完成变量声明并注册到作用域。
- * - 无初始化器时只做类型和符号表注册,并清空常量绑定。
- *
- *
+ * 处理变量声明语句(含类型提升及常量传播)。
*
- * @param stmt AST语句节点(已保证为DeclarationNode类型)
+ * @param stmt AST 语句节点(已保证为 DeclarationNode 类型)
* @param c 语句构建上下文
*/
@Override
@@ -45,24 +80,41 @@ public class DeclarationHandler implements IStatementHandler {
DeclarationNode decl = (DeclarationNode) stmt;
if (decl.getInitializer().isPresent()) {
- // 1. 有初始化器:先临时设置类型,分配目标寄存器并生成赋值IR
+ ExpressionNode init = decl.getInitializer().get();
+
+ // 1. 临时记录变量声明类型,供初始化表达式类型推断
c.ctx().setVarType(decl.getType());
+
+ // 2. 分配目标寄存器,并生成初始化表达式代码
IRVirtualRegister dest = c.ctx().newRegister();
- c.expr().buildInto(decl.getInitializer().get(), dest);
+ c.expr().buildInto(init, dest);
+ // 3. 常量传播优化
try {
- // 2. 尝试常量折叠,做常量传播优化
- Object constVal = c.constFolder().tryFoldConst(decl.getInitializer().get());
- if (constVal != null) c.ctx().getScope().setConstValue(decl.getName(), constVal);
- else c.ctx().getScope().clearConstValue(decl.getName());
+ Object constVal = c.constFolder().tryFoldConst(init);
+ if (constVal != null) {
+ c.ctx().getScope().setConstValue(decl.getName(), constVal);
+ } else {
+ c.ctx().getScope().clearConstValue(decl.getName());
+ }
} catch (Throwable ignored) {
}
-
c.ctx().clearVarType();
- // 3. 注册变量到作用域,绑定寄存器
- c.ctx().getScope().declare(decl.getName(), decl.getType(), dest);
+
+ // 4. 类型提升判定
+ String effectiveType = decl.getType();
+ if (init instanceof NewExpressionNode newExp) {
+ String newType = newExp.typeName();
+ if (isSubclassOf(newType, effectiveType)) {
+ effectiveType = newType;
+ }
+ }
+
+ // 5. 在作用域注册变量名、类型、寄存器
+ c.ctx().getScope().declare(decl.getName(), effectiveType, dest);
+
} else {
- // 4. 无初始化器,仅注册变量并清空常量绑定
+ // 无初始化器:仅注册类型及符号,并清空常量绑定
c.ctx().getScope().declare(decl.getName(), decl.getType());
c.ctx().getScope().clearConstValue(decl.getName());
}
--
Gitee
From ce97a8fea38e7072aae5dd4655a48409ff5676c1 Mon Sep 17 00:00:00 2001
From: Luke
Date: Wed, 10 Sep 2025 09:30:23 +0800
Subject: [PATCH 07/19] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0=E6=95=B0?=
=?UTF-8?q?=E7=BB=84=E5=AD=97=E9=9D=A2=E9=87=8F=E8=A1=A8=E8=BE=BE=E5=BC=8F?=
=?UTF-8?q?=E5=A4=84=E7=90=86=E5=99=A8=E6=96=87=E6=A1=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../jcnc/snow/compiler/ir/builder/handlers/NewHandler.java | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/builder/handlers/NewHandler.java b/src/main/java/org/jcnc/snow/compiler/ir/builder/handlers/NewHandler.java
index 2e475012..e42a1b42 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/builder/handlers/NewHandler.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/builder/handlers/NewHandler.java
@@ -16,7 +16,9 @@ import java.util.List;
/**
* 数组字面量表达式处理器。
*
- * 负责将 [a, b, c] 数组字面量节点编译为 IR 常量表达式,转换流程包括:
+ * 负责将 [a, b, c] 数组字面量节点编译为 IR 常量表达式
+ *
+ * 转换流程:
*
* - 递归遍历每个元素,确保全为编译期常量
* - 生成对应的 IRConstant 及 LoadConstInstruction 指令
--
Gitee
From 010365e516ec590bbaef6cafbb92258a576d7bd2 Mon Sep 17 00:00:00 2001
From: Luke
Date: Wed, 10 Sep 2025 09:56:24 +0800
Subject: [PATCH 08/19] =?UTF-8?q?docs:=20=E7=A7=BB=E9=99=A4=20DeclarationH?=
=?UTF-8?q?andler=20=E7=B1=BB=E4=B8=AD=E4=B8=8D=E5=BF=85=E8=A6=81=E7=9A=84?=
=?UTF-8?q?=E6=B3=A8=E9=87=8A?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../ir/builder/statement/handlers/DeclarationHandler.java | 5 -----
1 file changed, 5 deletions(-)
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/builder/statement/handlers/DeclarationHandler.java b/src/main/java/org/jcnc/snow/compiler/ir/builder/statement/handlers/DeclarationHandler.java
index 5367d05a..086f7174 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/builder/statement/handlers/DeclarationHandler.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/builder/statement/handlers/DeclarationHandler.java
@@ -31,11 +31,6 @@ import org.jcnc.snow.compiler.parser.ast.base.StatementNode;
* - 如无初始化器,仅做类型和符号表注册,并清空常量绑定。
*
*
- * 注意事项:
- *
- * - 本实现不会影响已有运行时结构,适用于现有虚拟机/IR,不依赖对象 vtable 派发。
- * - 如需支持运行时真正多态,请在对象结构及方法调用指令层面额外设计。
- *
*/
public class DeclarationHandler implements IStatementHandler {
--
Gitee
From eae45c5d2a589251fc76b05129f729787edaac92 Mon Sep 17 00:00:00 2001
From: Luke
Date: Wed, 10 Sep 2025 11:54:27 +0800
Subject: [PATCH 09/19] =?UTF-8?q?refactor:=20=E7=AE=80=E5=8C=96CallCommand?=
=?UTF-8?q?=E7=B1=BB=E7=9A=84=E5=AE=9E=E7=8E=B0=E5=92=8C=E6=96=87=E6=A1=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 精简了`CallCommand`类的文档,使其更加简洁明了。
- 移除了对虚拟调用的支持,仅保留静态调用。
- 优化了参数验证和异常处理逻辑。
- 删除了未使用的`Instance`和`VirtualTable`类,因为它们不再被`CallCommand`使用。
- 更新了`LocalVariableStore`类的文档和内部实现,以提高可读性和性能。
---
.../vm/commands/flow/control/CallCommand.java | 101 +++++++---------
.../org/jcnc/snow/vm/module/Instance.java | 95 ---------------
.../snow/vm/module/LocalVariableStore.java | 108 ++++++++++++------
.../org/jcnc/snow/vm/module/VirtualTable.java | 72 ------------
4 files changed, 118 insertions(+), 258 deletions(-)
delete mode 100644 src/main/java/org/jcnc/snow/vm/module/Instance.java
delete mode 100644 src/main/java/org/jcnc/snow/vm/module/VirtualTable.java
diff --git a/src/main/java/org/jcnc/snow/vm/commands/flow/control/CallCommand.java b/src/main/java/org/jcnc/snow/vm/commands/flow/control/CallCommand.java
index c5839629..d8d43476 100644
--- a/src/main/java/org/jcnc/snow/vm/commands/flow/control/CallCommand.java
+++ b/src/main/java/org/jcnc/snow/vm/commands/flow/control/CallCommand.java
@@ -6,93 +6,78 @@ import org.jcnc.snow.vm.module.*;
import static org.jcnc.snow.common.SnowConfig.print;
/**
- * The CallCommand class implements the {@link Command} interface and represents a subroutine/function call
- * instruction in the virtual machine.
- *
- * This command facilitates method invocation by creating a new stack frame, transferring arguments
- * from the operand stack to the callee's local variable store, and jumping to the specified target address.
- *
+ * Implements the CALL instruction for the virtual machine.
*
- * Specific behavior:
+ *
+ * Encoding (by {@code VMProgramBuilder.emitCall}):
*
- * - Parses the target address and the number of arguments from the instruction parameters.
- * - Validates the operands and checks for correct argument count.
- * - Builds a new local variable store for the callee and transfers arguments from the operand stack
- * (left-to-right order, where the top of the stack is the last argument).
- * - Pushes a new stack frame onto the call stack, saving the return address and local variables.
- * - Jumps to the specified target address to begin execution of the callee function.
- * - If any error occurs (e.g., malformed operands, stack underflow), an exception is thrown.
+ * - {@code CALL
} — static/known target
*
+ * The arguments are pushed to the operand stack from left to right before the call,
+ * so the last argument is on the top of the stack when this instruction executes.
+ *
*/
public class CallCommand implements Command {
/**
- * Executes the CALL instruction, initiating a subroutine/function call within the virtual machine.
+ * Executes the CALL instruction.
+ *
*
- * This method handles the creation of a new stack frame for the callee, argument passing,
- * and control transfer to the target function address.
+ * The CALL instruction transfers control to a subroutine at the given address,
+ * passing arguments from the operand stack to a new local variable store.
*
*
- * @param parts The instruction parameters. Must include:
- *
- * - {@code parts[0]}: The "CALL" operator.
- * - {@code parts[1]}: The target address of the callee function.
- * - {@code parts[2]}: The number of arguments to pass.
- *
- * @param currentPC The current program counter, used to record the return address for after the call.
- * @param operandStack The operand stack manager. Arguments are popped from this stack.
- * @param callerLVS The local variable store of the caller function (not directly modified here).
- * @param callStack The virtual machine's call stack manager, used to push the new stack frame.
- * @return The new program counter value, which is the address of the callee function (i.e., jump target).
- * The VM should transfer control to this address after setting up the call frame.
- * @throws IllegalArgumentException If the instruction parameters are malformed or missing.
- * @throws IllegalStateException If the operand stack does not contain enough arguments.
+ * @param parts the parts of the instruction; expects: [CALL, targetAddress, nArgs]
+ * @param currentPC the current program counter (PC)
+ * @param operandStack the VM's operand stack (used for passing arguments)
+ * @param ignoredCallerLVS the local variable store of the caller (unused in this implementation)
+ * @param callStack the VM's call stack (where new frames are pushed)
+ * @return the target address to transfer control to (i.e., jump to)
+ * @throws IllegalStateException if the instruction format is invalid
*/
@Override
public int execute(String[] parts,
int currentPC,
OperandStack operandStack,
- LocalVariableStore callerLVS,
+ LocalVariableStore /* caller LVT, unused */ ignoredCallerLVS,
CallStack callStack) {
- if (parts.length < 3)
- throw new IllegalArgumentException("CALL: need ");
+ // 1. Validate instruction arguments.
+ if (parts.length < 3) {
+ throw new IllegalStateException("CALL requires 2 operands: target and nArgs");
+ }
- /* ----------- Parse target address / method signature ----------- */
- final String targetToken = parts[1]; // Can be a numeric address or "@Class::method"
- final int nArgs = Integer.parseInt(parts[2]);
+ final String rawTarget = parts[1].trim();
+ final int nArgs = Integer.parseInt(parts[2].trim());
- /* ----------- Build callee's local variable store ----------- */
- LocalVariableStore calleeLVS = new LocalVariableStore();
- for (int slot = nArgs - 1; slot >= 0; slot--) {
- if (operandStack.isEmpty())
- throw new IllegalStateException("CALL: operand stack underflow");
- calleeLVS.setVariable(slot, operandStack.pop());
+ // 2. Pop arguments from the operand stack and restore left-to-right order.
+ // Arguments are pushed left-to-right, so we pop them and reverse into the args array.
+ final Object[] args = new Object[nArgs];
+ for (int i = nArgs - 1; i >= 0; i--) {
+ args[i] = operandStack.pop();
}
- /* ----------- Handle virtual call ----------- */
- int targetAddr;
- if (targetToken.startsWith("@")) { // "@Class::method" convention indicates a virtual call
- Object thisRef = calleeLVS.getVariable(0); // By convention, slot-0 stores "this"
- if (!(thisRef instanceof Instance inst))
- throw new IllegalStateException("VCALL: slot-0 is not an object reference");
+ // 3. Resolve the target address for the subroutine (currently supports only static calls).
+ int targetAddr = Integer.parseInt(rawTarget);
+ String methodNameForCtx = "subroutine@" + targetAddr;
+ print("\nCALL -> " + targetAddr);
- String methodSig = targetToken.substring(1); // Remove '@'
- targetAddr = inst.vtable().lookup(methodSig);
- } else {
- /* Direct/static call (numeric address) */
- targetAddr = Integer.parseInt(targetToken);
+ // 4. Build the callee's local variable store and copy arguments into it.
+ LocalVariableStore calleeLVS = new LocalVariableStore();
+ for (int i = 0; i < nArgs; i++) {
+ calleeLVS.setVariable(i, args[i]);
}
- /* ----------- Push new stack frame and jump ----------- */
+ // 5. Create a new stack frame for the callee and push it onto the call stack.
+ // The return address is set to the next instruction after CALL.
StackFrame newFrame = new StackFrame(
currentPC + 1,
calleeLVS,
- new MethodContext("subroutine@" + targetAddr, null)
+ new MethodContext(methodNameForCtx, null) // Don't log full args to avoid heavy logs
);
callStack.pushFrame(newFrame);
- print("\nCalling function at address: " + targetAddr);
- return targetAddr; // jump
+ // 6. Transfer control to the target address (subroutine entry point).
+ return targetAddr;
}
}
diff --git a/src/main/java/org/jcnc/snow/vm/module/Instance.java b/src/main/java/org/jcnc/snow/vm/module/Instance.java
deleted file mode 100644
index 87412e82..00000000
--- a/src/main/java/org/jcnc/snow/vm/module/Instance.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package org.jcnc.snow.vm.module;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * The {@code Instance} class represents a runtime object instance
- * in the virtual machine.
- *
- * Each instance maintains:
- *
- * - A reference to its {@link VirtualTable} (vtable), which provides
- * dynamic method dispatch and runtime method lookup.
- * - A map of field values, where each field is identified by name
- * and can hold an arbitrary object reference.
- *
- *
- * Key responsibilities:
- *
- * - Encapsulate the runtime state of an object.
- * - Enable field storage and retrieval through {@link #setField(String, Object)}
- * and {@link #getField(String)}.
- * - Provide access to the instance’s virtual table for method resolution.
- *
- */
-public final class Instance {
-
- /**
- * The virtual table associated with this instance (immutable).
- */
- private final VirtualTable vtable;
-
- /**
- * A mapping of field names to their runtime values.
- */
- private final Map fields = new HashMap<>();
-
- /**
- * Constructs a new {@code Instance} with the specified virtual table.
- *
- * @param vtable The virtual table that defines the method dispatch behavior
- * for this instance. Must not be {@code null}.
- */
- public Instance(VirtualTable vtable) {
- this.vtable = vtable;
- }
-
- /* ---------- Virtual Table ---------- */
-
- /**
- * Returns the virtual table associated with this instance.
- *
- * The virtual table is used for runtime method resolution
- * (dynamic dispatch).
- *
- *
- * @return The {@link VirtualTable} of this instance.
- */
- public VirtualTable vtable() {
- return vtable;
- }
-
- /* ---------- Fields ---------- */
-
- /**
- * Sets the value of a field in this instance.
- *
- * If the field does not already exist, it is created.
- * If the field exists, its value is overwritten.
- *
- *
- * @param name The name of the field to set. Must not be {@code null}.
- * @param value The value to assign to the field. Can be {@code null}.
- */
- public void setField(String name, Object value) {
- fields.put(name, value);
- }
-
- /**
- * Retrieves the value of a field in this instance.
- *
- * The value is cast to the expected type at runtime.
- * If the field is not present, this method returns {@code null}.
- *
- *
- * @param name The name of the field to retrieve. Must not be {@code null}.
- * @param The expected type of the field value.
- * @return The field value cast to type {@code T}, or {@code null} if absent.
- * @throws ClassCastException If the stored value cannot be cast to {@code T}.
- */
- @SuppressWarnings("unchecked")
- public T getField(String name) {
- return (T) fields.get(name);
- }
-}
diff --git a/src/main/java/org/jcnc/snow/vm/module/LocalVariableStore.java b/src/main/java/org/jcnc/snow/vm/module/LocalVariableStore.java
index 2904d04a..47d9fca9 100644
--- a/src/main/java/org/jcnc/snow/vm/module/LocalVariableStore.java
+++ b/src/main/java/org/jcnc/snow/vm/module/LocalVariableStore.java
@@ -9,70 +9,113 @@ import java.util.ArrayList;
import static org.jcnc.snow.vm.utils.VMUtils.isNativeImage;
/**
- * The {@code LocalVariableStore} represents a simple dynamically-sized
- * local-variable table (frame locals) of the VM.
+ * The {@code LocalVariableStore} represents a simple, dynamically-sized
+ * local-variable table (frame locals) for the virtual machine (VM).
*
- * It supports random access via {@link #setVariable(int, Object)}
- * / {@link #getVariable(int)} and can compact itself
- * by trimming trailing {@code null} slots after execution has finished.
+ * This class supports random access for storing and retrieving variables
+ * via {@link #setVariable(int, Object)} and {@link #getVariable(int)}.
+ * It can also compact itself by trimming trailing {@code null}
+ * slots after execution, for cleaner debug output.
+ *
+ *
Internally, it uses an {@link ArrayList} to store variables, automatically
+ * expanding as needed to support random index writes. This structure is designed
+ * for VM stack frame management and debug inspection.
*/
public class LocalVariableStore {
+ /**
+ * The backing list storing the local variables.
+ */
private final ArrayList localVariables;
- /* ---------- construction ---------- */
+ /* ---------- Construction ---------- */
+
+ /**
+ * Constructs a new {@code LocalVariableStore} with the given initial capacity.
+ *
+ * @param initialCapacity the initial capacity for the local variable list
+ */
public LocalVariableStore(int initialCapacity) {
this.localVariables = new ArrayList<>(initialCapacity);
handleMode();
}
+ /**
+ * Constructs a new {@code LocalVariableStore} with default capacity.
+ */
public LocalVariableStore() {
this.localVariables = new ArrayList<>();
handleMode();
}
- /* ---------- public API ---------- */
+ /* ---------- Public API ---------- */
/**
- * Sets the value at {@code index}, expanding the list if necessary.
+ * Sets the value at the specified index, expanding the list if necessary.
+ * If the list is smaller than {@code index + 1}, it will be padded
+ * with {@code null} until the required capacity is reached.
+ *
+ * @param index the index to set (0-based)
+ * @param value the value to store at the specified index
+ * @throws IndexOutOfBoundsException if {@code index} is negative
*/
public void setVariable(int index, Object value) {
ensureCapacity(index + 1);
localVariables.set(index, value);
}
- /* ------------------------------------------------------------
- * Backward compatibility: VM instruction decoder can directly call
- * store / load methods without caring about internal naming differences.
- * ------------------------------------------------------------ */
+ /**
+ * Stores a value at the specified index (alias for {@link #setVariable}).
+ *
This method is provided for VM instruction decoder compatibility.
+ *
+ * @param index the index to set
+ * @param value the value to store
+ */
public void store(int index, Object value) {
setVariable(index, value);
}
+ /**
+ * Loads the value from the specified index (alias for {@link #getVariable}).
+ *
This method is provided for VM instruction decoder compatibility.
+ *
+ * @param index the index to retrieve
+ * @return the value at the given index
+ */
public Object load(int index) {
return getVariable(index);
}
/**
- * Returns the value at {@code index}.
+ * Returns the value at the specified index.
+ *
If the list is not large enough, it is automatically expanded,
+ * filling new slots with {@code null} values.
+ *
+ * @param index the index to retrieve (0-based)
+ * @return the value at the specified index, or {@code null} if not set
+ * @throws IndexOutOfBoundsException if {@code index} is negative
*/
public Object getVariable(int index) {
- /* 修改点 #1 —— 自动扩容以避免 LOAD 越界异常 */
+ // Automatic expansion to avoid LOAD out-of-bounds exception.
if (index < 0)
throw new IndexOutOfBoundsException("Negative LV index: " + index);
ensureCapacity(index + 1);
- return localVariables.get(index); // 可能为 null,符合 JVM 语义
+ return localVariables.get(index);
}
/**
- * Exposes the backing list (read-only preferred).
+ * Returns the backing {@link ArrayList} storing the local variables.
+ *
Direct modification is not recommended. Prefer read-only usage.
+ *
+ * @return the internal list of local variables
*/
public ArrayList getLocalVariables() {
return localVariables;
}
/**
- * Prints every slot to the logger.
+ * Prints the contents of each slot in the local variable table to the logger.
+ * If the table is empty, a corresponding message is printed instead.
*/
public void printLv() {
if (localVariables.isEmpty()) {
@@ -86,24 +129,23 @@ public class LocalVariableStore {
}
}
-
- /* ---------- internal helpers ---------- */
+ /* ---------- Internal Helpers ---------- */
/**
- * Clears all variables (used when a stack frame is popped).
+ * Clears all variables in the table.
+ *
This method is typically called when a stack frame is popped.
*/
public void clearVariables() {
localVariables.clear();
}
/**
- * Compacts the table by removing trailing {@code null} slots.
- *
Call this once after program termination (e.g. in
- * {@code VirtualMachineEngine.execute()} before printing) to get
- * cleaner debug output without affecting execution-time indices.
+ * Compacts the table by removing only trailing {@code null} slots.
+ * This should be called after program termination, for cleaner debug output.
+ * Does not affect non-null slots or internal indices during execution.
*/
public void compact() {
- /* 修改点 #2 —— 仅删除“尾部” null,而不是整表过滤 */
+ // Only delete the "tail" null values, not filter the entire table.
int i = localVariables.size() - 1;
while (i >= 0 && localVariables.get(i) == null) {
localVariables.remove(i);
@@ -112,22 +154,22 @@ public class LocalVariableStore {
}
/**
- * Ensures backing list can hold {@code minCapacity} slots.
+ * Ensures that the backing list has at least the specified minimum capacity.
+ *
New slots are filled with {@code null} values if the list needs to grow.
+ *
+ * @param minCapacity the minimum capacity required
*/
private void ensureCapacity(int minCapacity) {
- /* 修改点 #3 —— 使用 while 循环填充 null,确保 slot 可随机写入 */
while (localVariables.size() < minCapacity) {
localVariables.add(null);
}
}
/**
- * Mode-specific UI hook for debugging.
- *
- * If debug mode is enabled and not running inside a GraalVM native-image,
- * this method will open the Swing-based variable inspector window.
- * In native-image environments (where AWT/Swing is unavailable),
- * the window will not be displayed.
+ * Handles debug mode hooks. If debug mode is enabled and not running inside a
+ * GraalVM native-image, this method will open a Swing-based variable inspector
+ * window for debugging purposes.
+ *
In native-image environments, this window is not displayed.
*/
private void handleMode() {
if (SnowConfig.isDebug()) {
diff --git a/src/main/java/org/jcnc/snow/vm/module/VirtualTable.java b/src/main/java/org/jcnc/snow/vm/module/VirtualTable.java
deleted file mode 100644
index 7ecda570..00000000
--- a/src/main/java/org/jcnc/snow/vm/module/VirtualTable.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package org.jcnc.snow.vm.module;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * The {@code VirtualTable} class represents a runtime virtual function table (vtable)
- * used by the virtual machine to support dynamic method dispatch.
- *
- * A vtable is a mapping from method signatures to their corresponding
- * entry addresses in the VM code segment. Each class or instance can have
- * its own vtable that determines which concrete method implementations
- * are invoked at runtime.
- *
- *
- * Key details:
- *
- * - Key: A method signature, such as {@code "Person::getName"}.
- * - Value: The entry point address of the method implementation
- * within the VM code segment.
- *
- */
-public final class VirtualTable {
-
- /**
- * Mapping from method signature to its entry address in the VM code segment.
- */
- private final Map table = new HashMap<>();
-
- /**
- * Registers a new method implementation in the virtual table, or overrides
- * an existing entry if the method signature is already present.
- *
- * @param methodSig The method signature (e.g., {@code "Person::getName"}).
- * @param addr The entry address of the method implementation in the VM code segment.
- */
- public void register(String methodSig, int addr) {
- table.put(methodSig, addr);
- }
-
- /**
- * Looks up the entry address for the given method signature.
- *
- * If the method is not found in the virtual table, an {@link IllegalStateException}
- * is thrown to aid debugging.
- *
- *
- * @param methodSig The method signature to look up.
- * @return The entry address of the corresponding method implementation.
- * @throws IllegalStateException If no mapping exists for the given method signature.
- */
- public int lookup(String methodSig) {
- Integer addr = table.get(methodSig);
- if (addr == null)
- throw new IllegalStateException("VTable missing entry: " + methodSig);
- return addr;
- }
-
- /**
- * Returns a read-only snapshot of the current virtual table.
- *
- * This is primarily intended for debugging or inspection purposes,
- * allowing external code to see the current state of the vtable
- * without modifying it.
- *
- *
- * @return An unmodifiable copy of the method signature to entry address mappings.
- */
- public Map snapshot() {
- return Map.copyOf(table);
- }
-}
--
Gitee
From 9b710abb5e78834a48bc4ae8eb1878ea219b50f9 Mon Sep 17 00:00:00 2001
From: Luke
Date: Wed, 10 Sep 2025 11:57:28 +0800
Subject: [PATCH 10/19] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0README=E6=96=87?=
=?UTF-8?q?=E6=A1=A3=E4=B8=AD=E7=9A=84=E6=89=A7=E8=A1=8C=E6=B5=81=E7=A8=8B?=
=?UTF-8?q?=E5=92=8C=E6=A0=B8=E5=BF=83=E5=8A=9F=E8=83=BD=E6=8F=8F=E8=BF=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 移除了`Instance`与`VirtualTable`相关的详细说明
---
src/main/java/org/jcnc/snow/vm/doc/README.md | 11 ++++-------
1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/src/main/java/org/jcnc/snow/vm/doc/README.md b/src/main/java/org/jcnc/snow/vm/doc/README.md
index 07f14a4f..ac5bb164 100644
--- a/src/main/java/org/jcnc/snow/vm/doc/README.md
+++ b/src/main/java/org/jcnc/snow/vm/doc/README.md
@@ -8,8 +8,8 @@
它采用**命令(Command)模式 + 统一操作码表(`VMOpCode`)+ 工厂注册(`CommandFactory`)**的结构,配合**运行时栈/局部变量表/调用栈
**与**方法栈帧**,构成清晰可扩展的执行层。
-执行流程:`VMLauncher/VMInitializer` 解析指令文件 → `CommandLoader` 读入并清洗文本 → `VirtualMachineEngine` 主循环按 **PC
-** 逐条解释执行(跳过空行与 `#` 注释),通过 `CommandExecutionHandler` 分发到各具体指令类,直到 `RET`(根帧)或 `HALT` 正常终止。
+执行流程:`VMLauncher/VMInitializer` 解析指令文件 → `CommandLoader` 读入并清洗文本 → `VirtualMachineEngine` 主循环按 PC
+逐条解释执行(跳过空行与 `#` 注释),通过 `CommandExecutionHandler` 分发到各具体指令类,直到 `RET`(根帧)或 `HALT` 正常终止。
## 核心功能
@@ -43,12 +43,11 @@
* **栈操作**:`PopCommand`(`POP`)、`DupCommand`(`DUP`)、`SwapCommand`(`SWAP`)
* **寄存器移动**:`MovCommand`(`MOV src,dst`,在同一局部变量表内复制槽位)
-* **引用/对象与虚方法支持**
+* **引用/对象支持**
* 引用操作:`R_PUSH / R_LOAD / R_STORE`(分别用于将引用压栈、从局部变量表加载/存储引用)
* 运行时模型:
* `module.StackFrame`(保存返回地址、`LocalVariableStore`、`OperandStack`、`MethodContext`)
* `module.CallStack`(带上限保护的调用栈)
- * `module.Instance`、`module.VirtualTable`(vtable:方法签名 → 入口地址,支持动态分派)
* **系统调用与 I/O**
* 统一入口:`SyscallCommand`(`SYSCALL`),失败时约定**向栈压 `-1`**
@@ -106,9 +105,7 @@ vm/
│ ├── LocalVariableStore // 局部变量表(自动扩容/紧凑化)
│ ├── CallStack // 调用栈(含深度保护)
│ ├── StackFrame // 栈帧:返回地址 + 局部表 + 栈 + 方法元信息
- │ ├── MethodContext // 方法上下文(名称/实参,用于调试)
- │ ├── Instance // 对象实例占位
- │ └── VirtualTable // vtable:方法签名 → 入口地址
+ │ └── MethodContext // 方法上下文(名称/实参,用于调试)
│
├── io/ // I/O 与文件系统桥接
│ ├── FDTable // 虚拟 fd ↔ NIO Channel 映射(含 0/1/2)
--
Gitee
From 4d8372df4c52c40893a25661449f9d2fb926e61b Mon Sep 17 00:00:00 2001
From: Luke
Date: Wed, 10 Sep 2025 15:16:39 +0800
Subject: [PATCH 11/19] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=20Signatur?=
=?UTF-8?q?eRegistrar=20=E7=B1=BB?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../semantic/core/SignatureRegistrar.java | 129 +++++++++++-------
1 file changed, 76 insertions(+), 53 deletions(-)
diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/core/SignatureRegistrar.java b/src/main/java/org/jcnc/snow/compiler/semantic/core/SignatureRegistrar.java
index 71e6cb4e..38d1dfc7 100644
--- a/src/main/java/org/jcnc/snow/compiler/semantic/core/SignatureRegistrar.java
+++ b/src/main/java/org/jcnc/snow/compiler/semantic/core/SignatureRegistrar.java
@@ -12,49 +12,66 @@ import java.util.List;
import java.util.Optional;
/**
- * {@code SignatureRegistrar}
+ * {@code SignatureRegistrar} 是语义分析前置阶段的注册器。
*
- * 语义分析准备阶段:负责函数签名登记、结构体签名登记与 import 校验。
+ * 它负责函数签名登记、结构体签名登记以及 import 模块引用校验,
+ * 为后续的类型推断和语义分析建立完整的类型环境。
*
+ *
本类通过三阶段处理逻辑,确保跨模块引用和继承在类型推断时可用:
+ *
+ * - 校验模块的 import 是否存在,并预注册结构体的名称占位符。
+ * - 解析结构体字段、构造函数和方法的签名信息。
+ * - 处理结构体继承关系,并继承字段与方法。
+ *
+ * 错误处理策略:
*
- * - 验证每个模块声明的 import 模块在全局模块表 {@link Context#modules()} 是否存在。
- * - 将每个函数、结构体方法、构造函数的类型签名登记到 {@link ModuleInfo},便于后续类型推断。
- * - 支持 {@code extends} 单继承:子类会继承父类的字段与方法。
- * - 若参数或返回类型无法解析,则报错并降级为 int 或 void,保证语义分析流程健壮。
+ * - 若引用未知模块、类型或父类,均会记录为 {@link SemanticError} 错误。
+ * - 若字段、参数、返回类型无法解析,将默认降级为 {@code int} 或 {@code void} 类型以保证流程健壮性。
*
- *
- * 作为语义分析前置流程,为后续函数体和表达式分析提供类型环境。
+ *
+ * @param ctx 语义分析上下文,记录所有模块、类型信息与错误列表
*/
public record SignatureRegistrar(Context ctx) {
/**
- * 遍历所有模块,注册函数/方法/结构体签名,校验 import 合法性。
+ * 注册传入的所有模块的类型签名信息,包括 import 检查、结构体与函数签名建立。
+ *
+ * 采用三阶段设计确保跨模块结构体引用/继承不会出错。
*
- * @param modules 需要分析的所有模块列表(AST 顶层节点)
+ * @param modules 所有模块 AST 节点列表
*/
public void register(Iterable modules) {
+ // 第一阶段:验证模块 imports 与预注册结构体名称
for (ModuleNode mod : modules) {
- ctx.setCurrentModule(mod.name()); // 切换上下文到当前模块
+ ctx.setCurrentModule(mod.name());
ModuleInfo mi = ctx.modules().get(mod.name());
- // ========== 1) 校验 imports ==========
+ // 检查 import 的模块是否存在
for (ImportNode imp : mod.imports()) {
if (!ctx.modules().containsKey(imp.moduleName())) {
- // 导入的模块在全局表中不存在,报错
ctx.errors().add(new SemanticError(imp, "未知模块: " + imp.moduleName()));
} else {
- // 添加到本模块导入集合
mi.getImports().add(imp.moduleName());
}
}
- // ========== 2) 结构体签名登记 ==========
+ // 为每个 struct 创建占位 StructType(无字段/方法)
for (StructNode stn : mod.structs()) {
- // 构造结构体类型对象,唯一标识为 (模块名, 结构体名)
- StructType st = new StructType(mod.name(), stn.name());
- mi.getStructs().put(stn.name(), st);
+ if (!mi.getStructs().containsKey(stn.name())) {
+ mi.getStructs().put(stn.name(), new StructType(mod.name(), stn.name()));
+ }
+ }
+ }
- // --- 2.0 字段签名登记 ---
+ // 第二阶段:解析 struct 字段、构造函数与方法签名
+ for (ModuleNode mod : modules) {
+ ctx.setCurrentModule(mod.name());
+ ModuleInfo mi = ctx.modules().get(mod.name());
+
+ for (StructNode stn : mod.structs()) {
+ StructType st = mi.getStructs().get(stn.name());
+
+ // 2.0 解析字段类型
if (stn.fields() != null) {
for (DeclarationNode field : stn.fields()) {
Type ft = ctx.parseType(field.getType());
@@ -66,12 +83,11 @@ public record SignatureRegistrar(Context ctx) {
}
}
- // --- 2.1 多个构造函数 init(重载,按参数个数区分) ---
+ // 2.1 注册构造函数类型(参数列表 -> void)
if (stn.inits() != null) {
for (FunctionNode initFn : stn.inits()) {
List ptypes = new ArrayList<>();
for (ParameterNode p : initFn.parameters()) {
- // 解析参数类型,不存在则报错降级为 int
Type t = ctx.parseType(p.type());
if (t == null) {
ctx.errors().add(new SemanticError(p, "未知类型: " + p.type()));
@@ -79,12 +95,11 @@ public record SignatureRegistrar(Context ctx) {
}
ptypes.add(t);
}
- // 构造函数返回类型固定为 void
st.addConstructor(new FunctionType(ptypes, BuiltinType.VOID));
}
}
- // --- 2.2 方法签名 ---
+ // 2.2 注册方法签名
for (FunctionNode fn : stn.methods()) {
List ptypes = new ArrayList<>();
for (ParameterNode p : fn.parameters()) {
@@ -100,32 +115,38 @@ public record SignatureRegistrar(Context ctx) {
st.getMethods().put(fn.name(), new FunctionType(ptypes, ret));
}
}
+ }
+
+ // 第三阶段:解析并建立 struct 的继承关系
+ for (ModuleNode mod : modules) {
+ ctx.setCurrentModule(mod.name());
+ ModuleInfo mi = ctx.modules().get(mod.name());
- // ========== 2.3 继承处理 ==========
for (StructNode stn : mod.structs()) {
- if (stn.parent() != null) {
- StructType child = mi.getStructs().get(stn.name());
- StructType parent = resolveParentStruct(mi, stn.parent());
-
- if (parent == null) {
- // 父类不存在(既不在本模块,也不在导入模块 / 限定名错误),报语义错误
- ctx.errors().add(new SemanticError(stn, "未知父类: " + stn.parent()));
- } else {
- // 建立继承链
- child.setParent(parent);
-
- // 继承字段
- parent.getFields().forEach(
- (k, v) -> child.getFields().putIfAbsent(k, v));
- // 继承方法
- parent.getMethods().forEach(
- (k, v) -> child.getMethods().putIfAbsent(k, v));
- // 构造函数不继承
- }
+ if (stn.parent() == null) continue;
+ StructType child = mi.getStructs().get(stn.name());
+ StructType parent = resolveParentStruct(mi, stn.parent());
+
+ if (parent == null) {
+ ctx.errors().add(new SemanticError(stn, "未知父类: " + stn.parent()));
+ continue;
}
+
+ // 建立父子继承关系
+ child.setParent(parent);
+ // 继承字段(若未重写)
+ parent.getFields().forEach((k, v) -> child.getFields().putIfAbsent(k, v));
+ // 继承方法(若未重写)
+ parent.getMethods().forEach((k, v) -> child.getMethods().putIfAbsent(k, v));
+ // 构造函数不继承
}
+ }
+
+ // 第四阶段:注册模块顶层函数签名
+ for (ModuleNode mod : modules) {
+ ctx.setCurrentModule(mod.name());
+ ModuleInfo mi = ctx.modules().get(mod.name());
- // ========== 3) 模块级函数签名登记 ==========
for (FunctionNode fn : mod.functions()) {
List params = new ArrayList<>();
for (ParameterNode p : fn.parameters()) {
@@ -144,14 +165,16 @@ public record SignatureRegistrar(Context ctx) {
}
/**
- * 解析父类结构体:
- *
- * - 支持限定名 {@code Module.Struct}。
- * - 支持在本模块与 import 的模块中按未限定名查找。
- *
+ * 解析父类结构体类型。
+ * 支持限定名形式(如 {@code Module.Struct}),
+ * 也支持在当前模块或导入模块中查找非限定名结构体。
+ *
+ * @param mi 当前模块信息
+ * @param parentName 父类名称(可以是限定名或非限定名)
+ * @return 对应的 StructType,找不到则返回 null
*/
private StructType resolveParentStruct(ModuleInfo mi, String parentName) {
- // 1. 限定名:Module.Struct
+ // 限定名:Module.Struct
int dot = parentName.indexOf('.');
if (dot > 0 && dot < parentName.length() - 1) {
String m = parentName.substring(0, dot);
@@ -163,11 +186,11 @@ public record SignatureRegistrar(Context ctx) {
return null;
}
- // 2. 先在当前模块找
+ // 当前模块中查找
StructType local = mi.getStructs().get(parentName);
if (local != null) return local;
- // 3. 在导入模块中找
+ // 导入模块中查找
for (String imported : mi.getImports()) {
ModuleInfo pim = ctx.modules().get(imported);
if (pim == null) continue;
@@ -175,7 +198,7 @@ public record SignatureRegistrar(Context ctx) {
if (st != null) return st;
}
- // 未找到
+ // 均找不到
return null;
}
}
--
Gitee
From 456fd48aa42184a1ce54c3bae567e2270e405224 Mon Sep 17 00:00:00 2001
From: Luke
Date: Wed, 10 Sep 2025 16:59:36 +0800
Subject: [PATCH 12/19] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96=20IRBuilde?=
=?UTF-8?q?rScope=20=E7=B1=BB=E7=BB=93=E6=9E=84=E5=92=8C=E6=96=87=E6=A1=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 更新类文档,明确 IRBuilderScope 的主要职责
- 优化方法文档,提高文档的准确性和可读性
- 删除冗余代码和不必要的注释
- 调整代码结构,按功能分组相关方法
---
.../ir/builder/core/IRBuilderScope.java | 169 +++++++-----------
1 file changed, 60 insertions(+), 109 deletions(-)
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/builder/core/IRBuilderScope.java b/src/main/java/org/jcnc/snow/compiler/ir/builder/core/IRBuilderScope.java
index 4df33b4d..61dad7f1 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/builder/core/IRBuilderScope.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/builder/core/IRBuilderScope.java
@@ -8,14 +8,13 @@ import java.util.HashMap;
import java.util.Map;
/**
- * {@code IRBuilderScope} 用于管理单个函数作用域内的变量名与虚拟寄存器的映射关系。
+ * {@code IRBuilderScope} 用于管理单个函数作用域内的变量名与虚拟寄存器的映射关系,以及相关类型、常量信息和结构体元数据。
*
- * 主要职责:
+ * 主要职责包括:
*
- * - 维护当前作用域内所有已声明变量的寄存器和类型信息
+ * - 维护当前作用域内所有已声明变量的虚拟寄存器和类型信息
* - 支持变量与虚拟寄存器的重新绑定与查找
- * - 支持变量的类型信息记录与查询
- * - 支持变量的编译期常量值记录与查询(便于常量折叠等优化)
+ * - 支持变量类型和编译期常量值的记录与查询
* - 支持跨模块全局常量(如 ModuleA.a)查找
* - 维护结构体字段布局(全局共享):字段名 → 槽位下标,用于对象字段读写
* - 维护结构体继承关系(子类 → 父类),super(...) 调用会用到
@@ -24,15 +23,15 @@ import java.util.Map;
public final class IRBuilderScope {
/**
- * 结构体字段布局表:结构体名 → (字段名 → 槽位下标)
+ * 结构体字段布局表(全局共享):结构体名 → (字段名 → 槽位下标)
*/
private static final Map> STRUCT_LAYOUTS = new HashMap<>();
/**
- * 结构体继承关系表:子类名 → 父类名
+ * 结构体继承关系表(全局共享):子类名 → 父类名
*/
private static final Map STRUCT_PARENTS = new HashMap<>();
/**
- * 变量名到虚拟寄存器的映射表(本地变量)
+ * 变量名到虚拟寄存器的映射表(本地变量,仅当前作用域)
*/
private final Map vars = new HashMap<>();
/**
@@ -52,27 +51,25 @@ public final class IRBuilderScope {
*/
private IRFunction fn;
- // ---------------- 作用域与变量 ----------------
+ // ---------------- 结构体全局布局/继承 注册与查询 ----------------
/**
- * 全局注册结构体的字段布局映射(字段名 -> 槽位下标)。
- * 一般在语义分析/IR 前期由类型系统收集后调用。
+ * 注册结构体字段布局。注册后该结构体名对应的字段布局会被全局保存。
*
- * @param structName 结构体名(建议为简单名,如 "Animal";如有模块前缀也可)
- * @param fieldToIndex 字段名到下标的映射(下标从 0 递增)
+ * @param structName 结构体名
+ * @param fieldToIndex 字段名到槽位下标的映射表
*/
static void registerStructLayout(String structName, Map fieldToIndex) {
if (structName == null || fieldToIndex == null) return;
- // 覆盖式注册:方便增量/重复编译时刷新
STRUCT_LAYOUTS.put(structName, new HashMap<>(fieldToIndex));
}
/**
- * 读取某结构体的完整字段布局(返回只读 Map)。
- * 支持“模块.结构体”及简单名两种写法。
+ * 获取结构体的字段布局。
+ * 支持全限定名与简单名查找。
*
- * @param structName 结构体名
- * @return 字段名到下标映射的只读视图,或 null
+ * @param structName 结构体名或全限定名
+ * @return 字段名到槽位下标的不可变映射表;若未注册则返回 null
*/
public static Map getStructLayout(String structName) {
Map layout = STRUCT_LAYOUTS.get(structName);
@@ -86,15 +83,10 @@ public final class IRBuilderScope {
}
/**
- * 注册结构体的父类信息。
- *
- * 该方法用于维护结构体与其父类之间的映射关系。通过调用此方法,
- * 可以为某个结构体名称指定其父结构体名称,并保存到全局的
- * {@code STRUCT_PARENTS} 映射中。
- *
+ * 注册结构体继承关系。
*
- * @param structName 子结构体的名称,不能为空或 {@code null}
- * @param parentName 父结构体的名称,不能为空、不能为 {@code null} 或空白
+ * @param structName 子类名
+ * @param parentName 父类名
*/
static void registerStructParent(String structName, String parentName) {
if (structName == null || parentName == null || parentName.isBlank()) return;
@@ -102,24 +94,10 @@ public final class IRBuilderScope {
}
/**
- * 获取某个结构体的父结构体名称。
- *
- * 查询逻辑如下:
- *
- * - 首先直接从 {@code STRUCT_PARENTS} 中查找对应的父结构体。
- * - 如果未找到,且 {@code structName} 含有点号(.),则提取点号后的简单类名进行查找。
- * - 如果仍未找到,则遍历 {@code STRUCT_PARENTS} 的所有条目:
- *
- * - 检查键(key)是否包含点号,若存在,则取其最后一个点号后的子串作为简单类名。
- * - 如果该简单类名与传入的 {@code structName} 相等,则返回对应的父类名称。
- *
- *
- * - 如果所有方式都未找到,则返回 {@code null}。
- *
- *
+ * 获取结构体父类名。支持全限定名和简单名的模糊查找。
*
- * @param structName 需要查找父类的结构体名称,可以是完整类名或简单类名
- * @return 父结构体名称;如果未找到,返回 {@code null}
+ * @param structName 结构体名
+ * @return 父类名;如果未注册或无父类则返回 null
*/
public static String getStructParent(String structName) {
if (structName == null || structName.isBlank()) return null;
@@ -143,93 +121,93 @@ public final class IRBuilderScope {
return null;
}
+ // ---------------- 作用域绑定 & 变量声明 ----------------
+
/**
- * 绑定当前作用域到指定 IRFunction。
+ * 绑定当前作用域至指定 IRFunction 对象。
+ * 后续变量声明、寄存器分配依赖于该函数上下文。
*
- * @param fn 目标 IRFunction
+ * @param fn 待绑定的 IRFunction 实例
*/
void attachFunction(IRFunction fn) {
this.fn = fn;
}
/**
- * 声明一个新变量并分配新的虚拟寄存器。
+ * 声明一个新变量,分配虚拟寄存器并记录类型。
+ * 同名变量会被覆盖。
*
- * @param name 变量名称
- * @param type 变量类型名
+ * @param name 变量名
+ * @param type 变量类型字符串
*/
public void declare(String name, String type) {
IRVirtualRegister reg = fn.newRegister();
vars.put(name, reg);
varTypes.put(name, type);
- varConstValues.remove(name); // 声明新变量即清除原常量绑定
+ varConstValues.remove(name);
}
/**
- * 声明新变量,并绑定到指定的寄存器。
+ * 声明一个新变量,指定虚拟寄存器并记录类型。
+ * 用于特殊情况(如参数寄存器直接传入)。
*
- * @param name 变量名称
- * @param type 变量类型名
- * @param reg 绑定的虚拟寄存器
+ * @param name 变量名
+ * @param type 变量类型字符串
+ * @param reg 指定的虚拟寄存器
*/
public void declare(String name, String type, IRVirtualRegister reg) {
vars.put(name, reg);
varTypes.put(name, type);
- varConstValues.remove(name); // 重复声明也会清除常量绑定
+ varConstValues.remove(name);
}
- // ---------------- 编译期常量 ----------------
-
/**
- * 更新变量的虚拟寄存器绑定(如变量已存在则覆盖,否则等同于新声明)。
+ * 更新指定变量所绑定的虚拟寄存器。
+ * 不改变类型信息。
*
- * @param name 变量名称
- * @param reg 新的虚拟寄存器
+ * @param name 变量名
+ * @param reg 新虚拟寄存器
*/
void put(String name, IRVirtualRegister reg) {
vars.put(name, reg);
}
/**
- * 查找变量名对应的虚拟寄存器。
+ * 查找变量对应的虚拟寄存器。
*
* @param name 变量名
- * @return 已绑定的虚拟寄存器,若未声明则返回 null
+ * @return 虚拟寄存器;不存在则返回 null
*/
public IRVirtualRegister lookup(String name) {
return vars.get(name);
}
/**
- * 查找变量名对应的类型名。
+ * 查找变量的类型字符串。
*
* @param name 变量名
- * @return 已声明类型字符串,若未声明则返回 null
+ * @return 类型字符串;不存在则返回 null
*/
public String lookupType(String name) {
return varTypes.get(name);
}
- // ---------------- 跨模块常量导入支持 ----------------
-
/**
- * 获取变量名到类型名映射的不可变副本。
+ * 获取当前作用域下所有变量的类型信息。
*
- * @return 变量名→类型名映射的只读视图(用于调试/全局分析)
+ * @return 不可变映射表:变量名 → 类型字符串
*/
public Map getVarTypes() {
return Collections.unmodifiableMap(varTypes);
}
- // ---------------- 结构体字段布局(全局静态) ----------------
+ // ---------------- 编译期常量与导入 ----------------
/**
- * 设置变量的编译期常量值(本地变量)。
- *
- * 便于 IR 生成时做常量折叠等优化,value 传 null 则清除绑定。
+ * 设置变量的编译期常量值。value=null 时将移除常量绑定。
*
- * @param name 变量名称
- * @param value 常量值(null 表示清除)
+ * @param name 变量名
+ * @param value 常量值对象;null 表示移除
*/
public void setConstValue(String name, Object value) {
if (value == null) varConstValues.remove(name);
@@ -237,61 +215,34 @@ public final class IRBuilderScope {
}
/**
- * 获取变量的编译期常量值(优先本地,再查跨模块导入)。
- *
- * 常用于优化与折叠,支持 "Module.a" 这类跨模块全局常量查找。
+ * 获取变量的编译期常量值。
+ * 若当前作用域未绑定,则查找导入的全局常量。
*
- * @param name 变量名称或"模块名.常量名"
- * @return 编译期常量值,或 null
+ * @param name 变量名(或导入常量名)
+ * @return 常量值对象;不存在则返回 null
*/
public Object getConstValue(String name) {
Object v = varConstValues.get(name);
if (v != null) return v;
- // 支持跨模块常量/全局变量(如 "ModuleA.a")
return externalConsts.get(name);
}
/**
- * 清除变量的编译期常量值绑定(本地)。
+ * 清除变量的编译期常量值绑定。
*
- * @param name 变量名称
+ * @param name 变量名
*/
public void clearConstValue(String name) {
varConstValues.remove(name);
}
- // ---------------- 结构体继承关系 ----------------
-
/**
- * 导入外部(其他模块)的全局常量/变量。
+ * 导入外部模块的全局常量。
*
- * @param qualifiedName 形如 "ModuleA.a"
- * @param value 其常量值
+ * @param qualifiedName 全限定名(如 ModuleA.a)
+ * @param value 常量值对象
*/
public void importExternalConst(String qualifiedName, Object value) {
externalConsts.put(qualifiedName, value);
}
-
- /**
- * 查询字段槽位下标。
- * 支持“模块.结构体”及简单名两种写法自动兼容。
- *
- * @param structName 结构体名("Module.Struct" 或 "Struct")
- * @param fieldName 字段名
- * @return 槽位下标;若未知返回 null
- */
- public Integer lookupFieldIndex(String structName, String fieldName) {
- // 先按原样查
- Map layout = STRUCT_LAYOUTS.get(structName);
- // 兼容 “模块.结构体” 的写法:若没命中,退化为简单名再查
- if (layout == null && structName != null) {
- int dot = structName.lastIndexOf('.');
- if (dot >= 0 && dot + 1 < structName.length()) {
- layout = STRUCT_LAYOUTS.get(structName.substring(dot + 1));
- }
- }
- if (layout == null) return null;
- return layout.get(fieldName);
- }
-
}
--
Gitee
From 205dac01aeeed39dfbdd9a9eb40d9f7efc220e12 Mon Sep 17 00:00:00 2001
From: Luke
Date: Wed, 10 Sep 2025 17:22:59 +0800
Subject: [PATCH 13/19] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E6=88=90?=
=?UTF-8?q?=E5=91=98=E8=AE=BF=E9=97=AE=E8=A1=A8=E8=BE=BE=E5=BC=8F=E5=A4=84?=
=?UTF-8?q?=E7=90=86=E9=80=BB=E8=BE=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 优化了成员访问表达式的处理流程,提高了代码可读性和可维护性
- 增加了对结构体继承和字段去重的处理,解决了父类字段下标重复计算的问题
- 改进了模块常量加载的逻辑,简化了代码结构
- 重新组织了代码结构,增加了注释,提高了代码的可理解性
---
.../ir/builder/handlers/MemberHandler.java | 153 ++++++++++++++----
1 file changed, 124 insertions(+), 29 deletions(-)
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/builder/handlers/MemberHandler.java b/src/main/java/org/jcnc/snow/compiler/ir/builder/handlers/MemberHandler.java
index f582002b..f39f7923 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/builder/handlers/MemberHandler.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/builder/handlers/MemberHandler.java
@@ -1,5 +1,6 @@
package org.jcnc.snow.compiler.ir.builder.handlers;
+import org.jcnc.snow.compiler.ir.builder.core.IRBuilderScope;
import org.jcnc.snow.compiler.ir.builder.expression.ExpressionBuilder;
import org.jcnc.snow.compiler.ir.builder.expression.ExpressionHandler;
import org.jcnc.snow.compiler.ir.common.GlobalConstTable;
@@ -11,64 +12,70 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
import org.jcnc.snow.compiler.parser.ast.IdentifierNode;
import org.jcnc.snow.compiler.parser.ast.MemberExpressionNode;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.*;
/**
- * 成员访问(MemberExpressionNode)处理器。
+ * {@code MemberHandler} 是成员访问表达式的处理器,
+ * 负责将 obj.field 类型的成员访问降级为底层的 __index_r(obj, fieldIndex) 调用。
+ * 主要解决结构体继承层级下 fieldIndex 的正确计算,避免父类字段下标重复累计的问题。
*
- * 负责处理对象字段、静态常量、模块常量等成员访问表达式,自动分派到对应的 IR 指令。
- * 支持对模块常量的优化直接折叠,也支持动态对象字段读取。
+ * 功能概述:
+ *
+ * - 对普通对象成员访问(如 obj.field)进行翻译,将其转换为 IR 的 __index_r(obj, fieldIndex) 形式;
+ * - 处理模块常量(如 ModuleName.constName),直接生成常量加载指令;
+ * - 智能处理扁平化与未扁平化结构体布局,准确计算字段的全局下标,兼容继承链与字段去重。
+ *
*/
public class MemberHandler implements ExpressionHandler {
+
/**
- * 处理成员访问表达式,返回对应的虚拟寄存器。
+ * 处理成员访问表达式,将 obj.field 转换为 __index_r(obj, fieldIndex) IR 表达式。
+ * 如果是 ModuleName.constName 这样的模块级常量,直接生成常量加载。
*
* @param b 表达式构建器
- * @param mem 成员访问 AST 节点
- * @return 存放成员值的虚拟寄存器
+ * @param mem 成员访问表达式 AST 节点
+ * @return IR 虚拟寄存器,存放成员访问结果
*/
@Override
public IRVirtualRegister handle(ExpressionBuilder b, MemberExpressionNode mem) {
- // ===== 1. 优先判定为模块常量(形如 mod.CONST)=====
- if (mem.object() instanceof IdentifierNode oid) {
- String mod = oid.name();
- Object c = GlobalConstTable.get(mod + "." + mem.member());
- if (c != null) {
- // 命中全局常量表,直接生成常量加载指令
- IRVirtualRegister r = b.ctx().newRegister();
- b.ctx().addInstruction(new LoadConstInstruction(r, new IRConstant(c)));
- return r;
+ // 特殊分支:如果是 ModuleName.constName,直接从全局常量表取常量
+ if (mem.object() instanceof IdentifierNode modId) {
+ Object constVal = GlobalConstTable.get(modId.name() + "." + mem.member());
+ if (constVal != null) {
+ IRVirtualRegister outConst = b.ctx().newRegister();
+ b.ctx().addInstruction(new LoadConstInstruction(outConst, IRConstant.fromObject(constVal)));
+ return outConst;
}
}
- // ===== 2. 常规对象字段访问(如 obj.field)=====
- IRVirtualRegister objReg = b.build(mem.object()); // 先获取对象寄存器
+ // 1. 计算被访问对象的寄存器
+ IRVirtualRegister objReg = b.build(mem.object());
- // ===== 3. 推断 owner 类型(优先用 object 的类型,否则 fallback 到 this 的类型)=====
+ // 2. 解析对象的类型(优先使用标识符,否则尝试 this)
String ownerType = null;
- if (mem.object() instanceof IdentifierNode oid) {
- ownerType = b.ctx().getScope().lookupType(oid.name());
+ if (mem.object() instanceof IdentifierNode id) {
+ ownerType = b.ctx().getScope().lookupType(id.name());
}
if (ownerType == null || ownerType.isEmpty()) {
- // 若找不到 object 的类型,则尝试 this
String thisType = b.ctx().getScope().lookupType("this");
- if (thisType != null) ownerType = thisType;
+ if (thisType != null && !thisType.isEmpty()) {
+ ownerType = thisType;
+ }
}
if (ownerType == null || ownerType.isEmpty()) {
throw new IllegalStateException("无法解析成员访问接收者的类型");
}
- // ===== 4. 查询字段索引(field offset),找不到直接报错 =====
- Integer fieldIndex = b.ctx().getScope().lookupFieldIndex(ownerType, mem.member());
+ // 3. 计算字段下标
+ Integer fieldIndex = resolveFieldIndex(ownerType, mem.member());
if (fieldIndex == null) {
throw new IllegalStateException("类型 " + ownerType + " 不存在字段: " + mem.member());
}
- // ===== 5. 生成下标参数,转为 __index_r 统一成员取值指令 =====
+ // 4. 生成 __index_r(obj, idx) 指令
IRVirtualRegister idxReg = b.ctx().newRegister();
- b.ctx().addInstruction(new LoadConstInstruction(idxReg,
- IRConstant.fromNumber(Integer.toString(fieldIndex))));
+ b.ctx().addInstruction(new LoadConstInstruction(
+ idxReg, IRConstant.fromNumber(Integer.toString(fieldIndex))));
IRVirtualRegister out = b.ctx().newRegister();
List args = new ArrayList<>();
@@ -77,4 +84,92 @@ public class MemberHandler implements ExpressionHandler {
b.ctx().addInstruction(new CallInstruction(out, "__index_r", args));
return out;
}
+
+ /**
+ * 计算结构体字段的下标槽位。
+ *
+ * - 若子类布局已扁平化(包含父类字段),直接返回布局中的下标;
+ * - 若未扁平化,则下标 = 去重累计的祖先字段数量 + 自身布局下标;
+ * - 若字段声明于祖先类,递归上溯继承链,并累计去重的祖先字段数量;
+ *
+ *
+ * @param structName 结构体名
+ * @param fieldName 字段名
+ * @return 字段在对象布局中的下标,找不到时返回 null
+ */
+ private Integer resolveFieldIndex(String structName, String fieldName) {
+ Map selfLayout = IRBuilderScope.getStructLayout(structName);
+
+ // 情况 A:字段在本类声明
+ if (selfLayout != null && selfLayout.containsKey(fieldName)) {
+ if (isFlattenedWithParent(structName, selfLayout)) {
+ // 已扁平化:布局里的下标就是全局槽位
+ return selfLayout.get(fieldName);
+ } else {
+ // 未扁平化:加上“去重后的祖先字段数”
+ return countDistinctAncestorFields(structName) + selfLayout.get(fieldName);
+ }
+ }
+
+ // 情况 B:字段在祖先类声明 —— 去重累计祖先字段数
+ int offset = 0;
+ Set seen = new HashSet<>();
+ String anc = IRBuilderScope.getStructParent(structName);
+ while (anc != null) {
+ Map ancLayout = IRBuilderScope.getStructLayout(anc);
+ if (ancLayout != null) {
+ if (ancLayout.containsKey(fieldName)) {
+ // 找到声明处:offset + 祖先布局中的下标
+ return offset + ancLayout.get(fieldName);
+ }
+ // 累计去重后的字段数
+ for (String k : ancLayout.keySet()) {
+ if (seen.add(k)) {
+ offset++;
+ }
+ }
+ }
+ anc = IRBuilderScope.getStructParent(anc);
+ }
+ return null;
+ }
+
+ /**
+ * 判断结构体布局是否已经“扁平化”地包含父类字段。
+ * 若任意父类字段出现在子类布局中,则认为已经扁平化。
+ *
+ * @param structName 当前结构体名
+ * @param childLayout 当前结构体的字段布局
+ * @return 如果已扁平化,返回 true;否则 false
+ */
+ private boolean isFlattenedWithParent(String structName, Map childLayout) {
+ String parent = IRBuilderScope.getStructParent(structName);
+ if (parent == null) return true;
+ Map parentLayout = IRBuilderScope.getStructLayout(parent);
+ if (parentLayout == null || parentLayout.isEmpty()) return true;
+ for (String k : parentLayout.keySet()) {
+ if (childLayout.containsKey(k)) return true;
+ }
+ return false;
+ }
+
+ /**
+ * 统计所有祖先类字段的数量(去重),
+ * 用于未扁平化继承场景,防止字段下标因继承链重复计算。
+ *
+ * @param structName 当前结构体名
+ * @return 所有祖先类字段(去重后)的总数
+ */
+ private int countDistinctAncestorFields(String structName) {
+ Set seen = new HashSet<>();
+ String anc = IRBuilderScope.getStructParent(structName);
+ while (anc != null) {
+ Map ancLayout = IRBuilderScope.getStructLayout(anc);
+ if (ancLayout != null) {
+ seen.addAll(ancLayout.keySet());
+ }
+ anc = IRBuilderScope.getStructParent(anc);
+ }
+ return seen.size();
+ }
}
--
Gitee
From c352fcdee9a78ab756fb8cb2040893948c1298fe Mon Sep 17 00:00:00 2001
From: Luke
Date: Wed, 10 Sep 2025 17:40:21 +0800
Subject: [PATCH 14/19] =?UTF-8?q?test:=20=E6=B7=BB=E5=8A=A0=20Graduate=20?=
=?UTF-8?q?=E7=B1=BB=E5=B9=B6=E6=9B=B4=E6=96=B0=E7=9B=B8=E5=85=B3=E4=BB=A3?=
=?UTF-8?q?=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 新增 Graduate 类,继承自 Student 类
- 在 Main.snow 中创建 Graduate 对象并调用 getName 方法
- 优化 Person 和 Student 类的代码格式
---
playground/Demo/Demo34/Graduate.snow | 22 +++++++++++++++++
playground/Demo/Demo34/Main.snow | 7 +++---
playground/Demo/Demo34/Person.snow | 34 +++++++++++++-------------
playground/Demo/Demo34/Student.snow | 36 +++++++++++++---------------
4 files changed, 58 insertions(+), 41 deletions(-)
create mode 100644 playground/Demo/Demo34/Graduate.snow
diff --git a/playground/Demo/Demo34/Graduate.snow b/playground/Demo/Demo34/Graduate.snow
new file mode 100644
index 00000000..50d7e761
--- /dev/null
+++ b/playground/Demo/Demo34/Graduate.snow
@@ -0,0 +1,22 @@
+module: Graduate
+ import: Student
+ struct: Graduate extends Student
+ fields:
+ declare year: int
+ init:
+ params:
+ declare name: int
+ declare year: int
+ body:
+ super(name)
+ this.year = year
+ end body
+ end init
+ function: getName
+ returns: int
+ body:
+ return super.getName() + this.year
+ end body
+ end function
+ end struct
+end module
diff --git a/playground/Demo/Demo34/Main.snow b/playground/Demo/Demo34/Main.snow
index d681d77c..5be9389d 100644
--- a/playground/Demo/Demo34/Main.snow
+++ b/playground/Demo/Demo34/Main.snow
@@ -1,14 +1,13 @@
module: main
- import: os,Student, Person
+ import: os,Student, Person, Graduate
function: main
returns: void
body:
declare a: Person = new Student(1)
-
os.println(a.getName())
-
-
+ declare p: Person = new Graduate(10, 2024)
+ os.println(p.getName())
end body
end function
end module
\ No newline at end of file
diff --git a/playground/Demo/Demo34/Person.snow b/playground/Demo/Demo34/Person.snow
index 395cd06a..868ee4fa 100644
--- a/playground/Demo/Demo34/Person.snow
+++ b/playground/Demo/Demo34/Person.snow
@@ -1,20 +1,20 @@
module: Person
-struct:Person
- fields:
- declare name: int
- init:
- params:
- declare name: int
- body:
- this.name = name
- end body
- end init
+ struct:Person
+ fields:
+ declare name: int
+ init:
+ params:
+ declare name: int
+ body:
+ this.name = name
+ end body
+ end init
- function: getName
- returns: int
- body:
- return this.name
- end body
- end function
-end struct
+ function: getName
+ returns: int
+ body:
+ return this.name
+ end body
+ end function
+ end struct
end module
\ No newline at end of file
diff --git a/playground/Demo/Demo34/Student.snow b/playground/Demo/Demo34/Student.snow
index a1cf41a4..3c750927 100644
--- a/playground/Demo/Demo34/Student.snow
+++ b/playground/Demo/Demo34/Student.snow
@@ -1,24 +1,20 @@
module: Student
-import : Person
+ import : Person
-struct : Student extends Person
- fields:
- declare id: int
+ struct : Student extends Person
+ init:
+ params:
+ declare name: int
+ body:
+ super(name)
+ end body
+ end init
- init:
- params:
- declare name: int
- body:
- super(name)
- end body
- end init
-
- // 重写父类方法,演示多态
- function: getName
- returns: int
- body:
- return super.getName() + 1000
- end body
- end function
-end struct
+ function: getName
+ returns: int
+ body:
+ return super.getName() + 1000
+ end body
+ end function
+ end struct
end module
--
Gitee
From dfc30a7c2b400db0ea107da9d788342efdb0bb48 Mon Sep 17 00:00:00 2001
From: Luke
Date: Wed, 10 Sep 2025 17:59:41 +0800
Subject: [PATCH 15/19] =?UTF-8?q?chore:=20=E7=A7=BB=E9=99=A4=20Demo34=20?=
=?UTF-8?q?=E8=BF=90=E8=A1=8C=E9=85=8D=E7=BD=AE=E4=B8=AD=E7=9A=84=E8=B0=83?=
=?UTF-8?q?=E8=AF=95=E5=8F=82=E6=95=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.run/Demo34.run.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.run/Demo34.run.xml b/.run/Demo34.run.xml
index d6e74c28..050c8705 100644
--- a/.run/Demo34.run.xml
+++ b/.run/Demo34.run.xml
@@ -2,7 +2,7 @@
-
+
--
Gitee
From 4fda5d49544351e322e1897ea9173fc314884e7f Mon Sep 17 00:00:00 2001
From: Luke
Date: Thu, 11 Sep 2025 11:24:26 +0800
Subject: [PATCH 16/19] =?UTF-8?q?test:=20=E6=9B=B4=E6=96=B0=E6=B5=8B?=
=?UTF-8?q?=E8=AF=95=E5=BA=8F=E5=88=97?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 在测试序列中添加了 Demo29、Demo30、Demo31、Demo32、Demo33 和 Demo34
---
".run/\346\265\213\350\257\225.run.xml" | 6 ++++++
1 file changed, 6 insertions(+)
diff --git "a/.run/\346\265\213\350\257\225.run.xml" "b/.run/\346\265\213\350\257\225.run.xml"
index 8152d4dc..1f30dd31 100644
--- "a/.run/\346\265\213\350\257\225.run.xml"
+++ "b/.run/\346\265\213\350\257\225.run.xml"
@@ -47,7 +47,13 @@
+
+
+
+
+
+
--
Gitee
From fb46bb1fb253bac0f1d202e387f0e394c71596b3 Mon Sep 17 00:00:00 2001
From: Luke
Date: Thu, 11 Sep 2025 11:25:14 +0800
Subject: [PATCH 17/19] =?UTF-8?q?test:=20=E4=BC=98=E5=8C=96=E5=87=BD?=
=?UTF-8?q?=E6=95=B0=E5=8F=82=E6=95=B0=E5=A3=B0=E6=98=8E?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
playground/Demo/Demo27/Test2.snow | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/playground/Demo/Demo27/Test2.snow b/playground/Demo/Demo27/Test2.snow
index 17613d69..7b7b5366 100644
--- a/playground/Demo/Demo27/Test2.snow
+++ b/playground/Demo/Demo27/Test2.snow
@@ -32,7 +32,7 @@ module: Main
// 重载示例:同名 eat,不同参数
function: eat
params:
- food: string
+ declare food: string
returns: void
body:
os.print(this.name + " eats " + food)
@@ -41,7 +41,7 @@ module: Main
function: eat
params:
- times: int
+ declare times: int
returns: void
body:
os.print(this.name + " eats " + times + " times.")
@@ -93,7 +93,7 @@ module: Main
// 多态演示函数
function: letAnimalSpeak
params:
- a: Animal
+ declare a: Animal
returns: void
body:
// 调用多态方法
--
Gitee
From 0ded492dc631efff4a38c6498e6ef406aa4b8424 Mon Sep 17 00:00:00 2001
From: Luke
Date: Thu, 11 Sep 2025 11:27:25 +0800
Subject: [PATCH 18/19] =?UTF-8?q?chore:=20=E7=A7=BB=E9=99=A4=20Demo33=20?=
=?UTF-8?q?=E8=BF=90=E8=A1=8C=E9=85=8D=E7=BD=AE=E4=B8=AD=E7=9A=84=E8=B0=83?=
=?UTF-8?q?=E8=AF=95=E5=8F=82=E6=95=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.run/Demo33.run.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.run/Demo33.run.xml b/.run/Demo33.run.xml
index 971ad410..d2c7ef00 100644
--- a/.run/Demo33.run.xml
+++ b/.run/Demo33.run.xml
@@ -2,7 +2,7 @@
-
+
--
Gitee
From fc28151f898463cbfdf81adf16341b8913a42772 Mon Sep 17 00:00:00 2001
From: Luke
Date: Thu, 11 Sep 2025 15:00:01 +0800
Subject: [PATCH 19/19] =?UTF-8?q?test:=20=E4=BF=AE=E6=AD=A3=E8=AF=AD?=
=?UTF-8?q?=E6=B3=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
playground/Demo/Demo27/Test2.snow | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/playground/Demo/Demo27/Test2.snow b/playground/Demo/Demo27/Test2.snow
index 7b7b5366..568837a8 100644
--- a/playground/Demo/Demo27/Test2.snow
+++ b/playground/Demo/Demo27/Test2.snow
@@ -13,7 +13,7 @@ module: Main
end body
end init
- // 封装:提供只读访问器
+ // 封装:提供只读访问器`
function: getName
returns: string
body:
--
Gitee