Compare commits

...

7 Commits

Author SHA1 Message Date
zhangxun
6d065bf3cb test: restore Demo22 2025-08-06 14:20:07 +08:00
zhangxun
538005b7dc test: 增加 Demo22(函数重载) 2025-08-06 09:47:54 +08:00
zhangxun
7dca18b6f3 style: 移除冗余分号 2025-08-06 01:16:56 +08:00
zhangxun
50cf0abf80 docs: 修改注释 2025-08-06 01:15:31 +08:00
zhangxun
6ea8f88b0a feat: 初步支持函数重载 2025-08-06 01:13:17 +08:00
zhangxun
6b56e65bce docs: 移除废弃的后缀 i、d 2025-08-06 01:04:19 +08:00
zhangxun
92bd94a563 feat: IR函数参数增加类型显示 2025-08-06 01:00:45 +08:00
13 changed files with 299 additions and 39 deletions

10
.run/Demo22.run.xml Normal file
View File

@ -0,0 +1,10 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Demo22" type="Application" factoryName="Application" folderName="Demo">
<option name="MAIN_CLASS_NAME" value="org.jcnc.snow.cli.SnowCLI" />
<module name="Snow" />
<option name="PROGRAM_PARAMETERS" value="compile run -d playground/Demo/Demo22 -o target/Demo22 --debug" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>

View File

@ -0,0 +1,46 @@
module: Main
import: os
function: main
params:
returns: int
body:
declare x: int = 0
x = inc(x)
println(x)
x = inc(x, 7)
println(x)
return 0
end body
end function
function: inc
params:
declare num: int
returns: int
body:
return num + 1
end body
end function
function: inc
params:
declare num: int
declare v: int
returns: int
body:
return num + v
end body
end function
function: println
params:
declare i1: int
returns: void
body:
os.syscall("PRINTLN",i1)
end body
end function
end module

View File

@ -72,7 +72,8 @@ public class CallGenerator implements InstructionGenerator<CallInstruction> {
String fn = ins.getFunctionName(); String fn = ins.getFunctionName();
// 特殊处理 syscall 调用 // 特殊处理 syscall 调用
if ("syscall".equals(fn) || fn.endsWith(".syscall")) { String tname = fn.substring(0, fn.lastIndexOf(':'));
if ("syscall".equals(tname) || tname.endsWith(".syscall")) {
generateSyscall(ins, out, slotMap, fn); generateSyscall(ins, out, slotMap, fn);
return; return;
} }

View File

@ -14,6 +14,9 @@ import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.StringJoiner;
import static org.jcnc.snow.compiler.ir.utils.ExpressionUtils.looksLikeFloat;
/** /**
* {@code ExpressionBuilder} 表达式 IR 构建器 * {@code ExpressionBuilder} 表达式 IR 构建器
@ -377,24 +380,73 @@ public record ExpressionBuilder(IRContext ctx) {
// 1. 递归生成所有参数的寄存器 // 1. 递归生成所有参数的寄存器
List<IRVirtualRegister> argv = call.arguments().stream().map(this::build).toList(); List<IRVirtualRegister> argv = call.arguments().stream().map(this::build).toList();
// 2. 规范化被调用方法名区分成员方法与普通函数 // 2. 生成参数列表描述类型_类型这种格式
StringJoiner sj = new StringJoiner("_");
for (ExpressionNode param : call.arguments()) {
switch (param) {
case NumberLiteralNode n -> {
String value = n.value();
char suffix = value.isEmpty() ? '\0'
: Character.toLowerCase(value.charAt(value.length() - 1));
switch (suffix) {
case 'b' -> sj.add("byte");
case 's' -> sj.add("short");
case 'l' -> sj.add("long");
case 'f' -> sj.add("float");
case 'd' -> sj.add("double");
default -> {
if (looksLikeFloat(value)) {
sj.add("double");
} else {
sj.add("int");
}
}
}
}
case BoolLiteralNode _ -> sj.add("bool");
case StringLiteralNode _ -> sj.add("string");
case IdentifierNode id -> {
String type = ctx.getScope().lookupType(id.name());
sj.add(type);
}
// case CallExpressionNode ce -> {
// }
case null, default -> throw new IllegalArgumentException("(内部错误) 不支持的参数表达式: " + param);
}
}
// 3. 规范化被调用方法名区分成员方法与普通函数
String callee = switch (call.callee()) { String callee = switch (call.callee()) {
// 成员方法调用 obj.method() // 成员方法调用 obj.method()
case MemberExpressionNode m when m.object() instanceof IdentifierNode id -> id.name() + "." + m.member(); case MemberExpressionNode m when m.object() instanceof IdentifierNode id -> {
String qualifiedName = id.name() + "." + m.member();
if (sj.length() > 0) {
qualifiedName = qualifiedName + ":" + sj;
}
yield qualifiedName;
}
// 普通函数调用或处理命名空间前缀如当前方法名为 namespace.func // 普通函数调用或处理命名空间前缀如当前方法名为 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)
yield current.substring(0, dot) + "." + id.name(); // 同命名空间内调用 String qualifiedName = dot > 0
yield id.name(); // 全局函数调用 ? current.substring(0, dot) + "." + id.name()
: id.name();
if (sj.length() > 0) {
qualifiedName = qualifiedName + ":" + sj;
}
yield qualifiedName; // 全局函数调用
} }
// 其它类型不支持 // 其它类型不支持
default -> throw new IllegalStateException( default -> throw new IllegalStateException(
"不支持的调用目标: " + call.callee().getClass().getSimpleName()); "不支持的调用目标: " + call.callee().getClass().getSimpleName());
}; };
// 3. 分配用于存放返回值的新寄存器并生成 Call 指令 // 4. 分配用于存放返回值的新寄存器并生成 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;

View File

@ -57,7 +57,7 @@ public class FunctionBuilder {
for (ParameterNode p : functionNode.parameters()) { for (ParameterNode p : functionNode.parameters()) {
IRVirtualRegister reg = irFunction.newRegister(); // 新寄存器 IRVirtualRegister reg = irFunction.newRegister(); // 新寄存器
irContext.getScope().declare(p.name(), p.type(), reg); // 变量名寄存器绑定 irContext.getScope().declare(p.name(), p.type(), reg); // 变量名寄存器绑定
irFunction.addParameter(reg); // 添加到函数参数列表 irFunction.addParameter(reg, p.type()); // 添加到函数参数列表
} }
// 3) 生成函数体 IR: 遍历每条语句逐一转化 // 3) 生成函数体 IR: 遍历每条语句逐一转化

View File

@ -4,12 +4,14 @@ import org.jcnc.snow.compiler.ir.core.IRFunction;
import org.jcnc.snow.compiler.ir.core.IRProgram; import org.jcnc.snow.compiler.ir.core.IRProgram;
import org.jcnc.snow.compiler.parser.ast.FunctionNode; import org.jcnc.snow.compiler.parser.ast.FunctionNode;
import org.jcnc.snow.compiler.parser.ast.ModuleNode; import org.jcnc.snow.compiler.parser.ast.ModuleNode;
import org.jcnc.snow.compiler.parser.ast.ParameterNode;
import org.jcnc.snow.compiler.parser.ast.base.Node; import org.jcnc.snow.compiler.parser.ast.base.Node;
import org.jcnc.snow.compiler.parser.ast.base.NodeContext; import org.jcnc.snow.compiler.parser.ast.base.NodeContext;
import org.jcnc.snow.compiler.parser.ast.base.StatementNode; import org.jcnc.snow.compiler.parser.ast.base.StatementNode;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.StringJoiner;
/** /**
* IRProgramBuilder 负责将 AST 根节点(如模块函数顶层语句)转换为可执行的 IRProgram 实例 * IRProgramBuilder 负责将 AST 根节点(如模块函数顶层语句)转换为可执行的 IRProgram 实例
@ -66,6 +68,15 @@ public final class IRProgramBuilder {
private IRFunction buildFunctionWithGlobals(ModuleNode moduleNode, FunctionNode functionNode) { private IRFunction buildFunctionWithGlobals(ModuleNode moduleNode, FunctionNode functionNode) {
// 拼接模块名和函数名生成全限定名 // 拼接模块名和函数名生成全限定名
String qualifiedName = moduleNode.name() + "." + functionNode.name(); String qualifiedName = moduleNode.name() + "." + functionNode.name();
StringJoiner sj = new StringJoiner("_");
for (ParameterNode param : functionNode.parameters()) {
sj.add(param.type());
}
if (sj.length() > 0) {
qualifiedName = qualifiedName + ":" + sj;
}
// 若无全局声明仅重命名后直接构建 // 若无全局声明仅重命名后直接构建
if (moduleNode.globals() == null || moduleNode.globals().isEmpty()) { if (moduleNode.globals() == null || moduleNode.globals().isEmpty()) {
return buildFunction(renameFunction(functionNode, qualifiedName)); return buildFunction(renameFunction(functionNode, qualifiedName));

View File

@ -35,6 +35,11 @@ public class IRFunction {
*/ */
private final List<IRVirtualRegister> parameters = new ArrayList<>(); private final List<IRVirtualRegister> parameters = new ArrayList<>();
/**
* 正式参数所对应的类型按声明顺序排列
*/
private final List<String> parametersType = new ArrayList<>();
/** /**
* 构造一个具有指定名称的 IRFunction 实例 * 构造一个具有指定名称的 IRFunction 实例
* *
@ -61,13 +66,15 @@ public class IRFunction {
* </p> * </p>
* *
* @param vr 表示函数某个参数的虚拟寄存器 * @param vr 表示函数某个参数的虚拟寄存器
* @param type 表示函数某个参数的类型
*/ */
public void addParameter(IRVirtualRegister vr) { public void addParameter(IRVirtualRegister vr, String type) {
parameters.add(vr); parameters.add(vr);
parametersType.add(type);
} }
/** /**
* 获取函数正式参数的只读列表 * 获取函数正式参数的虚拟寄存器只读列表
* *
* @return 按声明顺序排列的虚拟寄存器列表 * @return 按声明顺序排列的虚拟寄存器列表
*/ */
@ -75,6 +82,15 @@ public class IRFunction {
return List.copyOf(parameters); return List.copyOf(parameters);
} }
/**
* 获取函数正式参数的类型只读列表
*
* @return 按声明顺序排列的类型列表
*/
public List<String> parametersType() {
return List.copyOf(parametersType);
}
/** /**
* 向函数体末尾追加一条 IR 指令 * 向函数体末尾追加一条 IR 指令
* *
@ -130,6 +146,7 @@ public class IRFunction {
.append('('); .append('(');
for (int i = 0; i < parameters.size(); i++) { for (int i = 0; i < parameters.size(); i++) {
sb.append(parameters.get(i)); sb.append(parameters.get(i));
sb.append(": ").append(parametersType.get(i));
if (i < parameters.size() - 1) { if (i < parameters.size() - 1) {
sb.append(", "); sb.append(", ");
} }

View File

@ -35,7 +35,7 @@ public final class ExpressionUtils {
/** /**
* 设置当前线程的默认类型后缀 * 设置当前线程的默认类型后缀
* *
* @param suffix 类型后缀字符b/s/i/l/f/d'\0'表示无 * @param suffix 类型后缀字符b/s/l/f'\0'表示无
*/ */
public static void setDefaultSuffix(char suffix) { DEFAULT_SUFFIX.set(suffix); } public static void setDefaultSuffix(char suffix) { DEFAULT_SUFFIX.set(suffix); }
@ -47,21 +47,21 @@ public final class ExpressionUtils {
// 字面量常量解析 // 字面量常量解析
/** /**
* 安全解析整数字面量字符串自动去除单字符类型后缀b/s/l/f/d大小写均可并转换为 int * 安全解析整数字面量字符串自动去除单字符类型后缀b/s/l/f大小写均可并转换为 int
* *
* @param literal 字面量字符串 * @param literal 字面量字符串
* @return 字面量对应的 int 数值 * @return 字面量对应的 int 数值
* @throws NumberFormatException 如果字面量无法转换为整数 * @throws NumberFormatException 如果字面量无法转换为整数
*/ */
public static int parseIntSafely(String literal) { public static int parseIntSafely(String literal) {
String digits = literal.replaceAll("[bslfdBSDLF]$", ""); String digits = literal.replaceAll("[bslfBSLF]$", "");
return Integer.parseInt(digits); return Integer.parseInt(digits);
} }
/** /**
* 根据数字字面量字符串推断类型并生成对应的 IRConstant 常量值 * 根据数字字面量字符串推断类型并生成对应的 IRConstant 常量值
* <p> * <p>
* 支持的字面量后缀有 b/s/l/f/d大小写均可 * 支持的字面量后缀有 b/s/l/f大小写均可
* 无后缀时优先参考 IRContext 当前变量类型否则根据字面量格式'.''e'判断为 double否则为 int * 无后缀时优先参考 IRContext 当前变量类型否则根据字面量格式'.''e'判断为 double否则为 int
* *
* @param ctx IRContext允许参考变量声明类型 * @param ctx IRContext允许参考变量声明类型
@ -73,7 +73,7 @@ public final class ExpressionUtils {
: Character.toLowerCase(value.charAt(value.length() - 1)); : Character.toLowerCase(value.charAt(value.length() - 1));
String digits = switch (suffix) { String digits = switch (suffix) {
case 'b','s','l','f','d' -> value.substring(0, value.length() - 1); case 'b','s','l','f' -> value.substring(0, value.length() - 1);
default -> { default -> {
// 无后缀优先参考变量类型 // 无后缀优先参考变量类型
if (ctx.getVarType() != null) { if (ctx.getVarType() != null) {
@ -249,7 +249,7 @@ public final class ExpressionUtils {
* @param digits 字面量字符串 * @param digits 字面量字符串
* @return 是浮点格式则返回 true * @return 是浮点格式则返回 true
*/ */
private static boolean looksLikeFloat(String digits) { public static boolean looksLikeFloat(String digits) {
return digits.indexOf('.') >= 0 return digits.indexOf('.') >= 0
|| digits.indexOf('e') >= 0 || digits.indexOf('e') >= 0
|| digits.indexOf('E') >= 0; || digits.indexOf('E') >= 0;

View File

@ -77,8 +77,15 @@ public class CallExpressionAnalyzer implements ExpressionAnalyzer<CallExpression
return BuiltinType.INT; return BuiltinType.INT;
} }
// 分析所有实参并获取类型
List<Type> args = new ArrayList<>();
for (ExpressionNode arg : call.arguments()) {
args.add(ctx.getRegistry().getExpressionAnalyzer(arg)
.analyze(ctx, mi, fn, locals, arg));
}
// 查找目标函数签名先在当前模块/显式模块查找 // 查找目标函数签名先在当前模块/显式模块查找
FunctionType ft = target.getFunctions().get(functionName); FunctionType ft = target.retrieveFunction(functionName, args);
// 未找到则报错 // 未找到则报错
if (ft == null) { if (ft == null) {
@ -88,13 +95,6 @@ public class CallExpressionAnalyzer implements ExpressionAnalyzer<CallExpression
return BuiltinType.INT; return BuiltinType.INT;
} }
// 分析所有实参并获取类型
List<Type> args = new ArrayList<>();
for (ExpressionNode arg : call.arguments()) {
args.add(ctx.getRegistry().getExpressionAnalyzer(arg)
.analyze(ctx, mi, fn, locals, arg));
}
// 参数数量检查 // 参数数量检查
if (args.size() != ft.paramTypes().size()) { if (args.size() != ft.paramTypes().size()) {
ctx.getErrors().add(new SemanticError(call, ctx.getErrors().add(new SemanticError(call,

View File

@ -1,6 +1,7 @@
package org.jcnc.snow.compiler.semantic.analyzers.statement; package org.jcnc.snow.compiler.semantic.analyzers.statement;
import org.jcnc.snow.compiler.parser.ast.FunctionNode; import org.jcnc.snow.compiler.parser.ast.FunctionNode;
import org.jcnc.snow.compiler.parser.ast.ParameterNode;
import org.jcnc.snow.compiler.parser.ast.ReturnNode; import org.jcnc.snow.compiler.parser.ast.ReturnNode;
import org.jcnc.snow.compiler.semantic.analyzers.base.StatementAnalyzer; import org.jcnc.snow.compiler.semantic.analyzers.base.StatementAnalyzer;
import org.jcnc.snow.compiler.semantic.core.Context; import org.jcnc.snow.compiler.semantic.core.Context;
@ -11,6 +12,9 @@ import org.jcnc.snow.compiler.semantic.type.BuiltinType;
import org.jcnc.snow.compiler.semantic.type.FunctionType; import org.jcnc.snow.compiler.semantic.type.FunctionType;
import org.jcnc.snow.compiler.semantic.type.Type; import org.jcnc.snow.compiler.semantic.type.Type;
import java.util.ArrayList;
import java.util.List;
/** /**
* {@code ReturnAnalyzer} 是用于分析 {@link ReturnNode} 返回语句的语义分析器 * {@code ReturnAnalyzer} 是用于分析 {@link ReturnNode} 返回语句的语义分析器
* <p> * <p>
@ -42,12 +46,32 @@ public class ReturnAnalyzer implements StatementAnalyzer<ReturnNode> {
ctx.log("检查 return"); ctx.log("检查 return");
// 获取当前函数的定义信息 // 获取当前函数的重载列表
FunctionType expected = ctx.getModules() var overloading = ctx.getModules()
.get(mi.getName()) .get(mi.getName())
.getFunctions() .getFunctions()
.get(fn.name()); .get(fn.name());
List<Type> params = new ArrayList<>();
for (ParameterNode pn : fn.parameters()) {
params.add(locals.resolve(pn.name()).type());
}
// fn 对应的函数签名
FunctionType expected = overloading.stream()
.filter(ft -> ft.paramTypes().equals(params))
.findFirst()
.orElse(null);
if (expected == null) {
ctx.getErrors().add(new SemanticError(
fn,
"不存在的函数签名: " + params
));
ctx.log("不存在的函数签名: " + params);
return;
}
// 情况 1: 存在返回表达式需进行类型检查 // 情况 1: 存在返回表达式需进行类型检查
ret.getExpression().ifPresentOrElse(exp -> { ret.getExpression().ifPresentOrElse(exp -> {
var exprAnalyzer = ctx.getRegistry().getExpressionAnalyzer(exp); var exprAnalyzer = ctx.getRegistry().getExpressionAnalyzer(exp);

View File

@ -62,14 +62,54 @@ public final class BuiltinTypeRegistry {
/* ---------- 注册标准库 os ---------- */ /* ---------- 注册标准库 os ---------- */
ModuleInfo utils = new ModuleInfo("os"); ModuleInfo utils = new ModuleInfo("os");
// syscall(string, int): void 供标准库内部使用的调用接口 /* syscall(string, type): void 的一组重载 */
utils.getFunctions().put( List<FunctionType> overloading = new ArrayList<>();
"syscall", {
new FunctionType( // syscall(string, byte): void
overloading.add(new FunctionType(
Arrays.asList(BuiltinType.STRING, BuiltinType.BYTE),
BuiltinType.VOID
));
// syscall(string, short): void
overloading.add(new FunctionType(
Arrays.asList(BuiltinType.STRING, BuiltinType.SHORT),
BuiltinType.VOID
));
// syscall(string, int): void
overloading.add(new FunctionType(
Arrays.asList(BuiltinType.STRING, BuiltinType.INT), Arrays.asList(BuiltinType.STRING, BuiltinType.INT),
BuiltinType.VOID BuiltinType.VOID
) ));
);
// syscall(string, long): void
overloading.add(new FunctionType(
Arrays.asList(BuiltinType.STRING, BuiltinType.LONG),
BuiltinType.VOID
));
// syscall(string, float): void
overloading.add(new FunctionType(
Arrays.asList(BuiltinType.STRING, BuiltinType.FLOAT),
BuiltinType.VOID
));
// syscall(string, double): void
overloading.add(new FunctionType(
Arrays.asList(BuiltinType.STRING, BuiltinType.DOUBLE),
BuiltinType.VOID
));
// syscall(string, boolean): void
overloading.add(new FunctionType(
Arrays.asList(BuiltinType.STRING, BuiltinType.BOOLEAN),
BuiltinType.VOID
));
}
// syscall(string, `type`): void 供标准库内部使用的调用接口
utils.getFunctions().put("syscall", overloading);
// 注册 BuiltinUtils 到上下文的模块表若已存在则不重复添加 // 注册 BuiltinUtils 到上下文的模块表若已存在则不重复添加
ctx.getModules().putIfAbsent("os", utils); ctx.getModules().putIfAbsent("os", utils);

View File

@ -1,6 +1,7 @@
package org.jcnc.snow.compiler.semantic.core; package org.jcnc.snow.compiler.semantic.core;
import org.jcnc.snow.compiler.semantic.type.FunctionType; import org.jcnc.snow.compiler.semantic.type.FunctionType;
import org.jcnc.snow.compiler.semantic.type.Type;
import java.util.*; import java.util.*;
@ -25,8 +26,8 @@ public class ModuleInfo {
/** 该模块显式导入的模块名集合(用于跨模块访问符号) */ /** 该模块显式导入的模块名集合(用于跨模块访问符号) */
private final Set<String> imports = new HashSet<>(); private final Set<String> imports = new HashSet<>();
/** 该模块中定义的函数名 → 函数类型映射 */ /** 该模块中定义的函数名 → 函数类型列表映射 */
private final Map<String, FunctionType> functions = new HashMap<>(); private final Map<String, List<FunctionType>> functions = new HashMap<>();
/** /**
* 构造模块信息对象 * 构造模块信息对象
@ -65,8 +66,57 @@ public class ModuleInfo {
* *
* @return 模块内函数定义映射表 * @return 模块内函数定义映射表
*/ */
public Map<String, FunctionType> getFunctions() { public Map<String, List<FunctionType>> getFunctions() {
return functions; return functions;
} }
/**
* 添加一个新的函数类型
*
* @param name 函数名
* @param ft 函数类型
*/
public void addFunction(String name, FunctionType ft) {
if (!functions.containsKey(name)) {
functions.put(name, new ArrayList<>());
}
functions.get(name).add(ft);
}
/**
* 判断函数类型是否存在
*
* @param name 函数名
* @param ft 函数类型
* @return 函数类型存在则返回 true否则 false
*/
public boolean existsFunction(String name, FunctionType ft) {
if (!functions.containsKey(name)) {
return false;
}
return functions.get(name).stream().anyMatch((t) -> t.equals(ft));
}
/**
* 检索函数类型
* 通过函数名和参数列表唯一确定一个函数类型
*
* @param name 函数名
* @param params 参数列表
* @return 唯一确定的函数类型不存在则返回 null
*/
public FunctionType retrieveFunction(String name, List<Type> params) {
List<FunctionType> fts = functions.get(name);
if (fts != null) {
for (FunctionType ft : fts) {
if (ft.paramTypes().equals(params)) {
return ft;
}
}
}
return null;
}
} }

View File

@ -78,8 +78,17 @@ public record SignatureRegistrar(Context ctx) {
Type ret = Optional.ofNullable(ctx.parseType(fn.returnType())) Type ret = Optional.ofNullable(ctx.parseType(fn.returnType()))
.orElse(BuiltinType.VOID); .orElse(BuiltinType.VOID);
FunctionType ft = new FunctionType(params, ret);
if (mi.existsFunction(fn.name(), ft)) {
ctx.errors().add(new SemanticError(
fn,
"有歧义的函数: " + fn.name()
));
}
else {
// 注册函数签名 // 注册函数签名
mi.getFunctions().put(fn.name(), new FunctionType(params, ret)); mi.addFunction(fn.name(), ft);
}
} }
} }
} }