feat: 增加函数类型表达式支持,更新解析器和分析器

This commit is contained in:
2026-03-18 17:30:09 +08:00
parent e1d9812f92
commit 570a87c3cd
10 changed files with 228 additions and 35 deletions

View File

@@ -48,7 +48,8 @@ namespace Fig
/* Type Expressions */
TypeExpr,
NamedTypeExpr,
NullableTypeExpr
NullableTypeExpr,
FnTypeExpr,
};
struct AstNode

View File

@@ -64,4 +64,37 @@ namespace Fig
return std::format("<NullableTypeExpr '{}?'>", inner->toString());
}
};
struct FnTypeExpr final : public TypeExpr
{
// func (paratypes...) -> return_type
DynArray<TypeExpr *> paraTypes;
TypeExpr *returnType;
FnTypeExpr(DynArray<TypeExpr *> _paraTypes, TypeExpr *_returnType) :
paraTypes(std::move(_paraTypes)), returnType(_returnType)
{
type = AstType::FnTypeExpr;
}
virtual String toString() const override
{
String detail = "<FnTypeExpr 'func (";
for (auto &pt : paraTypes)
{
if (pt != paraTypes.front())
{
detail += ", ";
}
detail += pt->toString();
}
detail += ") -> ";
detail += returnType->toString();
detail += "'>";
return detail;
}
};
} // namespace Fig

View File

@@ -130,6 +130,7 @@ namespace Fig
ParsingBreak,
ParsingContinue,
ParsingNamedTypeExpr,
ParsingFnTypeExpr,
} type = StateType::Standby;
std::unordered_set<TokenType> stopAt = {};
};
@@ -228,6 +229,7 @@ namespace Fig
Result<TypeExpr *, Error> parseTypeExpr();
Result<TypeExpr *, Error> parseNamedTypeExpr();
Result<TypeExpr *, Error> parseFnTypeExpr();
Result<Expr *, Error> parseExpression(BindingPower = 0);
Result<Expr *, Error> parseLiteralExpr();

View File

@@ -25,9 +25,11 @@ namespace Fig
if (match(TokenType::Dot))
{
if (!currentToken().isIdentifier())
return std::unexpected(makeUnexpectTokenError("Type", "identifier", currentToken()));
return std::unexpected(
makeUnexpectTokenError("Type", "identifier", currentToken()));
}
else break;
else
break;
}
DynArray<TypeExpr *> arguments;
@@ -36,38 +38,108 @@ namespace Fig
while (true)
{
auto result = parseTypeExpr();
if (!result) return std::unexpected(result.error());
if (!result)
return std::unexpected(result.error());
arguments.push_back(*result);
if (match(TokenType::Greater)) break; // `>`
if (match(TokenType::Greater))
break; // `>`
if (!match(TokenType::Comma))
return std::unexpected(makeUnexpectTokenError("TypeArgs", "'>' or ','", currentToken()));
return std::unexpected(
makeUnexpectTokenError("TypeArgs", "'>' or ','", currentToken()));
}
}
return arena.Allocate<NamedTypeExpr>(path, arguments, location);
}
Result<TypeExpr *, Error> Parser::parseFnTypeExpr()
{
StateProtector p(this, {State::ParsingFnTypeExpr});
SourceLocation location = makeSourceLocation(consumeToken()); // consume `func`
if (!match(TokenType::LeftParen)) // `(`
{
return std::unexpected(
makeUnexpectTokenError("FnTypeExpr", "lparen (", currentToken()));
}
DynArray<TypeExpr *> paraTypes;
while (true)
{
auto result = parseTypeExpr();
if (!result)
{
return result;
}
paraTypes.push_back(*result);
if (match(TokenType::RightParen))
{
break;
}
else if (isEOF)
{
return std::unexpected(
makeUnexpectTokenError("FnTypeExpr", "rparen )", currentToken()));
}
if (!match(TokenType::Comma))
{
return std::unexpected(
makeUnexpectTokenError("FnTypeExpr", "comma ,", currentToken()));
}
}
TypeExpr *returnType = nullptr;
if (match(TokenType::RightArrow)) // ->
{
auto result = parseTypeExpr();
if (!result)
{
return result;
}
returnType = *result;
}
FnTypeExpr *fnTypeExpr = arena.Allocate<FnTypeExpr>(paraTypes, returnType);
return fnTypeExpr;
}
// 解析主入口: 处理 `?` 后缀
Result<TypeExpr *, Error> Parser::parseTypeExpr()
{
TypeExpr *base = nullptr;
// 目前只支持命名类型 (以后可以加函数类型 (Int)->Int)
if (currentToken().isIdentifier())
{
auto res = parseNamedTypeExpr();
if (!res) return std::unexpected(res.error());
base = *res;
}
else return std::unexpected(makeUnexpectTokenError("TypeExpr", "name", currentToken()));
// 空安全处理: Int?? 也可以,但 Analyzer 会规范化它
while (match(TokenType::Question))
auto result = parseNamedTypeExpr();
if (!result)
{
base = arena.Allocate<NullableTypeExpr>(base, makeSourceLocation(prevToken()));
return result;
}
base = *result;
}
else if (currentToken().type == TokenType::Function)
{
auto result = parseFnTypeExpr();
if (!result)
{
return result;
}
base = *result;
}
else
{
return std::unexpected(makeUnexpectTokenError("TypeExpr", "name", currentToken()));
}
// type (?)
if (currentToken().type == TokenType::Question) // ?
{
base = arena.Allocate<NullableTypeExpr>(base, makeSourceLocation(consumeToken())); // consume `?`
}
return base;
}
}
} // namespace Fig

View File

@@ -345,7 +345,7 @@ namespace Fig
return std::unexpected(res.error());
retT = *res;
}
// 🔥 强类型校验:返回值拦截
// 返回值拦截校验
if (state.currentFn && !retT.isAssignableTo(state.currentFn->resolvedReturnType))
{
return std::unexpected(Error(ErrorType::TypeError,
@@ -513,10 +513,10 @@ namespace Fig
auto *ft = static_cast<FuncType *>(calleeType.base);
if (ft->paramTypes.size() != argTypes.size())
{
return std::unexpected(Error(ErrorType::TypeError,
"expected " + std::to_string(ft->paramTypes.size()) + " arguments, got "
+ std::to_string(argTypes.size()),
"",
return std::unexpected(Error(ErrorType::SyntaxError,
std::format(
"expected {} arguments, go {}", ft->paramTypes.size(), argTypes.size()),
"none",
c->location));
}
for (size_t i = 0; i < argTypes.size(); ++i)
@@ -607,13 +607,46 @@ namespace Fig
return std::unexpected(
Error(ErrorType::UseUndeclaredIdentifier, "unknown type", "", texpr->location));
}
if (texpr->type == AstType::NullableTypeExpr)
else if (texpr->type == AstType::NullableTypeExpr)
{
auto res = resolveTypeExpr(static_cast<NullableTypeExpr *>(texpr)->inner);
if (res)
if (!res)
{
return res;
}
res->isNullable = true;
return res;
}
else if (texpr->type == AstType::FnTypeExpr)
{
auto f = static_cast<FnTypeExpr *>(texpr);
DynArray<Type> paraTypes;
Type returnType = typeCtx.GetBasic(TypeTag::Any);
for (auto &pt : f->paraTypes)
{
auto result = resolveTypeExpr(pt);
if (!result)
{
return result;
}
paraTypes.push_back(*result);
}
if (f->returnType)
{
auto result = resolveTypeExpr(f->returnType);
if (!result)
{
return result;
}
returnType = *result;
}
return typeCtx.CreateFuncType(paraTypes, returnType);
}
return typeCtx.GetBasic(TypeTag::Any);
}
} // namespace Fig

View File

@@ -39,10 +39,15 @@ namespace Fig
bool Type::isAssignableTo(const Type &target) const
{
if (target.is(TypeTag::Any) || this->is(TypeTag::Any))
return true; // Any 逃逸通道
{
return true; // Any 逃逸
}
if (this->is(TypeTag::Null) && target.isNullable)
{
return true; // Null 安全赋值
return this->base == target.base && (!this->isNullable || target.isNullable);
}
return *this->base == *target.base && (!this->isNullable || target.isNullable);
}
TypeContext::TypeContext()
@@ -65,8 +70,10 @@ namespace Fig
TypeContext::~TypeContext()
{
for (auto t : allTypes)
{
delete t;
}
}
Type TypeContext::GetBasic(TypeTag tag, bool nullable)
{

View File

@@ -51,6 +51,11 @@ namespace Fig
String name;
BaseType(TypeTag t, String n) : tag(t), name(std::move(n)) {}
virtual ~BaseType() = default;
bool operator==(const BaseType &other) const
{
return tag == other.tag && name == other.name;
}
};
class FuncType : public BaseType
@@ -62,6 +67,11 @@ namespace Fig
BaseType(TypeTag::Function, "Function"), paramTypes(std::move(params)), retType(ret)
{
}
bool operator==(const FuncType &other) const
{
return paramTypes == other.paramTypes && retType == other.retType;
}
};
class StructType : public BaseType
@@ -85,6 +95,11 @@ namespace Fig
fields.push_back({name, type, isPublic, (int) idx});
fieldMap[name] = idx;
}
bool operator==(const StructType &other) const
{
return this == &other; // 即使是两个完全一样的struct, 也认作不同的type
}
};
class InterfaceType : public BaseType
@@ -98,6 +113,11 @@ namespace Fig
};
HashMap<String, MethodSig> methods;
InterfaceType(String n) : BaseType(TypeTag::Interface, std::move(n)) {}
bool operator==(const InterfaceType &other) const
{
return this == &other; // 即使是两个完全一样的interface, 也认作不同的type
}
};
class TypeContext

View File

@@ -5,7 +5,6 @@
@date 2026-03-13
*/
#include <VM/Entry.hpp>
#include <filesystem>
@@ -13,15 +12,17 @@
#include <Core/Core.hpp>
#include <SourceManager/SourceManager.hpp>
#include <Bytecode/Disassembler.hpp>
#include <Compiler/Compiler.hpp>
#include <Lexer/Lexer.hpp>
#include <Parser/Parser.hpp>
#include <Sema/Analyzer.hpp>
#include <Compiler/Compiler.hpp>
#include <VM/VM.hpp>
namespace Fig::Entry
{
void RunFromPath(const String &path)
void RunFromPath(const String &path, const Config &conf)
{
namespace fs = std::filesystem;
@@ -86,6 +87,13 @@ namespace Fig::Entry
CompiledModule *compiledModule = *compile_result;
if (conf.dump)
{
Disassembler disassembler;
disassembler.DisassembleModule(compiledModule);
return;
}
VM vm;
auto execute_result = vm.Execute(compiledModule);

View File

@@ -9,5 +9,14 @@
namespace Fig::Entry
{
void RunFromPath(const String &);
struct Config
{
enum Mode
{
Debug,
Normal
} mode;
bool dump;
};
void RunFromPath(const String &, const Config &conf);
};

View File

@@ -22,6 +22,7 @@ int main(int argc, char **argv)
argparser.AddFlag('h', "help").Help("Print the help message");
argparser.AddFlag('v', "version").Help("Show toolchain version");
argparser.AddFlag("license").Help("Print the license text");
argparser.AddFlag("dump").Help("Dump the bytecode");
auto res = argparser.Parse(argc, argv);
if (!res)
@@ -35,6 +36,7 @@ int main(int argc, char **argv)
bool showHelp = args.HasFlag("help");
bool showVersion = args.HasFlag("version");
bool showLicense = args.HasFlag("license");
bool dump = args.HasFlag("dump");
if (showHelp)
{
@@ -77,8 +79,14 @@ int main(int argc, char **argv)
return 1;
}
Entry::Config config
{
.mode = Entry::Config::Normal,
.dump = dump
};
const String &path = positionals.front();
Entry::RunFromPath(path);
Entry::RunFromPath(path, config);
return 0;
}