feat: 添加“while 语句”支持,并对解析器进行重构以处理控制流相关内容

- 引入了 WhileStmt 结构来表示 while 循环语句。
- 在解析器中实现了对 while 语句的解析逻辑。
- 在分析器中为 while 语句添加了语义分析。
- 重构了现有的解析器方法,以利用 StateProtector 进行状态管理。
- 更新了对各种表达式和语句的错误处理。
- 移除了未使用的终止符管理方法,并简化了表达式解析。
- 将 FigLSPServer.cpp 重命名为 LSPServer.cpp,并调整了构建配置。
- 增强了重复声明和类型错误的错误报告。
- 在多个文件中改进了代码格式和一致性。
This commit is contained in:
2026-02-25 17:31:00 +08:00
parent b7bb889676
commit a0fb8cdffb
25 changed files with 670 additions and 355 deletions

View File

@@ -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 {};
}

View File

@@ -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 *);

View File

@@ -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);

View File

@@ -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