完善注释

This commit is contained in:
Luke 2025-04-27 16:57:27 +08:00
parent 55ae077ae1
commit 54c4914400

View File

@ -6,34 +6,56 @@ import org.jcnc.snow.compiler.parser.ast.base.StatementNode;
import java.util.*; import java.util.*;
/**
* 语义分析器
* <p>
* 负责对整个模块列表进行静态语义检查
* 包括模块导入函数定义变量使用表达式类型推导等
* 分析过程中收集所有发现的语义错误并最终返回错误列表
*/
public class SemanticAnalyzer { public class SemanticAnalyzer {
/** 所有模块信息(包括内置模块和用户模块) */
private final Map<String, ModuleInfo> modules = new HashMap<>(); private final Map<String, ModuleInfo> modules = new HashMap<>();
/** 语义错误列表 */
private final List<SemanticError> errors = new ArrayList<>(); private final List<SemanticError> errors = new ArrayList<>();
/** 是否启用详细日志打印 */
private final boolean verbose; private final boolean verbose;
/** 内置类型映射表 */
private static final Map<String, Type> BUILTIN_TYPES = Map.of( private static final Map<String, Type> BUILTIN_TYPES = Map.of(
"int", BuiltinType.INT, "int", BuiltinType.INT,
"string", BuiltinType.STRING, "string", BuiltinType.STRING,
"void", BuiltinType.VOID "void", BuiltinType.VOID
); );
// 默认关闭详细日志 /**
* 默认构造关闭详细日志
*/
public SemanticAnalyzer() { public SemanticAnalyzer() {
this(false); this(false);
} }
/** /**
* @param verbose 是否开启详细日志打印 * 构造函数
*
* @param verbose 是否启用详细日志
*/ */
public SemanticAnalyzer(boolean verbose) { public SemanticAnalyzer(boolean verbose) {
this.verbose = verbose; this.verbose = verbose;
} }
/** 打印日志,仅在 verbose 模式下输出。 */
private void log(String msg) { private void log(String msg) {
if (verbose) { if (verbose) {
System.out.println("[SemanticAnalyzer] " + msg); System.out.println("[SemanticAnalyzer] " + msg);
} }
} }
/**
* 主分析入口
*
* @param moduleNodes 所有待分析的模块节点
* @return 检查过程中发现的所有语义错误
*/
public List<SemanticError> analyze(List<ModuleNode> moduleNodes) { public List<SemanticError> analyze(List<ModuleNode> moduleNodes) {
log("开始语义分析"); log("开始语义分析");
initBuiltinModule(); initBuiltinModule();
@ -47,6 +69,7 @@ public class SemanticAnalyzer {
return errors; return errors;
} }
/** 初始化内置模块及其内置函数。 */
private void initBuiltinModule() { private void initBuiltinModule() {
ModuleInfo builtin = new ModuleInfo("BuiltinUtils"); ModuleInfo builtin = new ModuleInfo("BuiltinUtils");
builtin.getFunctions().put("to_int", new FunctionType(List.of(BuiltinType.STRING), BuiltinType.INT)); builtin.getFunctions().put("to_int", new FunctionType(List.of(BuiltinType.STRING), BuiltinType.INT));
@ -56,6 +79,7 @@ public class SemanticAnalyzer {
log("内置函数 to_int, to_string, print 注册到模块 " + builtin.getName()); log("内置函数 to_int, to_string, print 注册到模块 " + builtin.getName());
} }
/** 注册所有用户模块到模块表。 */
private void registerUserModules(List<ModuleNode> mods) { private void registerUserModules(List<ModuleNode> mods) {
for (var mod : mods) { for (var mod : mods) {
modules.put(mod.name(), new ModuleInfo(mod.name())); modules.put(mod.name(), new ModuleInfo(mod.name()));
@ -63,9 +87,12 @@ public class SemanticAnalyzer {
} }
} }
/** 注册模块的导入信息和函数签名。 */
private void registerSignaturesAndImports(List<ModuleNode> mods) { private void registerSignaturesAndImports(List<ModuleNode> mods) {
for (var mod : mods) { for (var mod : mods) {
ModuleInfo mi = modules.get(mod.name()); ModuleInfo mi = modules.get(mod.name());
// 处理导入
for (var imp : mod.imports()) { for (var imp : mod.imports()) {
if (!modules.containsKey(imp.moduleName())) { if (!modules.containsKey(imp.moduleName())) {
errors.add(new SemanticError(imp, "未知模块: " + imp.moduleName())); errors.add(new SemanticError(imp, "未知模块: " + imp.moduleName()));
@ -75,6 +102,8 @@ public class SemanticAnalyzer {
log("模块 " + mod.name() + " 导入模块: " + imp.moduleName()); log("模块 " + mod.name() + " 导入模块: " + imp.moduleName());
} }
} }
// 处理函数定义
for (var fn : mod.functions()) { for (var fn : mod.functions()) {
List<Type> params = new ArrayList<>(); List<Type> params = new ArrayList<>();
for (var p : fn.parameters()) { for (var p : fn.parameters()) {
@ -82,38 +111,42 @@ public class SemanticAnalyzer {
if (t == null) { if (t == null) {
errors.add(new SemanticError(p, "未知类型: " + p.type())); errors.add(new SemanticError(p, "未知类型: " + p.type()));
log("错误: 参数未知类型 " + p.type() + " 在函数 " + fn.name()); log("错误: 参数未知类型 " + p.type() + " 在函数 " + fn.name());
t = BuiltinType.INT; t = BuiltinType.INT; // 默认降级为 int
} }
params.add(t); params.add(t);
} }
Type ret = parseType(fn.returnType()); Type ret = Optional.ofNullable(parseType(fn.returnType()))
if (ret == null) { .orElseGet(() -> {
errors.add(new SemanticError(fn, "未知返回类型: " + fn.returnType())); errors.add(new SemanticError(fn, "未知返回类型: " + fn.returnType()));
log("错误: 函数返回类型未知 " + fn.returnType() + " 在函数 " + fn.name()); log("错误: 函数返回类型未知 " + fn.returnType() + " 在函数 " + fn.name());
ret = BuiltinType.VOID; return BuiltinType.VOID; // 默认降级为 void
} });
mi.getFunctions().put(fn.name(), new FunctionType(params, ret)); mi.getFunctions().put(fn.name(), new FunctionType(params, ret));
log("注册函数: " + mod.name() + "." + fn.name() + " 参数类型: " + params + " 返回类型: " + ret); log("注册函数: " + mod.name() + "." + fn.name() + " 参数类型: " + params + " 返回类型: " + ret);
} }
} }
} }
/** 检查所有函数内部的语义正确性。 */
private void checkAllFunctions(List<ModuleNode> mods) { private void checkAllFunctions(List<ModuleNode> mods) {
for (var mod : mods) { for (var mod : mods) {
ModuleInfo mi = modules.get(mod.name()); ModuleInfo mi = modules.get(mod.name());
for (var fn : mod.functions()) { for (var fn : mod.functions()) {
log("开始检查函数: " + mod.name() + "." + fn.name()); log("开始检查函数: " + mod.name() + "." + fn.name());
SymbolTable locals = new SymbolTable(null); SymbolTable locals = new SymbolTable(null);
// 注册参数
for (var p : fn.parameters()) { for (var p : fn.parameters()) {
locals.define(new Symbol(p.name(), parseType(p.type()), SymbolKind.VARIABLE)); locals.define(new Symbol(p.name(), parseType(p.type()), SymbolKind.VARIABLE));
log("定义参数: " + p.name() + " 类型: " + p.type()); log("定义参数: " + p.name() + " 类型: " + p.type());
} }
// 检查函数体
fn.body().forEach(stmt -> checkStatement(mi, fn, locals, stmt)); fn.body().forEach(stmt -> checkStatement(mi, fn, locals, stmt));
log("完成函数检查: " + mod.name() + "." + fn.name()); log("完成函数检查: " + mod.name() + "." + fn.name());
} }
} }
} }
/** 检查单个语句。 */
private void checkStatement(ModuleInfo mi, FunctionNode fn, SymbolTable locals, StatementNode stmt) { private void checkStatement(ModuleInfo mi, FunctionNode fn, SymbolTable locals, StatementNode stmt) {
log("检查语句: " + stmt); log("检查语句: " + stmt);
switch (stmt) { switch (stmt) {
@ -130,24 +163,26 @@ public class SemanticAnalyzer {
} }
} }
/** 检查变量声明。 */
private void checkDeclaration(ModuleInfo mi, DeclarationNode decl, SymbolTable locals) { private void checkDeclaration(ModuleInfo mi, DeclarationNode decl, SymbolTable locals) {
Type varType = Optional.ofNullable(parseType(decl.getType())).orElse(BuiltinType.INT); Type varType = Optional.ofNullable(parseType(decl.getType())).orElse(BuiltinType.INT);
log("声明变量: " + decl.getName() + " 类型: " + decl.getType()); log("声明变量: " + decl.getName() + " 类型: " + decl.getType());
if (!locals.define(new Symbol(decl.getName(), varType, SymbolKind.VARIABLE))) { if (!locals.define(new Symbol(decl.getName(), varType, SymbolKind.VARIABLE))) {
errors.add(new SemanticError(decl, "变量重复声明: " + decl.getName())); errors.add(new SemanticError(decl, "变量重复声明: " + decl.getName()));
log("错误: 变量重复声明 " + decl.getName()); log("错误: 变量重复声明 " + decl.getName());
} }
decl.getInitializer().ifPresent(init -> { decl.getInitializer().ifPresent(init -> {
Type initType = checkExpression(mi, null, locals, init); Type initType = checkExpression(mi, null, locals, init);
if (!varType.isCompatible(initType)) { if (!varType.isCompatible(initType)) {
errors.add(new SemanticError(decl, "初始化类型不匹配: 期望 " + varType + ", 实际 " + initType)); errors.add(new SemanticError(decl, "初始化类型不匹配: 期望 " + varType + ", 实际 " + initType));
log("错误: 初始化类型不匹配 for " + decl.getName() + ": 期望 " + varType + ", 实际 " + initType); log("错误: 初始化类型不匹配 " + decl.getName());
} else {
log("初始化成功: " + decl.getName() + " 类型: " + initType);
} }
}); });
} }
/** 检查赋值语句。 */
private void checkAssignment(ModuleInfo mi, AssignmentNode asg, SymbolTable locals) { private void checkAssignment(ModuleInfo mi, AssignmentNode asg, SymbolTable locals) {
log("赋值检查: " + asg.variable()); log("赋值检查: " + asg.variable());
Symbol sym = locals.resolve(asg.variable()); Symbol sym = locals.resolve(asg.variable());
@ -159,39 +194,36 @@ public class SemanticAnalyzer {
Type valType = checkExpression(mi, null, locals, asg.value()); Type valType = checkExpression(mi, null, locals, asg.value());
if (!sym.type().isCompatible(valType)) { if (!sym.type().isCompatible(valType)) {
errors.add(new SemanticError(asg, "赋值类型不匹配: 期望 " + sym.type() + ", 实际 " + valType)); errors.add(new SemanticError(asg, "赋值类型不匹配: 期望 " + sym.type() + ", 实际 " + valType));
log("错误: 赋值类型不匹配 for " + asg.variable() + ": 期望 " + sym.type() + ", 实际 " + valType); log("错误: 赋值类型不匹配 " + asg.variable());
} else {
log("赋值成功: " + asg.variable() + " = " + valType);
} }
} }
/** 检查 if 语句。 */
private void checkIf(ModuleInfo mi, FunctionNode fn, SymbolTable locals, IfNode ifn) { private void checkIf(ModuleInfo mi, FunctionNode fn, SymbolTable locals, IfNode ifn) {
log("检查 if 条件"); log("检查 if 条件");
Type cond = checkExpression(mi, fn, locals, ifn.condition()); Type cond = checkExpression(mi, fn, locals, ifn.condition());
if (cond != BuiltinType.INT) { if (cond != BuiltinType.INT) {
errors.add(new SemanticError(ifn, "if 条件必须为 int 类型(表示真假)")); errors.add(new SemanticError(ifn, "if 条件必须为 int 类型(表示真假)"));
log("错误: if 条件类型不为 int: " + cond); log("错误: if 条件类型不为 int");
} else {
log("if 条件类型合法: " + cond);
} }
ifn.thenBranch().forEach(s -> checkStatement(mi, fn, locals, s)); ifn.thenBranch().forEach(stmt -> checkStatement(mi, fn, locals, stmt));
ifn.elseBranch().forEach(s -> checkStatement(mi, fn, locals, s)); ifn.elseBranch().forEach(stmt -> checkStatement(mi, fn, locals, stmt));
} }
/** 检查循环。 */
private void checkLoop(ModuleInfo mi, FunctionNode fn, SymbolTable locals, LoopNode ln) { private void checkLoop(ModuleInfo mi, FunctionNode fn, SymbolTable locals, LoopNode ln) {
log("检查 loop 循环"); log("检查 loop 循环");
checkStatement(mi, fn, locals, ln.initializer()); checkStatement(mi, fn, locals, ln.initializer());
Type cond = checkExpression(mi, fn, locals, ln.condition()); Type cond = checkExpression(mi, fn, locals, ln.condition());
if (cond != BuiltinType.INT) { if (cond != BuiltinType.INT) {
errors.add(new SemanticError(ln, "loop 条件必须为 int 类型(表示真假)")); errors.add(new SemanticError(ln, "loop 条件必须为 int 类型(表示真假)"));
log("错误: loop 条件类型不为 int: " + cond); log("错误: loop 条件类型不为 int");
} else {
log("loop 条件类型合法: " + cond);
} }
checkStatement(mi, fn, locals, ln.update()); checkStatement(mi, fn, locals, ln.update());
ln.body().forEach(s -> checkStatement(mi, fn, locals, s)); ln.body().forEach(stmt -> checkStatement(mi, fn, locals, stmt));
} }
/** 检查 return 语句。 */
private void checkReturn(ModuleInfo mi, FunctionNode fn, SymbolTable locals, ReturnNode ret) { private void checkReturn(ModuleInfo mi, FunctionNode fn, SymbolTable locals, ReturnNode ret) {
log("检查 return"); log("检查 return");
FunctionType expected = modules.get(mi.getName()).getFunctions().get(fn.name()); FunctionType expected = modules.get(mi.getName()).getFunctions().get(fn.name());
@ -200,18 +232,15 @@ public class SemanticAnalyzer {
Type actual = checkExpression(mi, fn, locals, exp.get()); Type actual = checkExpression(mi, fn, locals, exp.get());
if (!expected.returnType().isCompatible(actual)) { if (!expected.returnType().isCompatible(actual)) {
errors.add(new SemanticError(ret, "return 类型不匹配: 期望 " + expected.returnType() + ", 实际 " + actual)); errors.add(new SemanticError(ret, "return 类型不匹配: 期望 " + expected.returnType() + ", 实际 " + actual));
log("错误: return 类型不匹配: 期望 " + expected.returnType() + ", 实际 " + actual); log("错误: return 类型不匹配");
} else {
log("return 类型合法: " + actual);
} }
} else if (expected.returnType() != BuiltinType.VOID) { } else if (expected.returnType() != BuiltinType.VOID) {
errors.add(new SemanticError(ret, "非 void 函数必须返回值: " + expected.returnType())); errors.add(new SemanticError(ret, "非 void 函数必须返回值"));
log("错误: 非 void 函数缺少返回值: 期望 " + expected.returnType()); log("错误: 非 void 函数缺少返回值");
} else {
log("void 函数 return 合法");
} }
} }
/** 检查表达式,并返回其推断类型。 */
private Type checkExpression(ModuleInfo mi, FunctionNode fn, SymbolTable locals, ExpressionNode expr) { private Type checkExpression(ModuleInfo mi, FunctionNode fn, SymbolTable locals, ExpressionNode expr) {
log("检查表达式: " + expr); log("检查表达式: " + expr);
Type result; Type result;
@ -227,45 +256,47 @@ public class SemanticAnalyzer {
result = BuiltinType.INT; result = BuiltinType.INT;
} }
} }
log("表达式类型: " + result);
return result; return result;
} }
/** 检查变量引用。 */
private Type checkIdentifier(IdentifierNode id, SymbolTable locals) { private Type checkIdentifier(IdentifierNode id, SymbolTable locals) {
log("检查标识符: " + id.name());
Symbol sym = locals.resolve(id.name()); Symbol sym = locals.resolve(id.name());
if (sym == null) { if (sym == null) {
errors.add(new SemanticError(id, "未声明的标识符: " + id.name())); errors.add(new SemanticError(id, "未声明的标识符: " + id.name()));
log("错误: 未声明的标识符 " + id.name()); log("错误: 未声明的标识符 " + id.name());
return BuiltinType.INT; return BuiltinType.INT;
} }
log("标识符类型: " + sym.type());
return sym.type(); return sym.type();
} }
/** 检查函数调用表达式,并推断返回类型。 */
private Type checkCall(ModuleInfo mi, FunctionNode fn, SymbolTable locals, CallExpressionNode call) { private Type checkCall(ModuleInfo mi, FunctionNode fn, SymbolTable locals, CallExpressionNode call) {
log("检查函数调用: " + call.callee()); log("检查函数调用: " + call.callee());
ModuleInfo target = mi; ModuleInfo target = mi;
String name; String functionName;
ExpressionNode callee = call.callee(); ExpressionNode callee = call.callee();
// 解析调用目标
if (callee instanceof MemberExpressionNode(var object, var member)) { if (callee instanceof MemberExpressionNode(var object, var member)) {
if (object instanceof IdentifierNode(var modName)) { if (object instanceof IdentifierNode(var moduleName)) {
if (!modules.containsKey(modName) || (!mi.getImports().contains(modName) && !mi.getName().equals(modName))) { if (!modules.containsKey(moduleName) ||
errors.add(new SemanticError(callee, "未知或未导入模块: " + modName)); (!mi.getImports().contains(moduleName) && !mi.getName().equals(moduleName))) {
log("错误: 未导入模块 " + modName); errors.add(new SemanticError(callee, "未知或未导入模块: " + moduleName));
log("错误: 未导入模块 " + moduleName);
return BuiltinType.INT; return BuiltinType.INT;
} }
target = modules.get(modName); target = modules.get(moduleName);
name = member; functionName = member;
log("调用模块函数: " + modName + "." + member); log("调用模块函数: " + moduleName + "." + member);
} else { } else {
errors.add(new SemanticError(callee, "不支持的调用方式: " + callee)); errors.add(new SemanticError(callee, "不支持的调用方式: " + callee));
log("错误: 不支持的调用方式 " + callee); log("错误: 不支持的调用方式 " + callee);
return BuiltinType.INT; return BuiltinType.INT;
} }
} else if (callee instanceof IdentifierNode(var idName)) { } else if (callee instanceof IdentifierNode(var idName)) {
name = idName; functionName = idName;
log("调用当前模块函数: " + idName); log("调用当前模块函数: " + idName);
} else { } else {
errors.add(new SemanticError(callee, "不支持的调用方式: " + callee)); errors.add(new SemanticError(callee, "不支持的调用方式: " + callee));
@ -273,75 +304,97 @@ public class SemanticAnalyzer {
return BuiltinType.INT; return BuiltinType.INT;
} }
FunctionType ft = target.getFunctions().get(name); // 查找函数签名
FunctionType ft = target.getFunctions().get(functionName);
if (ft == null) { if (ft == null) {
errors.add(new SemanticError(callee, "函数未定义: " + name)); errors.add(new SemanticError(callee, "函数未定义: " + functionName));
log("错误: 函数未定义 " + name); log("错误: 函数未定义 " + functionName);
return BuiltinType.INT; return BuiltinType.INT;
} }
var args = new ArrayList<Type>(); // 检查参数
List<Type> args = new ArrayList<>();
for (var a : call.arguments()) { for (var a : call.arguments()) {
Type at = checkExpression(mi, fn, locals, a); args.add(checkExpression(mi, fn, locals, a));
args.add(at);
} }
if (args.size() != ft.paramTypes().size()) { if (args.size() != ft.paramTypes().size()) {
errors.add(new SemanticError(call, "参数数量不匹配: 期望 " + ft.paramTypes().size() + " 个, 实际 " + args.size())); errors.add(new SemanticError(call, "参数数量不匹配: 期望 "
log("错误: 参数数量不匹配: 期望 " + ft.paramTypes().size() + " 个, 实际 " + args.size()); + ft.paramTypes().size() + " 个, 实际 " + args.size() + ""));
log("错误: 参数数量不匹配: 期望 " + ft.paramTypes().size() + ", 实际 " + args.size());
} else { } else {
for (int i = 0; i < args.size(); i++) { for (int i = 0; i < args.size(); i++) {
if (!ft.paramTypes().get(i).isCompatible(args.get(i))) { if (!ft.paramTypes().get(i).isCompatible(args.get(i))) {
errors.add(new SemanticError(call, String.format( errors.add(new SemanticError(call, String.format(
"参数类型不匹配 (位置 %d): 期望 %s, 实际 %s", i, ft.paramTypes().get(i), args.get(i) "参数类型不匹配 (位置 %d): 期望 %s, 实际 %s", i, ft.paramTypes().get(i), args.get(i)
))); )));
log("错误: 参数类型不匹配 (位置 " + i + "): 期望 " + ft.paramTypes().get(i) + ", 实际 " + args.get(i)); log("错误: 参数类型不匹配 (位置 " + i + "): 期望 " + ft.paramTypes().get(i) + ", 实际 " + args.get(i));
} }
} }
if (verbose) log("参数检查完成,所有参数类型符合期望");
} }
log("函数调用类型: 返回 " + ft.returnType()); log("函数调用类型: 返回 " + ft.returnType());
return ft.returnType(); return ft.returnType();
} }
/** 检查二元表达式,并推断结果类型。 */
private Type checkBinary(BinaryExpressionNode bin, ModuleInfo mi, FunctionNode fn, SymbolTable locals) { private Type checkBinary(BinaryExpressionNode bin, ModuleInfo mi, FunctionNode fn, SymbolTable locals) {
log("检查二元表达式: " + bin.operator()); log("检查二元表达式: " + bin.operator());
Type l = checkExpression(mi, fn, locals, bin.left()); Type left = checkExpression(mi, fn, locals, bin.left());
Type r = checkExpression(mi, fn, locals, bin.right()); Type right = checkExpression(mi, fn, locals, bin.right());
String op = bin.operator(); String op = bin.operator();
Type result; Type result;
switch (op) { switch (op) {
case "+" -> { case "+" -> {
if (l == BuiltinType.STRING || r == BuiltinType.STRING) result = BuiltinType.STRING; // 字符串拼接 整数相加
else if (l == BuiltinType.INT && r == BuiltinType.INT) result = BuiltinType.INT; if (left == BuiltinType.STRING || right == BuiltinType.STRING) {
else result = null; result = BuiltinType.STRING;
} else if (left == BuiltinType.INT && right == BuiltinType.INT) {
result = BuiltinType.INT;
} else {
result = null;
}
} }
case "-", "*", "/", "%" -> { case "-", "*", "/", "%" -> {
if (l == BuiltinType.INT && r == BuiltinType.INT) result = BuiltinType.INT; // 数学运算要求两边都是 int
else result = null; if (left == BuiltinType.INT && right == BuiltinType.INT) {
result = BuiltinType.INT;
} else {
result = null;
}
} }
case "<", "<=", ">", ">=", "==", "!=" -> { case "<", "<=", ">", ">=", "==", "!=" -> {
if (l == BuiltinType.INT && r == BuiltinType.INT) result = BuiltinType.INT; // 比较运算要求 int 返回 int (表示真假)
else result = null; if (left == BuiltinType.INT && right == BuiltinType.INT) {
result = BuiltinType.INT;
} else {
result = null;
}
} }
default -> { default -> {
// 未知运算符
errors.add(new SemanticError(bin, "未知运算符: " + op)); errors.add(new SemanticError(bin, "未知运算符: " + op));
log("错误: 未知运算符 " + op); log("错误: 未知运算符 " + op);
return BuiltinType.INT; return BuiltinType.INT;
} }
} }
if (result == null) { if (result == null) {
errors.add(new SemanticError(bin, String.format("运算符 '%s' 不支持类型: %s, %s", op, l, r))); errors.add(new SemanticError(bin, String.format(
log("错误: 运算符 '" + op + "' 不支持类型: " + l + ", " + r); "运算符 '%s' 不支持类型: %s 和 %s", op, left, right
result = BuiltinType.INT; )));
log("错误: 运算符 '" + op + "' 不支持类型: " + left + ", " + right);
result = BuiltinType.INT; // 默认降级为 int 避免后续出错
} else { } else {
log("二元表达式计算类型: " + result); log("二元表达式推导类型: " + result);
} }
return result; return result;
} }
/** 解析类型名称,返回对应的内置类型,如果不存在返回 null。 */
private Type parseType(String name) { private Type parseType(String name) {
return BUILTIN_TYPES.get(name); return BUILTIN_TYPES.get(name);
} }
} }