feat: 重构并扩展调用指令生成逻辑

- 优化了 syscall、数组下标访问和普通函数调用的处理逻辑
- 新增对多维数组下标访问的支持
- 改进了字符串常量和寄存器的绑定机制
- 统一了参数加载和错误处理的代码
This commit is contained in:
Luke 2025-08-01 23:33:31 +08:00
parent e5f23b77bd
commit 102e84bc01
3 changed files with 615 additions and 261 deletions

View File

@ -10,42 +10,46 @@ import org.jcnc.snow.compiler.ir.value.IRConstant;
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister; import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
import org.jcnc.snow.vm.engine.VMOpCode; import org.jcnc.snow.vm.engine.VMOpCode;
import java.util.*; import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/** /**
* {@code CallGenerator} 负责将 IR 层的 {@link CallInstruction} 生成对应的 VM 层函数调用指令 * {@code CallGenerator} 负责将 IR 层的 {@link CallInstruction} 生成对应的 VM 层函数调用指令
* <p> * <p>
* 支持 * 支持 syscall普通函数调用一维/多维数组下标访问以及字符串常量池绑定等功能
* <ul>
* <li>普通函数调用的参数压栈调用返回值保存</li>
* <li>特殊的 {@code syscall} 指令转为 VM SYSCALL 指令</li>
* <li>数组访问内置函数 {@code __index_i(arr, idx)} 的专用指令序列</li>
* </ul>
* <p>
* 对于 syscall 子命令支持常量字符串和字符串寄存器两种来源并支持寄存器-字符串常量池注册机制
* </p> * </p>
*
* <ul>
* <li>syscall: 支持字符串常量与寄存器到子命令的绑定与解析</li>
* <li>数组下标访问: 特殊的__index_i__index_r内部调用</li>
* <li>普通函数: 支持自动推断返回值类型与槽位类型</li>
* </ul>
*/ */
public class CallGenerator implements InstructionGenerator<CallInstruction> { public class CallGenerator implements InstructionGenerator<CallInstruction> {
/** /**
* 字符串常量池用于绑定虚拟寄存器 id 到字符串值 syscall 子命令使用 * 字符串常量池用于绑定虚拟寄存器 id 到字符串值 syscall 子命令使用
* <br>
* 使用 ConcurrentHashMap 保证并发安全所有 registerStringConst 的注册和读取都是线程安全的
*/ */
private static final Map<Integer, String> STRING_CONST_POOL = new HashMap<>(); private static final Map<Integer, String> STRING_CONST_POOL = new ConcurrentHashMap<>();
/** /**
* 注册一个字符串常量绑定到虚拟寄存器 id * 注册一个字符串常量绑定到虚拟寄存器 id
* *
* @param regId 虚拟寄存器 id * @param regId 虚拟寄存器 id
* @param value 字符串常量 * @param value 字符串常量
*/ */
public static void registerStringConst(int regId, String value) { public static void registerStringConst(int regId, String value) {
STRING_CONST_POOL.put(regId, value); STRING_CONST_POOL.put(regId, value);
} }
/** /**
* 返回当前指令生成器支持的 IR 指令类型 {@link CallInstruction} * 返回生成器支持的 IR 指令类型
* *
* @return {@code CallInstruction.class} * @return {@link CallInstruction} 类型的 Class 对象
*/ */
@Override @Override
public Class<CallInstruction> supportedClass() { public Class<CallInstruction> supportedClass() {
@ -53,122 +57,234 @@ public class CallGenerator implements InstructionGenerator<CallInstruction> {
} }
/** /**
* 生成 VM 指令序列实现函数调用/特殊 syscall/数组索引等 IR 指令的转换 * 生成指定的调用指令包括 syscall数组下标普通函数
* *
* @param ins 当前函数调用 IR 指令 * @param ins IR 层的调用指令
* @param out VM 指令输出构建器 * @param out VM 程序构建器
* @param slotMap IR 虚拟寄存器 VM 槽位映射表 * @param slotMap 寄存器到槽位的映射表
* @param currentFn 当前函数名 * @param currentFn 当前函数名
*/ */
@Override @Override
public void generate(CallInstruction ins, public void generate(CallInstruction ins,
VMProgramBuilder out, VMProgramBuilder out,
Map<IRVirtualRegister, Integer> slotMap, Map<IRVirtualRegister, Integer> slotMap,
String currentFn) { String currentFn) {
String fn = ins.getFunctionName();
/* ========== 特殊处理 syscall 调用 ========== */ // 特殊处理 syscall 调用
if ("syscall".equals(ins.getFunctionName()) || if ("syscall".equals(fn) || fn.endsWith(".syscall")) {
ins.getFunctionName().endsWith(".syscall")) { generateSyscall(ins, out, slotMap, fn);
return;
List<IRValue> args = ins.getArguments();
if (args.isEmpty()) {
throw new IllegalStateException("syscall 需要子命令参数");
}
// ---------- 0. 解析 syscall 子命令 ----------
// 支持 IRConstant 字面量或虚拟寄存器需已绑定字符串
String subcmd;
IRValue first = args.getFirst();
if (first instanceof IRConstant(Object value)) { // 直接字面量
if (!(value instanceof String s))
throw new IllegalStateException("syscall 第一个参数必须是字符串常量");
subcmd = s.toUpperCase(Locale.ROOT);
} else if (first instanceof IRVirtualRegister vr) { // 来自寄存器的字符串
String s = STRING_CONST_POOL.get(vr.id());
if (s == null)
throw new IllegalStateException("未找到 syscall 字符串常量绑定: " + vr);
subcmd = s.toUpperCase(Locale.ROOT);
} else {
throw new IllegalStateException("syscall 第一个参数必须是字符串常量");
}
// ---------- 1. 压栈其余 syscall 参数index 1 开始 ----------
for (int i = 1; i < args.size(); i++) {
IRVirtualRegister vr = (IRVirtualRegister) args.get(i);
int slotId = slotMap.get(vr);
char t = out.getSlotType(slotId);
if (t == '\0') t = 'I'; // 默认整型
out.emit(OpHelper.opcode(t + "_LOAD") + " " + slotId);
}
// ---------- 2. 生成 SYSCALL 指令 ----------
out.emit(VMOpCode.SYSCALL + " " + subcmd);
return; // syscall 无返回值直接返回
} }
/* ========== 特殊处理内部索引函数__index_i(arr, idx) ========== */ // 一维数组整型下标访问
if ("__index_i".equals(ins.getFunctionName())) { if ("__index_i".equals(fn)) {
// 加载参数arr 为引用类型idx 为整型 generateIndexInstruction(ins, out, slotMap, true);
if (ins.getArguments().size() != 2) { return;
throw new IllegalStateException("__index_i 需要两个参数(arr, idx)"); }
// 多维数组返回引用的下标访问
if ("__index_r".equals(fn)) {
generateIndexInstruction(ins, out, slotMap, false);
return;
}
// 普通函数调用
generateNormalCall(ins, out, slotMap, fn);
}
// ========== 私有辅助方法 ==========
/**
* 解析 syscall 子命令第一个参数支持字符串常量与已绑定字符串的虚拟寄存器
*
* @param arg 子命令参数应为字符串常量或寄存器
* @param fn 当前函数名仅用于报错信息
* @return 子命令大写字符串
* @throws IllegalStateException 如果参数不是字符串常量或已绑定寄存器
*/
private String resolveSyscallSubcmd(IRValue arg, String fn) {
switch (arg) {
case IRConstant(String s) -> {
return s.toUpperCase(Locale.ROOT);
} }
IRVirtualRegister arr = (IRVirtualRegister) ins.getArguments().get(0); case IRConstant(Object value) -> throw new IllegalStateException(
IRVirtualRegister idx = (IRVirtualRegister) ins.getArguments().get(1); "[CallGenerator] syscall 第一个参数必须是字符串常量 (function: %s, value: %s)"
.formatted(fn, value)
);
case IRVirtualRegister(int id) -> {
String s = STRING_CONST_POOL.get(id);
if (s == null) {
throw new IllegalStateException(
"[CallGenerator] 未找到 syscall 字符串常量绑定 (function: %s, regId: %d)"
.formatted(fn, id)
);
}
return s.toUpperCase(Locale.ROOT);
}
case null, default -> throw new IllegalStateException(
"[CallGenerator] syscall 第一个参数必须是字符串常量或已绑定字符串的寄存器 (function: %s, arg: %s)"
.formatted(fn, arg)
);
}
}
int arrSlot = slotMap.get(arr); /**
int idxSlot = slotMap.get(idx); * 加载一个参数到栈支持指定默认类型如果未设置类型则采用默认类型
*
* @param out VM 程序构建器
* @param slotMap 寄存器到槽位的映射
* @param arg 参数值应为虚拟寄存器
* @param defaultType 默认类型
* @param fn 当前函数名用于错误提示
* @throws IllegalStateException 如果参数不是虚拟寄存器或槽位未找到
*/
private void loadArgument(VMProgramBuilder out, Map<IRVirtualRegister, Integer> slotMap, IRValue arg, char defaultType, String fn) {
if (!(arg instanceof IRVirtualRegister vr)) {
throw new IllegalStateException(
"[CallGenerator] 参数必须为虚拟寄存器 (function: %s, arg: %s)".formatted(fn, arg));
}
Integer slot = slotMap.get(vr);
if (slot == null) {
throw new IllegalStateException(
"[CallGenerator] 未找到虚拟寄存器的槽位映射 (function: %s, reg: %s)".formatted(fn, vr));
}
char t = out.getSlotType(slot);
if (t == '\0') t = defaultType;
out.emit(OpHelper.opcode(t + "_LOAD") + " " + slot);
}
char arrT = out.getSlotType(arrSlot); /**
if (arrT == '\0') arrT = 'R'; // 默认为引用类型 * 生成一维/多维数组的下标访问指令
out.emit(OpHelper.opcode(arrT + "_LOAD") + " " + arrSlot); *
* @param ins 调用指令
* @param out VM 程序构建器
* @param slotMap 寄存器到槽位映射
* @param isInt 是否是一维整型下标
*/
private void generateIndexInstruction(CallInstruction ins, VMProgramBuilder out, Map<IRVirtualRegister, Integer> slotMap, boolean isInt) {
String fn = ins.getFunctionName();
List<IRValue> args = ins.getArguments();
if (args.size() != 2) {
throw new IllegalStateException(
"[CallGenerator] %s 需要两个参数(arr, idx),实际: %s".formatted(fn, args));
}
// 加载数组参数
loadArgument(out, slotMap, args.get(0), 'R', fn);
// 加载下标参数
loadArgument(out, slotMap, args.get(1), 'I', fn);
char idxT = out.getSlotType(idxSlot); out.emit(VMOpCode.SYSCALL + " " + "ARR_GET");
if (idxT == '\0') idxT = 'I'; // 默认为整型
out.emit(OpHelper.opcode(idxT + "_LOAD") + " " + idxSlot);
// 调用 SYSCALL ARR_GET VM 取出数组元素并压回栈顶 // 保存返回值到目标寄存器
out.emit(VMOpCode.SYSCALL + " " + "ARR_GET"); IRVirtualRegister dest = ins.getDest();
if (dest == null) {
// 取回返回值并保存当前仅支持 int 元素 throw new IllegalStateException(
int destSlot = slotMap.get(ins.getDest()); "[CallGenerator] %s 需要有目标寄存器用于保存返回值".formatted(fn));
}
Integer destSlot = slotMap.get(dest);
if (destSlot == null) {
throw new IllegalStateException(
"[CallGenerator] %s 未找到目标寄存器的槽位映射 (dest: %s)".formatted(fn, dest));
}
if (isInt) {
out.emit(OpHelper.opcode("I_STORE") + " " + destSlot); out.emit(OpHelper.opcode("I_STORE") + " " + destSlot);
out.setSlotType(destSlot, 'I'); out.setSlotType(destSlot, 'I');
return; } else {
out.emit(OpHelper.opcode("R_STORE") + " " + destSlot);
out.setSlotType(destSlot, 'R');
}
}
/**
* 生成 syscall 指令分支逻辑
* <ol>
* <li>解析 syscall 子命令</li>
* <li>压栈剩余参数</li>
* <li>发出 SYSCALL 指令</li>
* <li>若有返回值则保存至目标槽位</li>
* </ol>
*
* @param ins 调用指令
* @param out VM 程序构建器
* @param slotMap 寄存器到槽位映射
* @param fn 当前函数名
*/
private void generateSyscall(CallInstruction ins, VMProgramBuilder out, Map<IRVirtualRegister, Integer> slotMap, String fn) {
List<IRValue> args = ins.getArguments();
if (args.isEmpty()) {
throw new IllegalStateException(
"[CallGenerator] syscall 需要子命令参数 (function: %s)".formatted(fn));
} }
/* ========== 普通函数调用 ========== */ // 0. 解析 syscall 子命令第一个参数
String subcmd = resolveSyscallSubcmd(args.getFirst(), fn);
// ---------- 1. 推断返回值类型 void 返回时用 ---------- // 1. 压栈其余 syscall 参数 index 1 开始
char retType = 'I'; // 默认为整型 for (int i = 1; i < args.size(); i++) {
if (!ins.getArguments().isEmpty()) { loadArgument(out, slotMap, args.get(i), 'R', fn);
// 简化根据第一个参数类型推断返回类型或者通过全局表拿到返回类型 }
String ret = GlobalFunctionTable.getReturnType(ins.getFunctionName());
if (ret != null) { // 2. 生成 SYSCALL 指令
retType = Character.toUpperCase(ret.charAt(0)); out.emit(VMOpCode.SYSCALL + " " + subcmd);
// 3. 有返回值则保存到目标槽位
IRVirtualRegister dest = ins.getDest();
if (dest != null) {
Integer destSlot = slotMap.get(dest);
if (destSlot == null) {
throw new IllegalStateException(
"[CallGenerator] syscall 未找到目标寄存器的槽位映射 (function: %s, dest: %s)"
.formatted(fn, dest));
} }
out.emit(OpHelper.opcode("I_STORE") + " " + destSlot);
out.setSlotType(destSlot, 'I');
} }
}
// ---------- 2. 压栈所有参数 ---------- /**
* 生成普通函数调用指令
* <ol>
* <li>推断返回值类型</li>
* <li>压栈所有参数</li>
* <li>生成 CALL 指令</li>
* <li>保存返回值若非 void</li>
* </ol>
*
* @param ins 调用指令
* @param out VM 程序构建器
* @param slotMap 寄存器到槽位映射
* @param fn 当前函数名
*/
private void generateNormalCall(CallInstruction ins, VMProgramBuilder out, Map<IRVirtualRegister, Integer> slotMap, String fn) {
// 1. 推断返回值类型首字母大写缺省为 'I'
String retTypeName = GlobalFunctionTable.getReturnType(fn);
char retType = (retTypeName != null && !retTypeName.isEmpty()) ? Character.toUpperCase(retTypeName.charAt(0)) : 'I';
// 2. 压栈所有参数
for (IRValue arg : ins.getArguments()) { for (IRValue arg : ins.getArguments()) {
IRVirtualRegister vr = (IRVirtualRegister) arg; loadArgument(out, slotMap, arg, 'R', fn);
int slotId = slotMap.get(vr);
char t = out.getSlotType(slotId);
if (t == '\0') t = 'I';
out.emit(OpHelper.opcode(t + "_LOAD") + " " + slotId);
} }
// ---------- 3. 发出 CALL 指令 ---------- // 3. 发出 CALL 指令
out.emitCall(ins.getFunctionName(), ins.getArguments().size()); out.emitCall(fn, ins.getArguments().size());
// ---------- 3.5 如果为 void 返回直接结束 ---------- // 3.5 void 返回直接结束
if ("void".equals(GlobalFunctionTable.getReturnType(ins.getFunctionName()))) { if ("void".equals(retTypeName)) {
return; return;
} }
// ---------- 4. 保存返回值 ---------- // 4. 保存返回值到目标寄存器
int destSlot = slotMap.get(ins.getDest()); IRVirtualRegister dest = ins.getDest();
if (dest == null) {
throw new IllegalStateException(
"[CallGenerator] 普通函数调用未找到目标寄存器 (function: %s)".formatted(fn));
}
Integer destSlot = slotMap.get(dest);
if (destSlot == null) {
throw new IllegalStateException(
"[CallGenerator] 普通函数调用未找到目标寄存器的槽位映射 (function: %s, dest: %s)".formatted(fn, dest));
}
out.emit(OpHelper.opcode(retType + "_STORE") + " " + destSlot); out.emit(OpHelper.opcode(retType + "_STORE") + " " + destSlot);
out.setSlotType(destSlot, retType); out.setSlotType(destSlot, retType);
} }

View File

@ -12,7 +12,8 @@ import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
import org.jcnc.snow.compiler.parser.ast.*; import org.jcnc.snow.compiler.parser.ast.*;
import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
import java.util.*; import java.util.ArrayList;
import java.util.List;
/** /**
* {@code ExpressionBuilder} 表达式 IR 构建器 * {@code ExpressionBuilder} 表达式 IR 构建器
@ -24,17 +25,13 @@ import java.util.*;
* <li>为每种表达式类型生成对应 IR 指令</li> * <li>为每种表达式类型生成对应 IR 指令</li>
* <li>支持表达式嵌套的递归构建</li> * <li>支持表达式嵌套的递归构建</li>
* <li>支持写入指定目标寄存器避免冗余的 move 指令</li> * <li>支持写入指定目标寄存器避免冗余的 move 指令</li>
* <li>支持 IndexExpressionNode 的编译期折叠arr[2]自动降级为运行时调用 __index_i</li> * <li>支持 IndexExpressionNode 的编译期折叠arr[2]在运行时降级为 __index_i/__index_r</li>
* </ul> * </ul>
*/ */
public record ExpressionBuilder(IRContext ctx) { public record ExpressionBuilder(IRContext ctx) {
/** /**
* 构建表达式返回存储其结果的虚拟寄存器 * 构建表达式返回结果寄存器
*
* @param expr 要生成 IR 的表达式节点
* @return 存储表达式值的虚拟寄存器
* @throws IllegalStateException 不支持的表达式类型或未定义标识符
*/ */
public IRVirtualRegister build(ExpressionNode expr) { public IRVirtualRegister build(ExpressionNode expr) {
return switch (expr) { return switch (expr) {
@ -43,22 +40,22 @@ public record ExpressionBuilder(IRContext ctx) {
// 字符串字面量例如 "abc" // 字符串字面量例如 "abc"
case StringLiteralNode s -> buildStringLiteral(s.value()); case StringLiteralNode s -> buildStringLiteral(s.value());
// 布尔字面量例如 true / false // 布尔字面量例如 true / false
case BoolLiteralNode b -> buildBoolLiteral(b.getValue()); case BoolLiteralNode b -> buildBoolLiteral(b.getValue());
// 标识符变量名 ab // 标识符变量名 ab
case IdentifierNode id -> { case IdentifierNode id -> {
// 查找当前作用域中的变量寄存器 // 查找当前作用域中的变量寄存器
IRVirtualRegister reg = ctx.getScope().lookup(id.name()); IRVirtualRegister reg = ctx.getScope().lookup(id.name());
if (reg == null) if (reg == null) throw new IllegalStateException("未定义标识符: " + id.name());
throw new IllegalStateException("未定义标识符: " + id.name());
yield reg; yield reg;
} }
// 二元表达式 a+b, x==y // 二元表达式 a+b, x==y
case BinaryExpressionNode bin -> buildBinary(bin); case BinaryExpressionNode bin -> buildBinary(bin);
// 函数/方法调用表达式 // 函数/方法调用表达式
case CallExpressionNode call -> buildCall(call); case CallExpressionNode call -> buildCall(call);
// 一元表达式 -a, !a // 一元表达式 -a, !a
case UnaryExpressionNode un -> buildUnary(un); case UnaryExpressionNode un -> buildUnary(un);
case IndexExpressionNode idx -> buildIndex(idx);
case ArrayLiteralNode arr -> buildArrayLiteral(arr);
// 默认分支遇到未知表达式类型则直接抛异常 // 默认分支遇到未知表达式类型则直接抛异常
default -> throw new IllegalStateException( default -> throw new IllegalStateException(
"不支持的表达式类型: " + expr.getClass().getSimpleName()); "不支持的表达式类型: " + expr.getClass().getSimpleName());
@ -74,7 +71,7 @@ public record ExpressionBuilder(IRContext ctx) {
* <ul> * <ul>
* <li>字面量数字字符串布尔数组生成 loadConst 指令直接写入目标寄存器</li> * <li>字面量数字字符串布尔数组生成 loadConst 指令直接写入目标寄存器</li>
* <li>变量标识符查表获取源寄存器 move 到目标寄存器</li> * <li>变量标识符查表获取源寄存器 move 到目标寄存器</li>
* <li>二元表达式与下标表达式递归生成子表达式结果并写入目标寄存器</li> * <li>二元表达式下标调用表达式递归生成子表达式结果并写入目标寄存器</li>
* <li>其它类型统一先 build 到临时寄存器 move 到目标寄存器</li> * <li>其它类型统一先 build 到临时寄存器 move 到目标寄存器</li>
* </ul> * </ul>
* </p> * </p>
@ -85,22 +82,23 @@ public record ExpressionBuilder(IRContext ctx) {
*/ */
public void buildInto(ExpressionNode node, IRVirtualRegister dest) { public void buildInto(ExpressionNode node, IRVirtualRegister dest) {
switch (node) { switch (node) {
// 数字字面量生成 loadConst 指令写入目标寄存器 // 数字字面量生成 loadConst 指令将数值常量写入目标寄存器
case NumberLiteralNode n -> case NumberLiteralNode n -> InstructionFactory.loadConstInto(
InstructionFactory.loadConstInto( ctx, dest, ExpressionUtils.buildNumberConstant(ctx, n.value()));
ctx, dest, ExpressionUtils.buildNumberConstant(ctx, n.value()));
// 字符串字面量生成 loadConst 指令写入目标寄存器 // 字符串字面量生成 loadConst 指令将字符串常量写入目标寄存器
case StringLiteralNode s -> case StringLiteralNode s -> InstructionFactory.loadConstInto(
InstructionFactory.loadConstInto( ctx, dest, new IRConstant(s.value()));
ctx, dest, new IRConstant(s.value()));
// 布尔字面量转换为 int 1/0生成 loadConst // 布尔字面量转换为 int 1/0生成 loadConst 指令写入目标寄存器
case BoolLiteralNode b -> case BoolLiteralNode b -> InstructionFactory.loadConstInto(
InstructionFactory.loadConstInto( ctx, dest, new IRConstant(b.getValue() ? 1 : 0));
ctx, dest, new IRConstant(b.getValue() ? 1 : 0));
case ArrayLiteralNode arr -> // 数组字面量生成数组常量并写入目标寄存器
InstructionFactory.loadConstInto(ctx, dest, buildArrayConstant(arr)); case ArrayLiteralNode arr -> InstructionFactory.loadConstInto(
ctx, dest, buildArrayConstant(arr));
// 变量标识符查表获得源寄存器move 到目标寄存器
case IdentifierNode id -> { case IdentifierNode id -> {
IRVirtualRegister src = ctx.getScope().lookup(id.name()); IRVirtualRegister src = ctx.getScope().lookup(id.name());
if (src == null) if (src == null)
@ -108,12 +106,22 @@ public record ExpressionBuilder(IRContext ctx) {
InstructionFactory.move(ctx, src, dest); InstructionFactory.move(ctx, src, dest);
} }
// 二元表达式递归生成并写入目标寄存器 // 二元表达式递归生成左右子表达式将结果写入目标寄存器
case BinaryExpressionNode bin -> buildBinaryInto(bin, dest); case BinaryExpressionNode bin -> buildBinaryInto(bin, dest);
// 下标表达式递归生成索引结果move 到目标寄存器
case IndexExpressionNode idx -> { case IndexExpressionNode idx -> {
IRVirtualRegister tmp = buildIndex(idx); IRVirtualRegister tmp = buildIndex(idx);
InstructionFactory.move(ctx, tmp, dest); InstructionFactory.move(ctx, tmp, dest);
} }
// 调用表达式递归生成调用结果move 到目标寄存器
case CallExpressionNode call -> {
IRVirtualRegister tmp = buildCall(call);
InstructionFactory.move(ctx, tmp, dest);
}
// 其它类型统一先 build 到临时寄存器 move 到目标寄存器
default -> { default -> {
IRVirtualRegister tmp = build(node); IRVirtualRegister tmp = build(node);
InstructionFactory.move(ctx, tmp, dest); InstructionFactory.move(ctx, tmp, dest);
@ -121,80 +129,182 @@ public record ExpressionBuilder(IRContext ctx) {
} }
} }
/** /**
* 下标访问表达式处理支持编译期常量折叠数组和下标均为常量时直接求值 * 构建下标访问表达式IndexExpressionNode
* 否则生成运行时调用 __index_i VM 降级为 ARR_GET * <ul>
* <li>若数组和下标均为编译期常量则直接进行常量折叠直接返回目标常量寄存器</li>
* <li>否则
* <ul>
* <li>若数组表达式本身是下一个下标的中间值即多维数组链式下标则先用 __index_r 获取引用</li>
* <li>最后一级用 __index_i 获取实际整型元素值</li>
* </ul>
* </li>
* </ul>
* *
* @param node 下标访问表达式 * @param node 下标访问表达式节点
* @return 存储结果的虚拟寄存器 * @return 结果的虚拟寄存器
*/ */
private IRVirtualRegister buildIndex(IndexExpressionNode node) { private IRVirtualRegister buildIndex(IndexExpressionNode node) {
// 1. 常量折叠如果 array index 都是编译期常量直接取值
Object arrConst = tryFoldConst(node.array()); Object arrConst = tryFoldConst(node.array());
Object idxConst = tryFoldConst(node.index()); Object idxConst = tryFoldConst(node.index());
if (arrConst instanceof java.util.List<?> list && idxConst instanceof Number num) { if (arrConst instanceof java.util.List<?> list && idxConst instanceof Number num) {
int i = num.intValue(); int i = num.intValue();
// 越界检查
if (i < 0 || i >= list.size()) if (i < 0 || i >= list.size())
throw new IllegalStateException("数组下标越界: " + i + " (长度 " + list.size() + ")"); throw new IllegalStateException("数组下标越界: " + i + " (长度 " + list.size() + ")");
Object elem = list.get(i); Object elem = list.get(i);
IRVirtualRegister r = ctx.newRegister(); IRVirtualRegister r = ctx.newRegister();
// 加载常量元素到新寄存器
InstructionFactory.loadConstInto(ctx, r, new IRConstant(elem)); InstructionFactory.loadConstInto(ctx, r, new IRConstant(elem));
return r; return r;
} }
IRVirtualRegister arrReg = build(node.array());
// 2. 处理多级下标 arr[1][2]中间层用 __index_r 返回引用
IRVirtualRegister arrReg = (node.array() instanceof IndexExpressionNode inner)
? buildIndexRef(inner) // 递归获取引用
: build(node.array()); // 否则直接生成 array 的值
// 3. 生成下标值
IRVirtualRegister idxReg = build(node.index()); IRVirtualRegister idxReg = build(node.index());
IRVirtualRegister dest = ctx.newRegister();
// 4. 创建目标寄存器
IRVirtualRegister dest = ctx.newRegister();
// 5. 准备参数
List<IRValue> argv = new ArrayList<>(); List<IRValue> argv = new ArrayList<>();
argv.add(arrReg); argv.add(arrReg);
argv.add(idxReg); argv.add(idxReg);
ctx.addInstruction(new CallInstruction(dest, "__index_i", argv));
// 6. 选择调用指令
if (node.array() instanceof IndexExpressionNode) {
// 非最末层下标取引用
ctx.addInstruction(new CallInstruction(dest, "__index_r", argv));
} else {
// 最末层下标取实际元素值
ctx.addInstruction(new CallInstruction(dest, "__index_i", argv));
}
return dest; return dest;
} }
/** /**
* 尝试将表达式折叠为编译期常量支持嵌套 * 构建中间层下标访问表达式返回引用
* 支持数字字符串布尔数组常量标识符 * <p>
* 用于多维数组的链式下标访问 arr[1][2]保证中间结果是可被再次下标的引用
* <ul>
* <li>若数组和下标均为编译期常量则直接常量折叠返回目标常量寄存器</li>
* <li>否则递归处理 array生成引用指令__index_r</li>
* </ul>
* </p>
* *
* @param expr 要折叠的表达式节点 * @param node 下标访问表达式节点
* @return 常量对象如数字字符串List否则返回 null * @return 存放引用结果的虚拟寄存器
*/
private IRVirtualRegister buildIndexRef(IndexExpressionNode node) {
// 1. 常量折叠如果 array index 都是编译期常量直接取值
Object arrConst = tryFoldConst(node.array());
Object idxConst = tryFoldConst(node.index());
if (arrConst instanceof java.util.List<?> list && idxConst instanceof Number num) {
int i = num.intValue();
// 越界检查
if (i < 0 || i >= list.size())
throw new IllegalStateException("数组下标越界: " + i + " (长度 " + list.size() + ")");
Object elem = list.get(i);
IRVirtualRegister r = ctx.newRegister();
// 加载常量元素到新寄存器
InstructionFactory.loadConstInto(ctx, r, new IRConstant(elem));
return r;
}
// 2. 递归生成 array 引用用于支持链式多级下标
IRVirtualRegister arrReg = (node.array() instanceof IndexExpressionNode inner)
? buildIndexRef(inner) // 递归向下返回引用
: build(node.array()); // 基础数组直接 build
// 3. 生成下标值
IRVirtualRegister idxReg = build(node.index());
// 4. 创建目标寄存器
IRVirtualRegister dest = ctx.newRegister();
// 5. 组织参数列表
List<IRValue> argv = new ArrayList<>();
argv.add(arrReg);
argv.add(idxReg);
// 6. 生成 __index_r 调用指令总是返回引用
ctx.addInstruction(new CallInstruction(dest, "__index_r", argv));
return dest;
}
/**
* 常量折叠工具支持嵌套数组
* <p>
* 尝试将表达式节点 {@code expr} 折叠为常量值用于编译期计算/优化
* <ul>
* <li>数字字面量返回 int double</li>
* <li>字符串字面量返回字符串</li>
* <li>布尔字面量返回 1true 0false</li>
* <li>数组字面量递归折叠所有元素为 List如果有一项不能折叠则返回 null</li>
* <li>标识符尝试从作用域查找编译期常量值</li>
* <li>其它类型无法折叠返回 null</li>
* </ul>
* </p>
*
* @param expr 需要折叠的表达式节点
* @return 编译期常量值支持 intdoubleStringList否则返回 null
*/ */
private Object tryFoldConst(ExpressionNode expr) { private Object tryFoldConst(ExpressionNode expr) {
if (expr == null) return null; if (expr == null) return null;
// 数字字面量尝试解析为 int double
if (expr instanceof NumberLiteralNode n) { if (expr instanceof NumberLiteralNode n) {
String s = n.value(); String s = n.value();
try { try {
if (s.contains(".") || s.contains("e") || s.contains("E")) { if (s.contains(".") || s.contains("e") || s.contains("E"))
return Double.parseDouble(s); return Double.parseDouble(s); // 带小数或科学计数法为 double
} return Integer.parseInt(s); // 否则为 int
return Integer.parseInt(s);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
return null; return null; // 无法解析为数字
} }
} }
if (expr instanceof StringLiteralNode s) {
return s.value(); // 字符串字面量直接返回字符串
} if (expr instanceof StringLiteralNode s) return s.value();
if (expr instanceof BoolLiteralNode b) {
return b.getValue() ? 1 : 0; // 布尔字面量true 返回 1false 返回 0
} if (expr instanceof BoolLiteralNode b) return b.getValue() ? 1 : 0;
// 数组字面量递归折叠所有元素
if (expr instanceof ArrayLiteralNode arr) { if (expr instanceof ArrayLiteralNode arr) {
java.util.List<Object> list = new java.util.ArrayList<>(); List<Object> list = new ArrayList<>();
for (ExpressionNode e : arr.elements()) { for (ExpressionNode e : arr.elements()) {
Object v = tryFoldConst(e); Object v = tryFoldConst(e);
if (v == null) return null; if (v == null) return null; // 有一项无法折叠则整体失败
list.add(v); list.add(v);
} }
return java.util.List.copyOf(list); return List.copyOf(list);
} }
// 标识符尝试查找作用域中的常量值
if (expr instanceof IdentifierNode id) { if (expr instanceof IdentifierNode id) {
Object v = null; Object v = null;
try { try {
v = ctx.getScope().getConstValue(id.name()); v = ctx.getScope().getConstValue(id.name());
} catch (Throwable ignored) {} } catch (Throwable ignored) {
// 查不到常量或异常都视为无法折叠
}
return v; return v;
} }
// 其它类型不支持折叠返回 null
return null; return null;
} }
/** /**
* 一元表达式构建 * 一元表达式构建
* *
@ -207,62 +317,70 @@ public record ExpressionBuilder(IRContext ctx) {
*/ */
private IRVirtualRegister buildUnary(UnaryExpressionNode un) { private IRVirtualRegister buildUnary(UnaryExpressionNode un) {
// 递归生成操作数的寄存器 // 递归生成操作数的寄存器
IRVirtualRegister src = build(un.operand()); IRVirtualRegister src = build(un.operand());
// 分配目标寄存器 // 分配目标寄存器
IRVirtualRegister dest = ctx.newRegister(); IRVirtualRegister dest = ctx.newRegister();
switch (un.operator()) { switch (un.operator()) {
// 算术负号生成取负指令 // 算术负号生成取负指令例如-a
case "-" -> ctx.addInstruction( case "-" -> ctx.addInstruction(
new UnaryOperationInstruction(ExpressionUtils.negOp(un.operand()), dest, src)); new UnaryOperationInstruction(ExpressionUtils.negOp(un.operand()), dest, src));
// 逻辑非等价于 a == 0生成比较指令
// 逻辑非等价于 a == 0生成整数等于比较指令!a
case "!" -> { case "!" -> {
// 生成常量0的寄存器
IRVirtualRegister zero = InstructionFactory.loadConst(ctx, 0); IRVirtualRegister zero = InstructionFactory.loadConst(ctx, 0);
// 比较 src 是否等于0等价于逻辑非
return InstructionFactory.binOp(ctx, IROpCode.CMP_IEQ, src, zero); return InstructionFactory.binOp(ctx, IROpCode.CMP_IEQ, src, zero);
} }
// 其它一元运算符不支持异常 // 其它一元运算符不支持异常
default -> throw new IllegalStateException("未知一元运算符: " + un.operator()); default -> throw new IllegalStateException("未知一元运算符: " + un.operator());
} }
return dest; return dest;
} }
/** /**
* 构建函数或方法调用表达式模块内未限定调用会自动补全当前模块名 * 构建函数或方法调用表达式
* <p>
* 支持普通函数调用foo(a, b)与成员方法调用obj.method(a, b)
* <ul>
* <li>首先递归生成所有参数的虚拟寄存器列表</li>
* <li>根据 callee 类型区分成员访问或直接标识符调用并规范化方法名如加前缀</li>
* <li>为返回值分配新寄存器生成 Call 指令</li>
* </ul>
* </p>
* *
* @param call AST 调用表达式节点 * @param call 函数/方法调用表达式节点
* @return 存储调用结果的虚拟寄存器 * @return 调用结果的虚拟寄存器
*/ */
private IRVirtualRegister buildCall(CallExpressionNode call) { private IRVirtualRegister buildCall(CallExpressionNode call) {
// 递归生成所有参数实参对应的寄存器 // 1. 递归生成所有参数的寄存器
List<IRVirtualRegister> argv = call.arguments().stream().map(this::build).toList(); List<IRVirtualRegister> argv = call.arguments().stream().map(this::build).toList();
// 解析被调用目标名支持普通函数/成员方法 // 2. 规范化被调用方法名区分成员方法与普通函数
String callee = switch (call.callee()) { String callee = switch (call.callee()) {
// 成员方法调用例如 obj.foo() // 成员方法调用 obj.method()
case MemberExpressionNode m when m.object() instanceof IdentifierNode id case MemberExpressionNode m when m.object() instanceof IdentifierNode id -> id.name() + "." + m.member();
-> id.name() + "." + m.member(); // 普通函数调用或处理命名空间前缀如当前方法名为 namespace.func
// 普通函数调用如果未指定模块自动补全当前模块名
case IdentifierNode id -> { case IdentifierNode id -> {
String current = ctx.getFunction().name(); String current = ctx.getFunction().name();
int dot = current.lastIndexOf('.'); int dot = current.lastIndexOf('.');
if (dot > 0) { if (dot > 0)
// 当前处于模块内函数Module.func补全为同模块下的全限定名 yield current.substring(0, dot) + "." + id.name(); // 同命名空间内调用
yield current.substring(0, dot) + "." + id.name(); yield id.name(); // 全局函数调用
} else {
// 顶层/脚本函数等不含模块前缀保持原样
yield id.name();
}
} }
// 其它情况暂不支持 // 其它类型不支持
default -> throw new IllegalStateException("不支持的调用目标: " + call.callee().getClass().getSimpleName()); default -> throw new IllegalStateException(
"不支持的调用目标: " + call.callee().getClass().getSimpleName());
}; };
// 为返回值分配新寄存器生成 Call 指令 // 3. 分配用于存放返回值的新寄存器生成 Call 指令
IRVirtualRegister dest = ctx.newRegister(); IRVirtualRegister dest = ctx.newRegister();
ctx.addInstruction(new CallInstruction(dest, callee, new ArrayList<>(argv))); ctx.addInstruction(new CallInstruction(dest, callee, new ArrayList<>(argv)));
return dest; return dest;
} }
/** /**
* 二元表达式构建结果存储到新寄存器 * 二元表达式构建结果存储到新寄存器
* <br> * <br>
@ -277,44 +395,54 @@ public record ExpressionBuilder(IRContext ctx) {
IRVirtualRegister b = build(bin.right()); IRVirtualRegister b = build(bin.right());
String op = bin.operator(); String op = bin.operator();
// 比较运算符==!=>< 需要生成条件跳转或布尔值寄存器 // 判断是否为比较运算符==!=><
if (ComparisonUtils.isComparisonOperator(op)) { if (ComparisonUtils.isComparisonOperator(op)) {
// 生成比较操作返回布尔值寄存器
return InstructionFactory.binOp( return InstructionFactory.binOp(
ctx, ctx,
// 通过比较工具获得合适的 IR 操作码 // 根据运算符和操作数类型获得合适的 IR 操作码
ComparisonUtils.cmpOp(ctx.getScope().getVarTypes(), op, bin.left(), bin.right()), ComparisonUtils.cmpOp(ctx.getScope().getVarTypes(), op, bin.left(), bin.right()),
a, b); a, b);
} }
// 其它算术/位运算 // 其它二元运算算术位运算等
IROpCode code = ExpressionUtils.resolveOpCode(op, bin.left(), bin.right()); IROpCode code = ExpressionUtils.resolveOpCode(op, bin.left(), bin.right());
if (code == null) throw new IllegalStateException("不支持的运算符: " + op); if (code == null)
throw new IllegalStateException("不支持的运算符: " + op);
// 生成二元操作指令
return InstructionFactory.binOp(ctx, code, a, b); return InstructionFactory.binOp(ctx, code, a, b);
} }
/** /**
* 二元表达式构建结果直接写入目标寄存器用于赋值左值等优化场景 * 二元表达式构建结果直接写入目标寄存器用于赋值左值等优化场景
* *
* @param bin 二元表达式节点 * @param bin 二元表达式节点
* @param dest 目标虚拟寄存器 * @param dest 目标虚拟寄存器
*/ */
private void buildBinaryInto(BinaryExpressionNode bin, IRVirtualRegister dest) { private void buildBinaryInto(BinaryExpressionNode bin, IRVirtualRegister dest) {
// 递归生成左右操作数的寄存器
IRVirtualRegister a = build(bin.left()); IRVirtualRegister a = build(bin.left());
IRVirtualRegister b = build(bin.right()); IRVirtualRegister b = build(bin.right());
String op = bin.operator(); String op = bin.operator();
// 处理比较运算符==!=><
if (ComparisonUtils.isComparisonOperator(op)) { if (ComparisonUtils.isComparisonOperator(op)) {
InstructionFactory.binOpInto( InstructionFactory.binOpInto(
ctx, ctx,
// 选择对应类型和符号的比较操作码
ComparisonUtils.cmpOp(ctx.getScope().getVarTypes(), op, bin.left(), bin.right()), ComparisonUtils.cmpOp(ctx.getScope().getVarTypes(), op, bin.left(), bin.right()),
a, b, dest); a, b, dest);
} else { } else {
// 算术或位运算符
IROpCode code = ExpressionUtils.resolveOpCode(op, bin.left(), bin.right()); IROpCode code = ExpressionUtils.resolveOpCode(op, bin.left(), bin.right());
if (code == null) throw new IllegalStateException("不支持的运算符: " + op); if (code == null)
throw new IllegalStateException("不支持的运算符: " + op);
// 生成二元操作指令写入目标寄存器
InstructionFactory.binOpInto(ctx, code, a, b, dest); InstructionFactory.binOpInto(ctx, code, a, b, dest);
} }
} }
/* ───────────────── 字面量辅助方法 ───────────────── */ /* ───────────────── 字面量辅助方法 ───────────────── */
/** /**
@ -324,8 +452,11 @@ public record ExpressionBuilder(IRContext ctx) {
* @return 存储该字面量的寄存器 * @return 存储该字面量的寄存器
*/ */
private IRVirtualRegister buildNumberLiteral(String value) { private IRVirtualRegister buildNumberLiteral(String value) {
// 解析数字常量
IRConstant c = ExpressionUtils.buildNumberConstant(ctx, value); IRConstant c = ExpressionUtils.buildNumberConstant(ctx, value);
// 分配新寄存器
IRVirtualRegister r = ctx.newRegister(); IRVirtualRegister r = ctx.newRegister();
// 生成 LoadConst 指令
ctx.addInstruction(new LoadConstInstruction(r, c)); ctx.addInstruction(new LoadConstInstruction(r, c));
return r; return r;
} }
@ -337,8 +468,11 @@ public record ExpressionBuilder(IRContext ctx) {
* @return 存储该字符串的寄存器 * @return 存储该字符串的寄存器
*/ */
private IRVirtualRegister buildStringLiteral(String value) { private IRVirtualRegister buildStringLiteral(String value) {
// 构建字符串常量
IRConstant c = new IRConstant(value); IRConstant c = new IRConstant(value);
// 分配新寄存器
IRVirtualRegister r = ctx.newRegister(); IRVirtualRegister r = ctx.newRegister();
// 生成 LoadConst 指令
ctx.addInstruction(new LoadConstInstruction(r, c)); ctx.addInstruction(new LoadConstInstruction(r, c));
return r; return r;
} }
@ -350,8 +484,11 @@ public record ExpressionBuilder(IRContext ctx) {
* @return 存储 1/0 的寄存器 * @return 存储 1/0 的寄存器
*/ */
private IRVirtualRegister buildBoolLiteral(boolean v) { private IRVirtualRegister buildBoolLiteral(boolean v) {
// 转换为 1 0 的常量
IRConstant c = new IRConstant(v ? 1 : 0); IRConstant c = new IRConstant(v ? 1 : 0);
// 分配新寄存器
IRVirtualRegister r = ctx.newRegister(); IRVirtualRegister r = ctx.newRegister();
// 生成 LoadConst 指令
ctx.addInstruction(new LoadConstInstruction(r, c)); ctx.addInstruction(new LoadConstInstruction(r, c));
return r; return r;
} }
@ -363,33 +500,58 @@ public record ExpressionBuilder(IRContext ctx) {
* @return 存储该数组的寄存器 * @return 存储该数组的寄存器
*/ */
private IRVirtualRegister buildArrayLiteral(ArrayLiteralNode arr) { private IRVirtualRegister buildArrayLiteral(ArrayLiteralNode arr) {
// 递归生成支持嵌套的数组常量
IRConstant c = buildArrayConstant(arr); IRConstant c = buildArrayConstant(arr);
// 分配新寄存器
IRVirtualRegister r = ctx.newRegister(); IRVirtualRegister r = ctx.newRegister();
// 生成 LoadConst 指令
ctx.addInstruction(new LoadConstInstruction(r, c)); ctx.addInstruction(new LoadConstInstruction(r, c));
return r; return r;
} }
/** /**
* 构建数组常量所有元素均为数字字符串或布尔常量 * 构建支持嵌套的数组常量表达式
* <p>
* 遍历并递归处理数组字面量的所有元素
* <ul>
* <li>数字字面量根据内容生成 int double 常量</li>
* <li>字符串字面量直接存储字符串内容</li>
* <li>布尔字面量转换为 1true 0false存储</li>
* <li>数组字面量递归构建允许多层嵌套最终生成嵌套的 List</li>
* </ul>
* 若包含非常量元素则抛出异常
* </p>
* *
* @param arr 数组字面量节点 * @param arr 数组字面量节点
* @return 数组 IRConstant * @return 封装所有常量元素支持嵌套 List {@link IRConstant}
* @throws IllegalStateException 若含有非常量元素 * @throws IllegalStateException 如果数组中存在非常量元素
*/ */
private IRConstant buildArrayConstant(ArrayLiteralNode arr) { private IRConstant buildArrayConstant(ArrayLiteralNode arr) {
List<Object> list = new ArrayList<>(); List<Object> list = new ArrayList<>();
for (ExpressionNode e : arr.elements()) { for (ExpressionNode e : arr.elements()) {
switch (e) { switch (e) {
// 数字字面量解析并加入
case NumberLiteralNode n -> { case NumberLiteralNode n -> {
IRConstant num = ExpressionUtils.buildNumberConstant(ctx, n.value()); IRConstant num = ExpressionUtils.buildNumberConstant(ctx, n.value());
list.add(num.value()); list.add(num.value());
} }
// 字符串字面量直接加入
case StringLiteralNode s -> list.add(s.value()); case StringLiteralNode s -> list.add(s.value());
case BoolLiteralNode b -> list.add(b.getValue() ? 1 : 0); // 布尔字面量转成 1/0
case BoolLiteralNode b -> list.add(b.getValue() ? 1 : 0);
// 嵌套数组递归生成并加入
case ArrayLiteralNode inner -> {
IRConstant innerConst = buildArrayConstant(inner);
list.add(innerConst.value());
}
// 其它类型暂不支持
default -> throw new IllegalStateException( default -> throw new IllegalStateException(
"暂不支持含非常量元素的数组字面量: " + e.getClass().getSimpleName()); "暂不支持含非常量元素的数组字面量: " + e.getClass().getSimpleName());
} }
} }
// 返回不可变的 List 封装为 IRConstant
return new IRConstant(List.copyOf(list)); return new IRConstant(List.copyOf(list));
} }
} }

View File

@ -5,6 +5,10 @@ import org.jcnc.snow.vm.module.CallStack;
import org.jcnc.snow.vm.module.LocalVariableStore; import org.jcnc.snow.vm.module.LocalVariableStore;
import org.jcnc.snow.vm.module.OperandStack; import org.jcnc.snow.vm.module.OperandStack;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/** /**
* The {@code RPushCommand} class implements the {@link Command} interface * The {@code RPushCommand} class implements the {@link Command} interface
* and represents the "reference push" instruction ({@code R_PUSH}) in the virtual machine. * and represents the "reference push" instruction ({@code R_PUSH}) in the virtual machine.
@ -14,75 +18,34 @@ import org.jcnc.snow.vm.module.OperandStack;
* </p> * </p>
* *
* <p><b>Instruction format:</b> {@code R_PUSH <literal>}</p> * <p><b>Instruction format:</b> {@code R_PUSH <literal>}</p>
* <ul>
* <li>{@code <literal>}: The reference value (e.g., string, boolean, integer, floating-point, or array literal)
* to be pushed onto the stack. If the literal contains spaces, all arguments after {@code R_PUSH} are joined with spaces.</li>
* </ul>
*
* <p><b>Behavior:</b></p>
* <ul>
* <li>Ensures that at least one parameter is provided after the operator; otherwise, throws {@code IllegalStateException}.</li>
* <li>Concatenates all parameters after {@code R_PUSH} into a single string, separated by spaces.</li>
* <li>If the resulting string is an array literal (i.e., surrounded by square brackets), splits and parses its elements using {@link #getObject(String)} for primitive type support.</li>
* <li>Otherwise, pushes the literal as a string reference onto the operand stack.</li>
* <li>Increments the program counter to advance to the next instruction.</li>
* </ul>
* *
* <p> * <p>
* Supported element types in array literals include integers, floating-point numbers, booleans, * Example usages:
* and quoted strings (surrounded by double quotes). * <ul>
* <li>{@code R_PUSH "hello"} &rarr; push the string {@code "hello"} onto stack</li>
* <li>{@code R_PUSH [1,2,3]} &rarr; push an (unmodifiable) {@code List<Integer>} onto stack</li>
* <li>{@code R_PUSH [[1,2,3],[4,5,6]]} &rarr; push a nested (unmodifiable) {@code List<List<Integer>>} onto stack</li>
* </ul>
* </p>
*
* <p>
* Supported element types in array literals include integers, floating-point numbers (parsed as {@code Double}),
* booleans ({@code true}/{@code false} {@code 1}/{@code 0}), quoted strings (surrounded by double quotes),
* and further nested arrays.
* </p> * </p>
*/ */
public final class RPushCommand implements Command { public final class RPushCommand implements Command {
/** // ======== Parsing helpers ========
* Parses a string element into its corresponding Java object.
* <ul> private static final class Cursor {
* <li>If enclosed in double quotes, treats as a string literal (quotes are removed).</li> final String s;
* <li>If "true" or "false" (case-insensitive), returns 1 or 0 respectively (as integer representation).</li> int i;
* <li>If numeric (integer or floating-point), parses accordingly.</li> Cursor(String s) { this.s = s; this.i = 0; }
* <li>Otherwise, returns the string as-is.</li> boolean end() { return i >= s.length(); }
* </ul> char ch() { return s.charAt(i); }
*
* @param e The string to parse.
* @return The parsed object (String, Integer, Double, or Integer for boolean).
*/
private static Object getObject(String e) {
String x = e.trim();
Object v;
if (x.startsWith("\"") && x.endsWith("\"") && x.length() >= 2) {
// String literal (remove surrounding double quotes)
v = x.substring(1, x.length() - 1);
} else if ("true".equalsIgnoreCase(x) || "false".equalsIgnoreCase(x)) {
// Boolean value: true 1, false 0
v = Boolean.parseBoolean(x) ? 1 : 0;
} else {
try {
// Attempt to parse as floating-point or integer number
if (x.contains(".") || x.contains("e") || x.contains("E")) {
v = Double.parseDouble(x);
} else {
v = Integer.parseInt(x);
}
} catch (NumberFormatException ex) {
// Fallback: treat as plain string
v = x;
}
}
return v;
} }
/**
* Executes the {@code R_PUSH} instruction: pushes a reference value onto the operand stack.
*
* @param parts The instruction split into its components.
* @param pc The current program counter.
* @param stack The operand stack.
* @param lvs The local variable store (unused).
* @param cs The call stack (unused).
* @return The next program counter value.
* @throws IllegalStateException If no parameter is supplied after {@code R_PUSH}.
*/
@Override @Override
public int execute(String[] parts, int pc, public int execute(String[] parts, int pc,
OperandStack stack, OperandStack stack,
@ -102,22 +65,135 @@ public final class RPushCommand implements Command {
// If the literal is an array (e.g., [1, 2, "foo"]), parse elements and push as an unmodifiable list. // If the literal is an array (e.g., [1, 2, "foo"]), parse elements and push as an unmodifiable list.
if (literal.startsWith("[") && literal.endsWith("]")) { if (literal.startsWith("[") && literal.endsWith("]")) {
String inside = literal.substring(1, literal.length() - 1).trim(); Object parsed = parseValue(new Cursor(literal));
java.util.List<Object> list = new java.util.ArrayList<>(); if (!(parsed instanceof List<?> list)) {
if (!inside.isEmpty()) { // Should never happen for a bracketed value, but keep a guard.
// Split by comma, support element parsing (numbers, booleans, quoted strings) stack.push(parsed);
String[] elems = inside.split(","); } else {
for (String e : elems) { stack.push(deepUnmodifiable(list));
Object v = getObject(e);
list.add(v);
}
} }
// Push as an unmodifiable list to prevent further modifications.
stack.push(java.util.Collections.unmodifiableList(list));
} else { } else {
// Otherwise, push the string literal as-is. // Otherwise, push the string literal as-is.
stack.push(literal); stack.push(literal);
} }
return pc + 1; return pc + 1;
} }
/** Deeply wrap lists as unmodifiable; leave scalars intact. */
private static Object deepUnmodifiableObject(Object v) {
if (v instanceof List<?> l) {
return deepUnmodifiable(l);
}
return v;
}
private static List<?> deepUnmodifiable(List<?> l) {
List<Object> out = new ArrayList<>(l.size());
for (Object v : l) out.add(deepUnmodifiableObject(v));
return Collections.unmodifiableList(out);
}
// ======== Recursive-descent parser for array literals ========
private static 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);
}
private static List<Object> parseArray(Cursor c) {
// assumes current char is '['
expect(c, '[');
skipWs(c);
List<Object> values = new ArrayList<>();
if (!peek(c, ']')) {
while (true) {
Object v = parseValue(c);
values.add(v);
skipWs(c);
if (peek(c, ',')) {
c.i++; // consume ','
skipWs(c);
continue;
}
break;
}
}
expect(c, ']');
return values;
}
private static String parseQuoted(Cursor c) {
// assumes current char is '"'
expect(c, '\"');
StringBuilder sb = new StringBuilder();
while (!c.end()) {
char ch = c.ch();
c.i++;
if (ch == '\\') { // escape
if (c.end()) break;
char nxt = c.ch();
c.i++;
switch (nxt) {
case 'n' -> sb.append('\n');
case 'r' -> sb.append('\r');
case 't' -> sb.append('\t');
case '\"' -> sb.append('\"');
case '\\' -> sb.append('\\');
default -> sb.append(nxt);
}
} else if (ch == '\"') {
// end quote
return sb.toString();
} else {
sb.append(ch);
}
}
// Unclosed string: return what we have
return sb.toString();
}
private static Object parseAtom(Cursor c) {
int start = c.i;
while (!c.end()) {
char ch = c.ch();
if (ch == ',' || ch == ']' ) break;
if (Character.isWhitespace(ch)) break;
c.i++;
}
String token = c.s.substring(start, c.i).trim();
if (token.isEmpty()) return "";
// booleans
if ("true".equalsIgnoreCase(token)) return 1;
if ("false".equalsIgnoreCase(token)) return 0;
// number (int or double)
try {
if (token.contains(".") || token.contains("e") || token.contains("E")) {
return Double.parseDouble(token);
} else {
return Integer.parseInt(token);
}
} catch (NumberFormatException ex) {
// fallback: raw string
return token;
}
}
private static void skipWs(Cursor c) {
while (!c.end() && Character.isWhitespace(c.ch())) c.i++;
}
private static boolean peek(Cursor c, char ch) {
return !c.end() && c.ch() == ch;
}
private static void expect(Cursor c, char ch) {
if (c.end() || c.ch() != ch)
throw new IllegalArgumentException("R_PUSH array literal parse error: expected '" + ch + "' at position " + c.i);
c.i++; // consume
skipWs(c);
}
} }