feat: 添加“while 语句”支持,并对解析器进行重构以处理控制流相关内容
- 引入了 WhileStmt 结构来表示 while 循环语句。 - 在解析器中实现了对 while 语句的解析逻辑。 - 在分析器中为 while 语句添加了语义分析。 - 重构了现有的解析器方法,以利用 StateProtector 进行状态管理。 - 更新了对各种表达式和语句的错误处理。 - 移除了未使用的终止符管理方法,并简化了表达式解析。 - 将 FigLSPServer.cpp 重命名为 LSPServer.cpp,并调整了构建配置。 - 增强了重复声明和类型错误的错误报告。 - 在多个文件中改进了代码格式和一致性。
This commit is contained in:
@@ -11,7 +11,8 @@ namespace Fig
|
||||
{
|
||||
Result<void, Error> Analyzer::analyzeVarDecl(VarDecl *stmt)
|
||||
{
|
||||
if (env.Resolve(stmt->name) != std::nullopt)
|
||||
auto sym = env.Resolve(stmt->name);
|
||||
if (sym != std::nullopt && sym->depth == env.GetDepth())
|
||||
{
|
||||
return std::unexpected(Error(ErrorType::RedeclarationError,
|
||||
std::format("variable `{}` has already defined in this scope", stmt->name),
|
||||
@@ -50,7 +51,7 @@ namespace Fig
|
||||
"none",
|
||||
makeSourceLocation(stmt->initExpr)));
|
||||
}
|
||||
env.Define(stmt->name, declaredType, stmt->isPublic, false);
|
||||
stmt->localId = env.Define(stmt->name, declaredType, stmt->isPublic, false);
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -63,12 +64,11 @@ namespace Fig
|
||||
}
|
||||
if (stmt->cond->resolvedType != TypeTag::Any && stmt->cond->resolvedType != TypeTag::Bool)
|
||||
{
|
||||
return std::unexpected(Error(
|
||||
ErrorType::TypeError,
|
||||
std::format("if condition must be boolean, got `{}`", magic_enum::enum_name(stmt->cond->resolvedType)),
|
||||
return std::unexpected(Error(ErrorType::TypeError,
|
||||
std::format("if condition must be boolean, got `{}`",
|
||||
magic_enum::enum_name(stmt->cond->resolvedType)),
|
||||
"ensure condition is boolean",
|
||||
makeSourceLocation(stmt->cond)
|
||||
));
|
||||
makeSourceLocation(stmt->cond)));
|
||||
}
|
||||
auto consequentRes = analyzeStmt(stmt->consequent);
|
||||
if (!consequentRes)
|
||||
@@ -106,6 +106,31 @@ namespace Fig
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<void, Error> Analyzer::analyzeWhileStmt(WhileStmt *stmt)
|
||||
{
|
||||
auto condRes = analyzeExpr(stmt->cond);
|
||||
if (!condRes)
|
||||
{
|
||||
return condRes;
|
||||
}
|
||||
|
||||
if (stmt->cond->resolvedType != TypeTag::Any && stmt->cond->resolvedType != TypeTag::Bool)
|
||||
{
|
||||
return std::unexpected(Error(ErrorType::TypeError,
|
||||
std::format("while condition must be boolean, got `{}`",
|
||||
magic_enum::enum_name(stmt->cond->resolvedType)),
|
||||
"ensure condition is boolean",
|
||||
makeSourceLocation(stmt->cond)));
|
||||
}
|
||||
|
||||
auto bodyRes = analyzeStmt(stmt->body);
|
||||
if (!bodyRes)
|
||||
{
|
||||
return bodyRes;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<void, Error> Analyzer::analyzeIdentiExpr(IdentiExpr *expr)
|
||||
{
|
||||
auto sym = env.Resolve(expr->name);
|
||||
@@ -117,8 +142,11 @@ namespace Fig
|
||||
makeSourceLocation(expr)));
|
||||
}
|
||||
// TODO: 引入 Module 跨文件 import,检查 isPublic
|
||||
expr->resolvedType = sym->type;
|
||||
expr->localId = sym->localId;
|
||||
|
||||
expr->resolvedType = sym->type;
|
||||
expr->resolvedDepth = sym->depth;
|
||||
expr->isGlobal = (sym->depth == 0);
|
||||
|
||||
return {};
|
||||
}
|
||||
@@ -138,7 +166,7 @@ namespace Fig
|
||||
|
||||
switch (expr->op)
|
||||
{
|
||||
// 1. 算术族 (+, -, *, /, **)
|
||||
// 算术族 (+, -, *, /, **)
|
||||
case BinaryOperator::Add:
|
||||
if (lType == TypeTag::String && rType == TypeTag::String)
|
||||
{
|
||||
@@ -172,7 +200,7 @@ namespace Fig
|
||||
}
|
||||
break;
|
||||
|
||||
// 2. 整数特化族 (%, &, |, ^, <<, >>)
|
||||
// 整数特化族 (%, &, |, ^, <<, >>)
|
||||
case BinaryOperator::Modulo:
|
||||
case BinaryOperator::BitAnd:
|
||||
case BinaryOperator::BitOr:
|
||||
@@ -196,8 +224,7 @@ namespace Fig
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
// 3. 比较族 (==, !=, <, >, <=, >=)
|
||||
// 比较族 (==, !=, <, >, <=, >=)
|
||||
|
||||
case BinaryOperator::Equal:
|
||||
case BinaryOperator::NotEqual:
|
||||
@@ -206,7 +233,8 @@ namespace Fig
|
||||
case BinaryOperator::LessEqual:
|
||||
case BinaryOperator::GreaterEqual:
|
||||
case BinaryOperator::Is:
|
||||
if (lType != TypeTag::Any && rType != TypeTag::Any && lType != rType) // lType == rType放行
|
||||
if (lType != TypeTag::Any && rType != TypeTag::Any
|
||||
&& lType != rType) // lType == rType放行
|
||||
{
|
||||
if (!((lType == TypeTag::Int && rType == TypeTag::Double)
|
||||
|| (lType == TypeTag::Double && rType == TypeTag::Int)))
|
||||
@@ -217,7 +245,7 @@ namespace Fig
|
||||
makeSourceLocation(expr)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO: 支持Struct后进行检查,右操作数是 Struct才合理
|
||||
// 如 1.2 is Int --> false
|
||||
// 1 is Int --> true
|
||||
@@ -225,8 +253,7 @@ namespace Fig
|
||||
expr->resolvedType = TypeTag::Bool;
|
||||
break;
|
||||
|
||||
|
||||
// 4. 逻辑族 (&&, ||)
|
||||
// 逻辑族 (&&, ||)
|
||||
case BinaryOperator::LogicalAnd:
|
||||
case BinaryOperator::LogicalOr:
|
||||
if (lType == TypeTag::Bool && rType == TypeTag::Bool)
|
||||
@@ -246,8 +273,7 @@ namespace Fig
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
// 5. 纯赋值与复合赋值族 (=, +=, -=, ...)
|
||||
// 纯赋值与复合赋值族 (=, +=, -=, ...)
|
||||
case BinaryOperator::Assign:
|
||||
case BinaryOperator::AddAssign:
|
||||
case BinaryOperator::SubAssign:
|
||||
@@ -258,12 +284,11 @@ namespace Fig
|
||||
// 左侧必须是合法的 L-Value
|
||||
if (!isValidLvalue(expr->left))
|
||||
{
|
||||
return std::unexpected(
|
||||
Error(ErrorType::NotAnLvalue,
|
||||
"invalid assignment target",
|
||||
"left side must be a variable, property, or indexable target",
|
||||
makeSourceLocation(expr->left) // 错误精准定位到左侧节点
|
||||
));
|
||||
return std::unexpected(Error(ErrorType::NotAnLvalue,
|
||||
"invalid assignment target",
|
||||
"left side must be a variable, property, or indexable target",
|
||||
makeSourceLocation(expr->left) // 错误精准定位到左侧节点
|
||||
));
|
||||
}
|
||||
|
||||
// 类型匹配拦截 (纯赋值)
|
||||
@@ -283,8 +308,7 @@ namespace Fig
|
||||
expr->resolvedType = lType;
|
||||
break;
|
||||
|
||||
|
||||
// 6. 成员访问 (.)
|
||||
// 成员访问 (.)
|
||||
case BinaryOperator::MemberAccess:
|
||||
if (lType != TypeTag::Struct && lType != TypeTag::Any)
|
||||
{
|
||||
@@ -293,6 +317,15 @@ namespace Fig
|
||||
"check if the left side evaluates to an object",
|
||||
makeSourceLocation(expr->left)));
|
||||
}
|
||||
if (expr->right->type != AstType::IdentiExpr)
|
||||
{
|
||||
return std::unexpected(Error(
|
||||
ErrorType::SyntaxError,
|
||||
std::format("expect field name after member access '.', got {}", expr->right->toString()),
|
||||
"none",
|
||||
makeSourceLocation(expr->right)
|
||||
));
|
||||
}
|
||||
expr->resolvedType = TypeTag::Any;
|
||||
break;
|
||||
|
||||
@@ -335,14 +368,18 @@ namespace Fig
|
||||
case AstType::IfStmt: {
|
||||
return analyzeIfStmt(static_cast<IfStmt *>(stmt));
|
||||
}
|
||||
|
||||
// TODO: 其他语句分析
|
||||
|
||||
// default:
|
||||
// return std::unexpected(Error(ErrorType::TypeError,
|
||||
// "unsupported statement type in analyzer",
|
||||
// "internal compiler error",
|
||||
// makeSourceLocation(stmt)));
|
||||
case AstType::WhileStmt: {
|
||||
return analyzeWhileStmt(static_cast<WhileStmt *>(stmt));
|
||||
}
|
||||
|
||||
// TODO: 其他语句分析
|
||||
|
||||
// default:
|
||||
// return std::unexpected(Error(ErrorType::TypeError,
|
||||
// "unsupported statement type in analyzer",
|
||||
// "internal compiler error",
|
||||
// makeSourceLocation(stmt)));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
@@ -356,17 +393,13 @@ namespace Fig
|
||||
{
|
||||
case AstType::LiteralExpr: {
|
||||
auto *lit = static_cast<LiteralExpr *>(expr);
|
||||
switch(lit->token.type)
|
||||
switch (lit->token.type)
|
||||
{
|
||||
case TokenType::LiteralTrue:
|
||||
case TokenType::LiteralFalse:
|
||||
lit->resolvedType = TypeTag::Bool;
|
||||
break;
|
||||
|
||||
case TokenType::LiteralNull:
|
||||
lit->resolvedType = TypeTag::Null;
|
||||
break;
|
||||
|
||||
case TokenType::LiteralFalse: lit->resolvedType = TypeTag::Bool; break;
|
||||
|
||||
case TokenType::LiteralNull: lit->resolvedType = TypeTag::Null; break;
|
||||
|
||||
case TokenType::LiteralNumber: {
|
||||
const String &lexeme = manager.GetSub(lit->token.index, lit->token.length);
|
||||
if (lexeme.contains(U'.') || lexeme.contains(U'e'))
|
||||
@@ -385,9 +418,10 @@ namespace Fig
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
default: {
|
||||
lit->resolvedType = TypeTag::Any;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ namespace Fig
|
||||
|
||||
Result<void, Error> analyzeVarDecl(VarDecl *);
|
||||
Result<void, Error> analyzeIfStmt(IfStmt *);
|
||||
Result<void, Error> analyzeWhileStmt(WhileStmt *);
|
||||
|
||||
Result<void, Error> analyzeIdentiExpr(IdentiExpr *);
|
||||
Result<void, Error> analyzeInfixExpr(InfixExpr *);
|
||||
|
||||
@@ -24,10 +24,10 @@ int main()
|
||||
return 1;
|
||||
}
|
||||
|
||||
Lexer lexer(manager.GetSource(), fileName);
|
||||
Lexer lexer(manager.GetSource(), fileName);
|
||||
Parser parser(lexer, manager, fileName);
|
||||
|
||||
const auto &result = parser.Parse();
|
||||
auto result = parser.Parse();
|
||||
if (!result)
|
||||
{
|
||||
ReportError(result.error(), manager);
|
||||
|
||||
@@ -7,15 +7,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Sema/Type.hpp>
|
||||
#include <Deps/Deps.hpp>
|
||||
#include <Error/Error.hpp>
|
||||
#include <Sema/Type.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <optional>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
|
||||
// 记录在 Analyzer 中的符号元数据
|
||||
struct Symbol
|
||||
{
|
||||
@@ -24,41 +24,108 @@ namespace Fig
|
||||
bool isPublic;
|
||||
int depth; // 词法作用域深度
|
||||
bool isConstant; // 是否是 const 声明的不可变常量 (用于报错: 尝试修改常量)
|
||||
|
||||
int localId = -1; // Analyzer 虚拟槽位分配
|
||||
};
|
||||
|
||||
// 作用域回档水位线
|
||||
struct ScopeWatermark
|
||||
{
|
||||
std::size_t symbolCount;
|
||||
int savedLocalId;
|
||||
};
|
||||
|
||||
// 语义分析函数上下文 (隔离局部变量 ID 空间)
|
||||
struct SemaFuncState
|
||||
{
|
||||
SemaFuncState *enclosing = nullptr;
|
||||
int currentDepth = 0;
|
||||
int nextLocalId = 0;
|
||||
DynArray<ScopeWatermark> scopeStack;
|
||||
};
|
||||
|
||||
class Environment
|
||||
{
|
||||
private:
|
||||
DynArray<Symbol> symbols;
|
||||
int currentDepth = 0;
|
||||
SemaFuncState *current = nullptr;
|
||||
|
||||
public:
|
||||
Environment()
|
||||
{
|
||||
current = new SemaFuncState();
|
||||
}
|
||||
|
||||
~Environment()
|
||||
{
|
||||
while (current)
|
||||
{
|
||||
SemaFuncState *prev = current->enclosing;
|
||||
delete current;
|
||||
current = prev;
|
||||
}
|
||||
}
|
||||
|
||||
// 函数边界控
|
||||
|
||||
void EnterFunction()
|
||||
{
|
||||
SemaFuncState *newState = new SemaFuncState();
|
||||
newState->enclosing = current;
|
||||
current = newState;
|
||||
}
|
||||
|
||||
void LeaveFunction()
|
||||
{
|
||||
assert(current && "Environment: Unmatched LeaveFunction");
|
||||
SemaFuncState *oldState = current;
|
||||
current = oldState->enclosing;
|
||||
delete oldState;
|
||||
}
|
||||
|
||||
// 词法作用域控制
|
||||
|
||||
void EnterScope()
|
||||
{
|
||||
currentDepth++;
|
||||
current->currentDepth++;
|
||||
current->scopeStack.push_back({symbols.size(), current->nextLocalId});
|
||||
}
|
||||
|
||||
void LeaveScope()
|
||||
{
|
||||
while (!symbols.empty() && symbols.back().depth > currentDepth)
|
||||
assert(current->currentDepth > 0 && "Environment: Unmatched LeaveScope");
|
||||
current->currentDepth--;
|
||||
|
||||
assert(!current->scopeStack.empty());
|
||||
ScopeWatermark archive = current->scopeStack.back();
|
||||
current->scopeStack.pop_back();
|
||||
|
||||
// 物理截断符号表,回滚槽位发号器以复用物理寄存器
|
||||
while (symbols.size() > archive.symbolCount)
|
||||
{
|
||||
symbols.pop_back();
|
||||
}
|
||||
currentDepth--;
|
||||
current->nextLocalId = archive.savedLocalId;
|
||||
}
|
||||
|
||||
// 注册符号, 调用前确保无重复 (内部assert)
|
||||
void Define(const String &name, TypeTag type, bool isPublic, bool isConst)
|
||||
// 符号操作
|
||||
|
||||
// 注册符号, 返回分配的 localId。调用前内部执行同级作用域重定义断言
|
||||
int Define(const String &name, TypeTag type, bool isPublic, bool isConst)
|
||||
{
|
||||
for (auto it = symbols.rbegin(); it != symbols.rend(); ++it)
|
||||
{
|
||||
if (it->depth < currentDepth)
|
||||
if (it->depth < current->currentDepth)
|
||||
break;
|
||||
if (it->name == name)
|
||||
{
|
||||
assert(false && "Environment.Define: redefinition");
|
||||
}
|
||||
}
|
||||
symbols.push_back({name, type, isPublic, currentDepth, isConst});
|
||||
|
||||
int allocatedId = current->nextLocalId++;
|
||||
symbols.push_back({name, type, isPublic, current->currentDepth, isConst, allocatedId});
|
||||
return allocatedId;
|
||||
}
|
||||
|
||||
// 解析符号。找不到返回 nullopt
|
||||
@@ -74,7 +141,7 @@ namespace Fig
|
||||
|
||||
int GetDepth() const
|
||||
{
|
||||
return currentDepth;
|
||||
return current->currentDepth;
|
||||
}
|
||||
};
|
||||
} // namespace Fig
|
||||
Reference in New Issue
Block a user