feat: 增加函数类型表达式支持,更新解析器和分析器
This commit is contained in:
@@ -48,7 +48,8 @@ namespace Fig
|
|||||||
/* Type Expressions */
|
/* Type Expressions */
|
||||||
TypeExpr,
|
TypeExpr,
|
||||||
NamedTypeExpr,
|
NamedTypeExpr,
|
||||||
NullableTypeExpr
|
NullableTypeExpr,
|
||||||
|
FnTypeExpr,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AstNode
|
struct AstNode
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
else return std::unexpected(makeUnexpectTokenError("TypeExpr", "name", currentToken()));
|
|
||||||
|
|
||||||
// 空安全处理: Int?? 也可以,但 Analyzer 会规范化它
|
|
||||||
while (match(TokenType::Question))
|
|
||||||
{
|
{
|
||||||
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;
|
return base;
|
||||||
}
|
}
|
||||||
}
|
} // namespace Fig
|
||||||
|
|||||||
@@ -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)
|
||||||
|
{
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
res->isNullable = true;
|
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
|
||||||
@@ -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,8 +70,10 @@ 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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
};
|
};
|
||||||
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('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;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user