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 */ /* Type Expressions */
TypeExpr, TypeExpr,
NamedTypeExpr, NamedTypeExpr,
NullableTypeExpr NullableTypeExpr,
FnTypeExpr,
}; };
struct AstNode struct AstNode

View File

@@ -64,4 +64,37 @@ namespace Fig
return std::format("<NullableTypeExpr '{}?'>", inner->toString()); 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 } // namespace Fig

View File

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

View File

@@ -25,9 +25,11 @@ namespace Fig
if (match(TokenType::Dot)) if (match(TokenType::Dot))
{ {
if (!currentToken().isIdentifier()) if (!currentToken().isIdentifier())
return std::unexpected(makeUnexpectTokenError("Type", "identifier", currentToken())); return std::unexpected(
makeUnexpectTokenError("Type", "identifier", currentToken()));
} }
else break; else
break;
} }
DynArray<TypeExpr *> arguments; DynArray<TypeExpr *> arguments;
@@ -36,38 +38,108 @@ namespace Fig
while (true) while (true)
{ {
auto result = parseTypeExpr(); auto result = parseTypeExpr();
if (!result) return std::unexpected(result.error()); if (!result)
return std::unexpected(result.error());
arguments.push_back(*result); arguments.push_back(*result);
if (match(TokenType::Greater)) break; // `>` if (match(TokenType::Greater))
break; // `>`
if (!match(TokenType::Comma)) 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); 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() Result<TypeExpr *, Error> Parser::parseTypeExpr()
{ {
TypeExpr *base = nullptr; TypeExpr *base = nullptr;
// 目前只支持命名类型 (以后可以加函数类型 (Int)->Int)
if (currentToken().isIdentifier()) if (currentToken().isIdentifier())
{ {
auto res = parseNamedTypeExpr(); auto result = parseNamedTypeExpr();
if (!res) return std::unexpected(res.error()); if (!result)
base = *res; {
return result;
}
base = *result;
} }
else return std::unexpected(makeUnexpectTokenError("TypeExpr", "name", currentToken())); else if (currentToken().type == TokenType::Function)
// 空安全处理: Int?? 也可以,但 Analyzer 会规范化它
while (match(TokenType::Question))
{ {
base = arena.Allocate<NullableTypeExpr>(base, makeSourceLocation(prevToken())); 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; return base;
} }
} } // namespace Fig

View File

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

View File

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

View File

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

View File

@@ -5,7 +5,6 @@
@date 2026-03-13 @date 2026-03-13
*/ */
#include <VM/Entry.hpp> #include <VM/Entry.hpp>
#include <filesystem> #include <filesystem>
@@ -13,15 +12,17 @@
#include <Core/Core.hpp> #include <Core/Core.hpp>
#include <SourceManager/SourceManager.hpp> #include <SourceManager/SourceManager.hpp>
#include <Bytecode/Disassembler.hpp>
#include <Compiler/Compiler.hpp>
#include <Lexer/Lexer.hpp> #include <Lexer/Lexer.hpp>
#include <Parser/Parser.hpp> #include <Parser/Parser.hpp>
#include <Sema/Analyzer.hpp> #include <Sema/Analyzer.hpp>
#include <Compiler/Compiler.hpp>
#include <VM/VM.hpp> #include <VM/VM.hpp>
namespace Fig::Entry namespace Fig::Entry
{ {
void RunFromPath(const String &path) void RunFromPath(const String &path, const Config &conf)
{ {
namespace fs = std::filesystem; namespace fs = std::filesystem;
@@ -52,7 +53,7 @@ namespace Fig::Entry
const String &source = manager.GetSource(); const String &source = manager.GetSource();
Lexer lexer(source, fileName); Lexer lexer(source, fileName);
Parser parser(lexer, manager, fileName); Parser parser(lexer, manager, fileName);
auto parse_result = parser.Parse(); auto parse_result = parser.Parse();
@@ -64,7 +65,7 @@ namespace Fig::Entry
Program *program = *parse_result; Program *program = *parse_result;
Analyzer analyer(manager); Analyzer analyer(manager);
auto analyze_result = analyer.Analyze(program); auto analyze_result = analyer.Analyze(program);
if (!analyze_result) if (!analyze_result)
{ {
@@ -73,7 +74,7 @@ namespace Fig::Entry
} }
Diagnostics diagnostics; Diagnostics diagnostics;
Compiler compiler(manager, diagnostics); Compiler compiler(manager, diagnostics);
auto compile_result = compiler.Compile(program); auto compile_result = compiler.Compile(program);
diagnostics.EmitAll(manager); diagnostics.EmitAll(manager);
@@ -86,6 +87,13 @@ namespace Fig::Entry
CompiledModule *compiledModule = *compile_result; CompiledModule *compiledModule = *compile_result;
if (conf.dump)
{
Disassembler disassembler;
disassembler.DisassembleModule(compiledModule);
return;
}
VM vm; VM vm;
auto execute_result = vm.Execute(compiledModule); auto execute_result = vm.Execute(compiledModule);

View File

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