重构类型系统并改进诊断功能
- 更新了类型系统,新增了类型并优化了结构。 - 引入了基类型和派生类,用于函数、结构体和接口类型。 - 实现了类型上下文,用于管理内置类型和类型解析。 - 添加了诊断类,用于收集和报告警告和错误。 - 通过改进错误处理增强了虚拟机执行,以应对递归限制问题。 - 实现了反汇编器,将字节码转换为代码,以改善调试和分析。 - 添加了新的抽象语法树节点,用于成员表达式、对象初始化、接口和结构体定义。 - 引入了语义错误测试,包括重定义、未声明的变量和无效的结构字段。
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1,100 +1,53 @@
|
||||
/*!
|
||||
@file src/Sema/Analyzer.hpp
|
||||
@brief 前端类型检查器定义
|
||||
@author PuqiAR (im@puqiar.top)
|
||||
@date 2026-02-23
|
||||
@brief 语义分析器定义
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Sema/Environment.hpp>
|
||||
#include <Sema/Type.hpp>
|
||||
|
||||
#include <Ast/Ast.hpp>
|
||||
#include <Deps/Deps.hpp>
|
||||
#include <Sema/Type.hpp>
|
||||
#include <Sema/Environment.hpp>
|
||||
#include <Utils/Arena.hpp>
|
||||
#include <Error/Diagnostics.hpp>
|
||||
#include <SourceManager/SourceManager.hpp>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
class Analyzer
|
||||
{
|
||||
private:
|
||||
Environment env;
|
||||
Arena arena;
|
||||
SourceManager &manager;
|
||||
TypeContext typeCtx;
|
||||
Environment env;
|
||||
Diagnostics diag;
|
||||
|
||||
TypeContext typeCtx;
|
||||
HashMap<String, BaseType*> globalTypes;
|
||||
HashMap<String, Symbol*> globalSymbols;
|
||||
|
||||
TypeInfo *currentReturnType = nullptr; // 正在分析的函数,预期返回类型
|
||||
bool hasInit = false;
|
||||
bool hasMain = false;
|
||||
|
||||
struct ReturnTypeProtector
|
||||
{
|
||||
Analyzer *analyzer;
|
||||
TypeInfo *prevCurrentReturnType;
|
||||
// 核心递归查找:解决跨越函数边界的捕获问题
|
||||
Result<Symbol*, Error> resolveSymbolInternal(const String &name, const SourceLocation &loc, Scope* startScope);
|
||||
|
||||
[[nodiscard]]
|
||||
ReturnTypeProtector(Analyzer *_analyzer, TypeInfo *current) :
|
||||
analyzer(_analyzer), prevCurrentReturnType(_analyzer->currentReturnType)
|
||||
{
|
||||
analyzer->currentReturnType = current;
|
||||
}
|
||||
Result<Type, Error> resolveTypeExpr(TypeExpr *texpr);
|
||||
Result<void, Error> pass1(Program *prog);
|
||||
Result<void, Error> resolveTypes(Program *prog);
|
||||
Result<void, Error> checkBodies(Program *prog);
|
||||
|
||||
~ReturnTypeProtector()
|
||||
{
|
||||
analyzer->currentReturnType = prevCurrentReturnType;
|
||||
}
|
||||
|
||||
ReturnTypeProtector(const ReturnTypeProtector &) = delete;
|
||||
ReturnTypeProtector &operator=(const ReturnTypeProtector &) = delete;
|
||||
};
|
||||
|
||||
|
||||
SourceLocation makeSourceLocation(
|
||||
AstNode *ast, std::source_location loc = std::source_location::current())
|
||||
{
|
||||
return SourceLocation(ast->location.sp,
|
||||
ast->location.fileName,
|
||||
"[internal analyzer]",
|
||||
loc.function_name());
|
||||
}
|
||||
|
||||
bool isValidLvalue(Expr *expr)
|
||||
{
|
||||
if (expr->type == AstType::IdentiExpr)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (expr->type == AstType::InfixExpr)
|
||||
{
|
||||
InfixExpr *infix = static_cast<InfixExpr *>(expr);
|
||||
if (infix->op == BinaryOperator::MemberAccess)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (expr->type == AstType::IndexExpr)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Result<TypeInfo *, Error> resolveType(TypeExpr *);
|
||||
|
||||
Result<void, Error> analyzeVarDecl(VarDecl *);
|
||||
Result<void, Error> analyzeIfStmt(IfStmt *);
|
||||
Result<void, Error> analyzeWhileStmt(WhileStmt *);
|
||||
Result<void, Error> analyzeFnDefStmt(FnDefStmt *);
|
||||
Result<void, Error> analyzeReturnStmt(ReturnStmt *);
|
||||
|
||||
Result<void, Error> analyzeIdentiExpr(IdentiExpr *);
|
||||
Result<void, Error> analyzeInfixExpr(InfixExpr *);
|
||||
Result<void, Error> analyzeCallExpr(CallExpr *);
|
||||
|
||||
Result<void, Error> analyzeStmt(Stmt *);
|
||||
Result<void, Error> analyzeExpr(Expr *);
|
||||
Result<void, Error> analyzeStmt(Stmt *stmt);
|
||||
Result<Type, Error> analyzeExpr(Expr *expr);
|
||||
|
||||
int addUpvalue(Scope *scope, Symbol *target, bool isLocal);
|
||||
|
||||
public:
|
||||
Result<void, Error> Analyze(Program *);
|
||||
Analyzer(SourceManager &m) : manager(m) {}
|
||||
|
||||
Analyzer(SourceManager &_manager) : manager(_manager), typeCtx() {}
|
||||
Result<void, Error> Analyze(Program *prog);
|
||||
|
||||
Diagnostics& GetDiagnostics() { return diag; }
|
||||
TypeContext& GetTypeContext() { return typeCtx; }
|
||||
};
|
||||
}; // namespace Fig
|
||||
}
|
||||
|
||||
@@ -1,50 +1,59 @@
|
||||
#include <Sema/Analyzer.hpp>
|
||||
|
||||
#include <Deps/Deps.hpp>
|
||||
#include <Error/Error.hpp>
|
||||
#include <Lexer/Lexer.hpp>
|
||||
#include <Parser/Parser.hpp>
|
||||
#include <SourceManager/SourceManager.hpp>
|
||||
|
||||
#include <Sema/Analyzer.hpp>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
void runTest(const std::string &path)
|
||||
{
|
||||
using namespace Fig;
|
||||
std::cout << "\n[TEST] Testing: " << path << std::endl;
|
||||
|
||||
SourceManager srcManager{String(path)};
|
||||
String source = srcManager.Read();
|
||||
if (!srcManager.read)
|
||||
{
|
||||
std::cerr << "FAILED: Could not read file" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
Lexer lexer(source, String(path));
|
||||
Parser parser(lexer, srcManager, String(path));
|
||||
|
||||
auto pRes = parser.Parse();
|
||||
if (!pRes)
|
||||
{
|
||||
std::cerr << "FAILED: Parser Error" << std::endl;
|
||||
ReportError(pRes.error(), srcManager);
|
||||
return;
|
||||
}
|
||||
|
||||
// 修复:确保 analyzer 存活直到错误打印完成
|
||||
Analyzer analyzer(srcManager);
|
||||
auto aRes = analyzer.Analyze(*pRes);
|
||||
|
||||
if (!aRes)
|
||||
{
|
||||
std::cout << "SUCCESS: Analyzer correctly caught error:" << std::endl;
|
||||
ReportError(aRes.error(), srcManager);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "FAILED: Analyzer missed the semantic error!" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace Fig;
|
||||
|
||||
const String &fileName = "test.fig";
|
||||
const String &filePath = "T:/Files/Maker/Code/MyCodingLanguage/The Fig Project/Fig/test.fig";
|
||||
|
||||
SourceManager manager(filePath);
|
||||
manager.Read();
|
||||
|
||||
if (!manager.read)
|
||||
std::string testDir = "T:/Files/Maker/Code/MyCodingLanguage/The Fig Project/Fig/tests/Sema";
|
||||
for (const auto &entry : fs::directory_iterator(testDir))
|
||||
{
|
||||
std::cerr << "Read file failed \n";
|
||||
return 1;
|
||||
if (entry.path().extension() == ".fig")
|
||||
{
|
||||
runTest(entry.path().string());
|
||||
}
|
||||
}
|
||||
|
||||
Lexer lexer(manager.GetSource(), fileName);
|
||||
Parser parser(lexer, manager, fileName);
|
||||
|
||||
auto result = parser.Parse();
|
||||
if (!result)
|
||||
{
|
||||
ReportError(result.error(), manager);
|
||||
return 1;
|
||||
}
|
||||
|
||||
Program *program = *result;
|
||||
|
||||
Analyzer analyzer(manager);
|
||||
|
||||
const auto &analyzeResult = analyzer.Analyze(program);
|
||||
if (!analyzeResult)
|
||||
{
|
||||
ReportError(analyzeResult.error(), manager);
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::cout << "Analyze successfully, PROGRAM OK\n";
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,147 +1,74 @@
|
||||
/*!
|
||||
@file src/Sema/Environment.hpp
|
||||
@brief 符号和作用域环境定义
|
||||
@author PuqiAR (im@puqiar.top)
|
||||
@date 2026-02-23
|
||||
@brief 树状符号表定义
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Deps/Deps.hpp>
|
||||
#include <Error/Error.hpp>
|
||||
#include <Sema/Type.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <optional>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
// 记录在 Analyzer 中的符号元数据
|
||||
enum class SymbolLocation
|
||||
{
|
||||
Global,
|
||||
Local,
|
||||
Upvalue
|
||||
};
|
||||
|
||||
struct Symbol
|
||||
{
|
||||
String name;
|
||||
TypeInfo *type;
|
||||
bool isPublic;
|
||||
int depth; // 词法作用域深度
|
||||
bool isConstant; // 是否是 const 声明的不可变常量 (用于报错: 尝试修改常量)
|
||||
String name;
|
||||
Type type;
|
||||
SymbolLocation location;
|
||||
int index;
|
||||
bool isConst;
|
||||
|
||||
int localId = -1; // Analyzer 虚拟槽位分配
|
||||
Symbol(String n, Type t, SymbolLocation l, int i, bool c) :
|
||||
name(std::move(n)), type(t), location(l), index(i), isConst(c)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// 作用域回档水位线
|
||||
struct ScopeWatermark
|
||||
struct UpvalueCapture
|
||||
{
|
||||
std::size_t symbolCount;
|
||||
int savedLocalId;
|
||||
Symbol *target;
|
||||
int index;
|
||||
bool isLocal;
|
||||
};
|
||||
|
||||
// 语义分析函数上下文 (隔离局部变量 ID 空间)
|
||||
struct SemaFuncState
|
||||
struct Scope
|
||||
{
|
||||
SemaFuncState *enclosing = nullptr;
|
||||
int currentDepth = 0;
|
||||
int nextLocalId = 0;
|
||||
DynArray<ScopeWatermark> scopeStack;
|
||||
Scope *parent = nullptr;
|
||||
bool isFunctionBoundary = false;
|
||||
|
||||
HashMap<String, Symbol *> locals;
|
||||
DynArray<UpvalueCapture> upvalues;
|
||||
|
||||
int nextLocalId = 0;
|
||||
|
||||
Scope(Scope *p, bool isFn) : parent(p), isFunctionBoundary(isFn)
|
||||
{
|
||||
if (p && !isFn)
|
||||
nextLocalId = p->nextLocalId;
|
||||
}
|
||||
};
|
||||
|
||||
class Environment
|
||||
{
|
||||
private:
|
||||
DynArray<Symbol> symbols;
|
||||
SemaFuncState *current = nullptr;
|
||||
|
||||
public:
|
||||
Environment()
|
||||
Scope *current = nullptr;
|
||||
|
||||
void Push(bool isFn)
|
||||
{
|
||||
current = new SemaFuncState();
|
||||
current = new Scope(current, isFn);
|
||||
}
|
||||
|
||||
~Environment()
|
||||
void Pop()
|
||||
{
|
||||
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()
|
||||
{
|
||||
current->currentDepth++;
|
||||
current->scopeStack.push_back({symbols.size(), current->nextLocalId});
|
||||
}
|
||||
|
||||
void LeaveScope()
|
||||
{
|
||||
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();
|
||||
}
|
||||
current->nextLocalId = archive.savedLocalId;
|
||||
}
|
||||
|
||||
// 符号操作
|
||||
|
||||
// 注册符号, 返回分配的 localId。调用前内部执行同级作用域重定义断言
|
||||
int Define(const String &name, TypeInfo *type, bool isPublic, bool isConst)
|
||||
{
|
||||
for (auto it = symbols.rbegin(); it != symbols.rend(); ++it)
|
||||
{
|
||||
if (it->depth < current->currentDepth)
|
||||
break;
|
||||
if (it->name == name)
|
||||
{
|
||||
assert(false && "Environment.Define: redefinition");
|
||||
}
|
||||
}
|
||||
|
||||
int allocatedId = current->nextLocalId++;
|
||||
symbols.push_back({name, type, isPublic, current->currentDepth, isConst, allocatedId});
|
||||
return allocatedId;
|
||||
}
|
||||
|
||||
// 解析符号。找不到返回 nullopt
|
||||
std::optional<Symbol> Resolve(const String &name)
|
||||
{
|
||||
for (auto it = symbols.rbegin(); it != symbols.rend(); ++it)
|
||||
{
|
||||
if (it->name == name)
|
||||
return *it;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
int GetDepth() const
|
||||
{
|
||||
return current->currentDepth;
|
||||
Scope *old = current;
|
||||
current = current->parent;
|
||||
delete old;
|
||||
}
|
||||
};
|
||||
} // namespace Fig
|
||||
} // namespace Fig
|
||||
|
||||
93
src/Sema/Type.cpp
Normal file
93
src/Sema/Type.cpp
Normal file
@@ -0,0 +1,93 @@
|
||||
/*!
|
||||
@file src/Sema/Type.cpp
|
||||
@brief 类型系统实现
|
||||
*/
|
||||
|
||||
#include <Sema/Type.hpp>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
bool Type::is(TypeTag t) const
|
||||
{
|
||||
return base && base->tag == t;
|
||||
}
|
||||
|
||||
String Type::toString() const
|
||||
{
|
||||
if (!base)
|
||||
return "Unknown";
|
||||
if (base->tag == TypeTag::Function)
|
||||
{
|
||||
auto *ft = static_cast<FuncType *>(base);
|
||||
String sig = "func(";
|
||||
for (size_t i = 0; i < ft->paramTypes.size(); ++i)
|
||||
{
|
||||
sig += ft->paramTypes[i].toString();
|
||||
if (i < ft->paramTypes.size() - 1)
|
||||
sig += ", ";
|
||||
}
|
||||
sig += ") -> " + ft->retType.toString();
|
||||
return sig;
|
||||
}
|
||||
|
||||
String res = base->name;
|
||||
if (isNullable && base->tag != TypeTag::Null)
|
||||
res += "?";
|
||||
return res;
|
||||
}
|
||||
|
||||
bool Type::isAssignableTo(const Type &target) const
|
||||
{
|
||||
if (target.is(TypeTag::Any) || this->is(TypeTag::Any))
|
||||
return true; // Any 逃逸通道
|
||||
if (this->is(TypeTag::Null) && target.isNullable)
|
||||
return true; // Null 安全赋值
|
||||
return this->base == target.base && (!this->isNullable || target.isNullable); // 严格匹配
|
||||
}
|
||||
|
||||
TypeContext::TypeContext()
|
||||
{
|
||||
intType = new BaseType(TypeTag::Int, "Int");
|
||||
doubleType = new BaseType(TypeTag::Double, "Double");
|
||||
stringType = new BaseType(TypeTag::String, "String");
|
||||
boolType = new BaseType(TypeTag::Bool, "Bool");
|
||||
anyType = new BaseType(TypeTag::Any, "Any");
|
||||
nullType = new BaseType(TypeTag::Null, "Null");
|
||||
|
||||
allTypes.push_back(intType);
|
||||
allTypes.push_back(doubleType);
|
||||
allTypes.push_back(stringType);
|
||||
allTypes.push_back(boolType);
|
||||
allTypes.push_back(anyType);
|
||||
allTypes.push_back(nullType);
|
||||
}
|
||||
|
||||
TypeContext::~TypeContext()
|
||||
{
|
||||
for (auto t : allTypes)
|
||||
delete t;
|
||||
}
|
||||
|
||||
Type TypeContext::GetBasic(TypeTag tag, bool nullable)
|
||||
{
|
||||
BaseType *b = nullptr;
|
||||
switch (tag)
|
||||
{
|
||||
case TypeTag::Int: b = intType; break;
|
||||
case TypeTag::Double: b = doubleType; break;
|
||||
case TypeTag::String: b = stringType; break;
|
||||
case TypeTag::Bool: b = boolType; break;
|
||||
case TypeTag::Any: b = anyType; break;
|
||||
case TypeTag::Null: b = nullType; break;
|
||||
default: break;
|
||||
}
|
||||
return {b, nullable};
|
||||
}
|
||||
|
||||
Type TypeContext::CreateFuncType(DynArray<Type> params, Type ret)
|
||||
{
|
||||
auto *ft = new FuncType(std::move(params), ret);
|
||||
allTypes.push_back(ft);
|
||||
return Type{ft, false};
|
||||
}
|
||||
} // namespace Fig
|
||||
@@ -1,171 +1,115 @@
|
||||
/*!
|
||||
@file src/Sema/Type.hpp
|
||||
@brief 前端类型检查的类型定义和类型驻留池
|
||||
@author PuqiAR (im@puqiar.top)
|
||||
@date 2026-02-23
|
||||
@brief 类型系统定义:对齐 NaN-boxing 物理布局
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Deps/Deps.hpp>
|
||||
#include <cstdint>
|
||||
#include <Error/Error.hpp>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
enum class TypeTag : std::uint8_t
|
||||
{
|
||||
Any, // 动态类型底线
|
||||
Null, // 空值
|
||||
Int,
|
||||
Double,
|
||||
Bool,
|
||||
String,
|
||||
Bool,
|
||||
Null,
|
||||
Any,
|
||||
Function,
|
||||
Struct,
|
||||
Interface
|
||||
};
|
||||
|
||||
struct TypeInfo
|
||||
class BaseType;
|
||||
|
||||
struct Type
|
||||
{
|
||||
BaseType *base = nullptr;
|
||||
bool isNullable = false;
|
||||
|
||||
bool operator==(const Type &other) const
|
||||
{
|
||||
return base == other.base && isNullable == other.isNullable;
|
||||
}
|
||||
bool operator!=(const Type &other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
bool is(TypeTag tag) const;
|
||||
String toString() const;
|
||||
|
||||
bool isAssignableTo(const Type &target) const;
|
||||
};
|
||||
|
||||
class BaseType
|
||||
{
|
||||
public:
|
||||
TypeTag tag;
|
||||
String name; // 完整路径序列化, 如 Int, std.file.File
|
||||
String name;
|
||||
BaseType(TypeTag t, String n) : tag(t), name(std::move(n)) {}
|
||||
virtual ~BaseType() = default;
|
||||
};
|
||||
|
||||
bool isAny() const
|
||||
class FuncType : public BaseType
|
||||
{
|
||||
public:
|
||||
DynArray<Type> paramTypes;
|
||||
Type retType;
|
||||
FuncType(DynArray<Type> params, Type ret) :
|
||||
BaseType(TypeTag::Function, "Function"), paramTypes(std::move(params)), retType(ret)
|
||||
{
|
||||
return tag == TypeTag::Any;
|
||||
}
|
||||
|
||||
bool isNull() const
|
||||
{
|
||||
return tag == TypeTag::Null;
|
||||
}
|
||||
|
||||
bool isInt() const
|
||||
{
|
||||
return tag == TypeTag::Int;
|
||||
}
|
||||
|
||||
bool isDouble() const
|
||||
{
|
||||
return tag == TypeTag::Double;
|
||||
}
|
||||
|
||||
bool isBool() const
|
||||
{
|
||||
return tag == TypeTag::Bool;
|
||||
}
|
||||
|
||||
bool isString() const
|
||||
{
|
||||
return tag == TypeTag::String;
|
||||
}
|
||||
|
||||
bool isFunction() const
|
||||
{
|
||||
return tag == TypeTag::Function;
|
||||
}
|
||||
|
||||
bool isStruct() const
|
||||
{
|
||||
return tag == TypeTag::Struct;
|
||||
}
|
||||
};
|
||||
|
||||
// 全局唯一类型驻留池
|
||||
class StructType : public BaseType
|
||||
{
|
||||
public:
|
||||
struct Field
|
||||
{
|
||||
String name;
|
||||
Type type;
|
||||
bool isPublic;
|
||||
int index;
|
||||
};
|
||||
DynArray<Field> fields;
|
||||
HashMap<String, size_t> fieldMap;
|
||||
HashMap<String, class FnDefStmt *> methods;
|
||||
|
||||
StructType(String n) : BaseType(TypeTag::Struct, std::move(n)) {}
|
||||
void AddField(String name, Type type, bool isPublic)
|
||||
{
|
||||
size_t idx = fields.size();
|
||||
fields.push_back({name, type, isPublic, (int) idx});
|
||||
fieldMap[name] = idx;
|
||||
}
|
||||
};
|
||||
|
||||
class InterfaceType : public BaseType
|
||||
{
|
||||
public:
|
||||
struct MethodSig
|
||||
{
|
||||
String name;
|
||||
DynArray<Type> params;
|
||||
Type retType;
|
||||
};
|
||||
HashMap<String, MethodSig> methods;
|
||||
InterfaceType(String n) : BaseType(TypeTag::Interface, std::move(n)) {}
|
||||
};
|
||||
|
||||
class TypeContext
|
||||
{
|
||||
private:
|
||||
DynArray<TypeInfo *> allTypes;
|
||||
|
||||
// 缓存
|
||||
TypeInfo *typeAny;
|
||||
TypeInfo *typeNull;
|
||||
TypeInfo *typeInt;
|
||||
TypeInfo *typeDouble;
|
||||
TypeInfo *typeBool;
|
||||
TypeInfo *typeString;
|
||||
TypeInfo *typeFunction;
|
||||
TypeInfo *typeStruct;
|
||||
|
||||
public:
|
||||
TypeInfo *GetAny()
|
||||
{
|
||||
return typeAny;
|
||||
}
|
||||
TypeInfo *GetNull()
|
||||
{
|
||||
return typeNull;
|
||||
}
|
||||
TypeInfo *GetInt()
|
||||
{
|
||||
return typeInt;
|
||||
}
|
||||
TypeInfo *GetDouble()
|
||||
{
|
||||
return typeDouble;
|
||||
}
|
||||
TypeInfo *GetBool()
|
||||
{
|
||||
return typeBool;
|
||||
}
|
||||
TypeInfo *GetString()
|
||||
{
|
||||
return typeString;
|
||||
}
|
||||
TypeInfo *GetFunction()
|
||||
{
|
||||
return typeFunction;
|
||||
}
|
||||
TypeInfo *GetStruct()
|
||||
{
|
||||
return typeStruct;
|
||||
}
|
||||
DynArray<BaseType *> allTypes;
|
||||
BaseType *intType, *doubleType, *stringType, *boolType, *anyType, *nullType;
|
||||
|
||||
TypeInfo *ResolveTypePath(const String &fullName)
|
||||
{
|
||||
for (auto *t : allTypes)
|
||||
{
|
||||
if (t->name == fullName)
|
||||
return t;
|
||||
}
|
||||
return nullptr; // 没找到该类型
|
||||
}
|
||||
|
||||
TypeInfo *ResolveTypePath(const DynArray<String> &path)
|
||||
{
|
||||
// TODO: 支持Module 系统, 查 Module 的导出表
|
||||
String fullName = path.empty() ? "" : path[0];
|
||||
for (size_t i = 1; i < path.size(); ++i)
|
||||
{
|
||||
fullName += "." + path[i];
|
||||
}
|
||||
|
||||
return ResolveTypePath(fullName);
|
||||
}
|
||||
|
||||
~TypeContext()
|
||||
{
|
||||
for (TypeInfo *t : allTypes)
|
||||
delete t;
|
||||
}
|
||||
|
||||
TypeContext()
|
||||
{
|
||||
typeAny = createBuiltin(TypeTag::Any, "Any");
|
||||
typeNull = createBuiltin(TypeTag::Null, "Null");
|
||||
typeInt = createBuiltin(TypeTag::Int, "Int");
|
||||
typeDouble = createBuiltin(TypeTag::Double, "Double");
|
||||
typeBool = createBuiltin(TypeTag::Bool, "Bool");
|
||||
typeString = createBuiltin(TypeTag::String, "String");
|
||||
typeFunction = createBuiltin(TypeTag::Function, "Function");
|
||||
typeStruct = createBuiltin(TypeTag::Struct, "Struct");
|
||||
}
|
||||
|
||||
private:
|
||||
TypeInfo *createBuiltin(TypeTag tag, String name)
|
||||
{
|
||||
TypeInfo *t = new TypeInfo{tag, std::move(name)};
|
||||
allTypes.push_back(t);
|
||||
return t;
|
||||
}
|
||||
TypeContext();
|
||||
~TypeContext();
|
||||
|
||||
Type GetBasic(TypeTag tag, bool nullable = false);
|
||||
Type CreateFuncType(DynArray<Type> params, Type ret);
|
||||
};
|
||||
}; // namespace Fig
|
||||
} // namespace Fig
|
||||
|
||||
Reference in New Issue
Block a user