fix: AOT 编译后无法定位语义错误
This commit is contained in:
parent
d020a7d5bf
commit
55ab421d88
@ -66,12 +66,12 @@ public class StatementBuilder {
|
|||||||
buildIf(ifNode);
|
buildIf(ifNode);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (stmt instanceof ExpressionStatementNode(ExpressionNode exp, _, _, _)) {
|
if (stmt instanceof ExpressionStatementNode(ExpressionNode exp, int _, int _, String _)) {
|
||||||
// 纯表达式语句,如 foo();
|
// 纯表达式语句,如 foo();
|
||||||
expr.build(exp);
|
expr.build(exp);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (stmt instanceof AssignmentNode(String var, ExpressionNode rhs, _, _, _)) {
|
if (stmt instanceof AssignmentNode(String var, ExpressionNode rhs, int _, int _, String _)) {
|
||||||
// 赋值语句,如 a = b + 1;
|
// 赋值语句,如 a = b + 1;
|
||||||
|
|
||||||
final String type = ctx.getScope().lookupType(var);
|
final String type = ctx.getScope().lookupType(var);
|
||||||
|
|||||||
@ -41,7 +41,7 @@ public final class ComparisonUtils {
|
|||||||
/* ------------ 内部工具 ------------ */
|
/* ------------ 内部工具 ------------ */
|
||||||
|
|
||||||
private static boolean isLongLiteral(ExpressionNode node) {
|
private static boolean isLongLiteral(ExpressionNode node) {
|
||||||
if (node instanceof NumberLiteralNode(String value)) {
|
if (node instanceof NumberLiteralNode(String value, int _, int _, String _)) {
|
||||||
return value.endsWith("L") || value.endsWith("l");
|
return value.endsWith("L") || value.endsWith("l");
|
||||||
}
|
}
|
||||||
return false; // 变量暂不处理(后续可扩展符号表查询)
|
return false; // 变量暂不处理(后续可扩展符号表查询)
|
||||||
|
|||||||
@ -127,7 +127,7 @@ public final class ExpressionUtils {
|
|||||||
|
|
||||||
/** 递归推断单个表达式节点的类型后缀(b/s/i/l/f/d)。 */
|
/** 递归推断单个表达式节点的类型后缀(b/s/i/l/f/d)。 */
|
||||||
private static char typeChar(ExpressionNode node) {
|
private static char typeChar(ExpressionNode node) {
|
||||||
if (node instanceof NumberLiteralNode(String value)) {
|
if (node instanceof NumberLiteralNode(String value, int _, int _, String _)) {
|
||||||
char last = Character.toLowerCase(value.charAt(value.length() - 1));
|
char last = Character.toLowerCase(value.charAt(value.length() - 1));
|
||||||
return switch (last) {
|
return switch (last) {
|
||||||
case 'b','s','i','l','f','d' -> last;
|
case 'b','s','i','l','f','d' -> last;
|
||||||
|
|||||||
@ -9,9 +9,17 @@ import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
|
|||||||
* 表达布尔类型的字面量常量(如 "true" 或 "false")。
|
* 表达布尔类型的字面量常量(如 "true" 或 "false")。
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @param value 字面量的布尔值
|
* @param value 字面量的布尔值
|
||||||
|
* @param line 当前节点所在的行号
|
||||||
|
* @param column 当前节点所在的列号
|
||||||
|
* @param file 当前节点所在的文件
|
||||||
*/
|
*/
|
||||||
public record BoolLiteralNode(boolean value) implements ExpressionNode {
|
public record BoolLiteralNode(
|
||||||
|
boolean value,
|
||||||
|
int line,
|
||||||
|
int column,
|
||||||
|
String file
|
||||||
|
) implements ExpressionNode {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 使用布尔字面量字符串构造一个 {@code BoolLiteralNode} 实例。
|
* 使用布尔字面量字符串构造一个 {@code BoolLiteralNode} 实例。
|
||||||
@ -22,8 +30,8 @@ public record BoolLiteralNode(boolean value) implements ExpressionNode {
|
|||||||
*
|
*
|
||||||
* @param lexeme 布尔字面量的字符串表示
|
* @param lexeme 布尔字面量的字符串表示
|
||||||
*/
|
*/
|
||||||
public BoolLiteralNode(String lexeme) {
|
public BoolLiteralNode(String lexeme, int line, int column, String file) {
|
||||||
this(Boolean.parseBoolean(lexeme));
|
this(Boolean.parseBoolean(lexeme), line, column, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -10,9 +10,17 @@ import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
|
|||||||
* 在语义分析或类型推导阶段再行解析为具体数值类型。
|
* 在语义分析或类型推导阶段再行解析为具体数值类型。
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @param value 数字字面量的原始字符串表示
|
* @param value 数字字面量的原始字符串表示
|
||||||
|
* @param line 当前节点所在的行号
|
||||||
|
* @param column 当前节点所在的列号
|
||||||
|
* @param file 当前节点所在的文件
|
||||||
*/
|
*/
|
||||||
public record NumberLiteralNode(String value) implements ExpressionNode {
|
public record NumberLiteralNode(
|
||||||
|
String value,
|
||||||
|
int line,
|
||||||
|
int column,
|
||||||
|
String file
|
||||||
|
) implements ExpressionNode {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回数字字面量的字符串形式。
|
* 返回数字字面量的字符串形式。
|
||||||
|
|||||||
@ -9,9 +9,17 @@ import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
|
|||||||
* 节点内部仅保存不带引号的字符串内容,便于后续语义处理或编码。
|
* 节点内部仅保存不带引号的字符串内容,便于后续语义处理或编码。
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @param value 字符串常量的内容,原始值中不包含双引号
|
* @param value 字符串常量的内容,原始值中不包含双引号
|
||||||
|
* @param line 当前节点所在的行号
|
||||||
|
* @param column 当前节点所在的列号
|
||||||
|
* @param file 当前节点所在的文件
|
||||||
*/
|
*/
|
||||||
public record StringLiteralNode(String value) implements ExpressionNode {
|
public record StringLiteralNode(
|
||||||
|
String value,
|
||||||
|
int line,
|
||||||
|
int column,
|
||||||
|
String file
|
||||||
|
) implements ExpressionNode {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回字符串字面量的带引号表示,适用于语法树调试或文本输出。
|
* 返回字符串字面量的带引号表示,适用于语法树调试或文本输出。
|
||||||
|
|||||||
@ -3,7 +3,7 @@ package org.jcnc.snow.compiler.parser.ast.base;
|
|||||||
/**
|
/**
|
||||||
* {@code Node} 是抽象语法树(AST)中所有语法节点的统一根接口。
|
* {@code Node} 是抽象语法树(AST)中所有语法节点的统一根接口。
|
||||||
* <p>
|
* <p>
|
||||||
* 作为标记接口(Marker Interface),该接口不定义任何方法,
|
* 作为标记接口(Marker Interface),该接口定义 3 个方法:line()、column() 和 file() 用于定位错误,
|
||||||
* 主要用于统一标识并组织 AST 体系中的各种语法构件节点,包括:
|
* 主要用于统一标识并组织 AST 体系中的各种语法构件节点,包括:
|
||||||
* </p>
|
* </p>
|
||||||
* <ul>
|
* <ul>
|
||||||
@ -15,4 +15,25 @@ package org.jcnc.snow.compiler.parser.ast.base;
|
|||||||
* 所有 AST 处理逻辑(如遍历、分析、代码生成)均可基于该接口实现统一调度和类型判定。
|
* 所有 AST 处理逻辑(如遍历、分析、代码生成)均可基于该接口实现统一调度和类型判定。
|
||||||
* </p>
|
* </p>
|
||||||
*/
|
*/
|
||||||
public interface Node {}
|
public interface Node {
|
||||||
|
/**
|
||||||
|
* 获取当前表达式所在的行号。
|
||||||
|
*
|
||||||
|
* @return 当前表达式的行号。
|
||||||
|
*/
|
||||||
|
int line();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前表达式所在的列号。
|
||||||
|
*
|
||||||
|
* @return 当前表达式的列号。
|
||||||
|
*/
|
||||||
|
int column();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前表达式所在的文件名。
|
||||||
|
*
|
||||||
|
* @return 当前表达式所在的文件名。
|
||||||
|
*/
|
||||||
|
String file();
|
||||||
|
}
|
||||||
|
|||||||
@ -28,6 +28,6 @@ public class BoolLiteralParselet implements PrefixParselet {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ExpressionNode parse(ParserContext ctx, Token token) {
|
public ExpressionNode parse(ParserContext ctx, Token token) {
|
||||||
return new BoolLiteralNode(token.getLexeme());
|
return new BoolLiteralNode(token.getLexeme(), token.getLine(), token.getCol(), ctx.getSourceName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,6 +24,6 @@ public class NumberLiteralParselet implements PrefixParselet {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ExpressionNode parse(ParserContext ctx, Token token) {
|
public ExpressionNode parse(ParserContext ctx, Token token) {
|
||||||
return new NumberLiteralNode(token.getLexeme());
|
return new NumberLiteralNode(token.getLexeme(), token.getLine(), token.getCol(), ctx.getSourceName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -27,6 +27,6 @@ public class StringLiteralParselet implements PrefixParselet {
|
|||||||
public ExpressionNode parse(ParserContext ctx, Token token) {
|
public ExpressionNode parse(ParserContext ctx, Token token) {
|
||||||
String raw = token.getRaw();
|
String raw = token.getRaw();
|
||||||
String content = raw.substring(1, raw.length() - 1);
|
String content = raw.substring(1, raw.length() - 1);
|
||||||
return new StringLiteralNode(content);
|
return new StringLiteralNode(content, token.getLine(), token.getCol(), ctx.getSourceName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -67,7 +67,7 @@ public class ASTPrinter {
|
|||||||
}
|
}
|
||||||
case FunctionNode(
|
case FunctionNode(
|
||||||
String name, List<ParameterNode> parameters, String returnType, List<StatementNode> body
|
String name, List<ParameterNode> parameters, String returnType, List<StatementNode> body
|
||||||
, _, _, _
|
, int _, int _, String _
|
||||||
) -> {
|
) -> {
|
||||||
System.out.println(pad + "function " + name
|
System.out.println(pad + "function " + name
|
||||||
+ "(params=" + parameters + ", return=" + returnType + ")");
|
+ "(params=" + parameters + ", return=" + returnType + ")");
|
||||||
@ -82,7 +82,7 @@ public class ASTPrinter {
|
|||||||
.orElse("");
|
.orElse("");
|
||||||
System.out.println(pad + "declare " + d.getName() + ":" + d.getType() + init);
|
System.out.println(pad + "declare " + d.getName() + ":" + d.getType() + init);
|
||||||
}
|
}
|
||||||
case AssignmentNode(String variable, ExpressionNode value, _, int _, String _) ->
|
case AssignmentNode(String variable, ExpressionNode value, int _, int _, String _) ->
|
||||||
System.out.println(pad + variable + " = " + value);
|
System.out.println(pad + variable + " = " + value);
|
||||||
case IfNode(
|
case IfNode(
|
||||||
ExpressionNode condition, List<StatementNode> thenBranch, List<StatementNode> elseBranch, int _,
|
ExpressionNode condition, List<StatementNode> thenBranch, List<StatementNode> elseBranch, int _,
|
||||||
|
|||||||
@ -194,15 +194,15 @@ public class ASTJsonSerializer {
|
|||||||
"operand", exprToMap(operand)
|
"operand", exprToMap(operand)
|
||||||
);
|
);
|
||||||
// 布尔字面量
|
// 布尔字面量
|
||||||
case BoolLiteralNode(boolean value) -> exprMap("BoolLiteral", "value", value);
|
case BoolLiteralNode(boolean value, int _, int _, String _) -> exprMap("BoolLiteral", "value", value);
|
||||||
// 标识符
|
// 标识符
|
||||||
case IdentifierNode(String name, int _, int _, String _) -> exprMap("Identifier", "name", name);
|
case IdentifierNode(String name, int _, int _, String _) -> exprMap("Identifier", "name", name);
|
||||||
// 数字字面量
|
// 数字字面量
|
||||||
case NumberLiteralNode(String value) -> exprMap("NumberLiteral", "value", value);
|
case NumberLiteralNode(String value, int _, int _, String _) -> exprMap("NumberLiteral", "value", value);
|
||||||
// 字符串字面量
|
// 字符串字面量
|
||||||
case StringLiteralNode(String value) -> exprMap("StringLiteral", "value", value);
|
case StringLiteralNode(String value, int _, int _, String _) -> exprMap("StringLiteral", "value", value);
|
||||||
// 调用表达式
|
// 调用表达式
|
||||||
case CallExpressionNode(ExpressionNode callee, List<ExpressionNode> arguments, _, _, _) -> {
|
case CallExpressionNode(ExpressionNode callee, List<ExpressionNode> arguments, int _, int _, String _) -> {
|
||||||
List<Object> args = new ArrayList<>(arguments.size());
|
List<Object> args = new ArrayList<>(arguments.size());
|
||||||
for (ExpressionNode arg : arguments) args.add(exprToMap(arg));
|
for (ExpressionNode arg : arguments) args.add(exprToMap(arg));
|
||||||
yield exprMap("CallExpression", "callee", exprToMap(callee), "arguments", args);
|
yield exprMap("CallExpression", "callee", exprToMap(callee), "arguments", args);
|
||||||
|
|||||||
@ -51,8 +51,8 @@ public class CallExpressionAnalyzer implements ExpressionAnalyzer<CallExpression
|
|||||||
ExpressionNode callee = call.callee();
|
ExpressionNode callee = call.callee();
|
||||||
|
|
||||||
// 支持模块调用形式:ModuleName.FunctionName(...)
|
// 支持模块调用形式:ModuleName.FunctionName(...)
|
||||||
if (callee instanceof MemberExpressionNode(var obj, String member, _, _, _)
|
if (callee instanceof MemberExpressionNode(var obj, String member, int _, int _, String _)
|
||||||
&& obj instanceof IdentifierNode(String mod, _, _, _)) {
|
&& obj instanceof IdentifierNode(String mod, int _, int _, String _)) {
|
||||||
// 验证模块是否存在并已导入
|
// 验证模块是否存在并已导入
|
||||||
if (!ctx.getModules().containsKey(mod)
|
if (!ctx.getModules().containsKey(mod)
|
||||||
|| (!mi.getImports().contains(mod) && !mi.getName().equals(mod))) {
|
|| (!mi.getImports().contains(mod) && !mi.getName().equals(mod))) {
|
||||||
@ -65,7 +65,7 @@ public class CallExpressionAnalyzer implements ExpressionAnalyzer<CallExpression
|
|||||||
functionName = member;
|
functionName = member;
|
||||||
|
|
||||||
// 简单函数名形式:func(...)
|
// 简单函数名形式:func(...)
|
||||||
} else if (callee instanceof IdentifierNode(String name, _, _, _)) {
|
} else if (callee instanceof IdentifierNode(String name, int _, int _, String _)) {
|
||||||
functionName = name;
|
functionName = name;
|
||||||
|
|
||||||
// 不支持的 callee 形式
|
// 不支持的 callee 形式
|
||||||
|
|||||||
@ -42,18 +42,9 @@ public record SemanticError(Node node, String message) {
|
|||||||
String file = null;
|
String file = null;
|
||||||
|
|
||||||
if (node != null) {
|
if (node != null) {
|
||||||
try {
|
line = node.line();
|
||||||
line = (int) node.getClass().getMethod("line").invoke(node);
|
col = node.column();
|
||||||
} catch (Exception ignored) {
|
file = node.file();
|
||||||
}
|
|
||||||
try {
|
|
||||||
col = (int) node.getClass().getMethod("column").invoke(node);
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
file = (String) node.getClass().getMethod("file").invoke(node);
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user