feat: 增加函数类型表达式支持,更新解析器和分析器
This commit is contained in:
@@ -48,7 +48,8 @@ namespace Fig
|
||||
/* Type Expressions */
|
||||
TypeExpr,
|
||||
NamedTypeExpr,
|
||||
NullableTypeExpr
|
||||
NullableTypeExpr,
|
||||
FnTypeExpr,
|
||||
};
|
||||
|
||||
struct AstNode
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
10
src/main.cpp
10
src/main.cpp
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user