feat: 在解析器中实现 Lambda 和 new 表达式
- 增加了对 Lambda 表达式的初步解析支持,包括参数处理和返回类型。Lambda闭包尚未支持。 - 引入了用于对象初始化的新的表达式,支持可选的命名参数。 - 改进了表达式语法错误的错误报告。 - 更新了解析器和分析器以处理新的表达式类型并验证其语义。 - 修改了现有测试以涵盖新功能并确保其正确性。 - 改进了各种解析和语义错误的诊断。
This commit is contained in:
@@ -6,7 +6,7 @@ Language: Cpp
|
|||||||
AccessModifierOffset: -4
|
AccessModifierOffset: -4
|
||||||
|
|
||||||
# 开括号(开圆括号、开尖括号、开方括号)后的对齐: Align, DontAlign, AlwaysBreak(总是在开括号后换行)
|
# 开括号(开圆括号、开尖括号、开方括号)后的对齐: Align, DontAlign, AlwaysBreak(总是在开括号后换行)
|
||||||
AlignAfterOpenBracket: DontAlign
|
AlignAfterOpenBracket: AlwaysBreak
|
||||||
|
|
||||||
# 连续赋值时,对齐所有等号
|
# 连续赋值时,对齐所有等号
|
||||||
AlignConsecutiveAssignments: true
|
AlignConsecutiveAssignments: true
|
||||||
|
|||||||
@@ -11,13 +11,19 @@
|
|||||||
#include <Ast/Expr/IdentiExpr.hpp>
|
#include <Ast/Expr/IdentiExpr.hpp>
|
||||||
#include <Ast/Expr/IndexExpr.hpp>
|
#include <Ast/Expr/IndexExpr.hpp>
|
||||||
#include <Ast/Expr/InfixExpr.hpp>
|
#include <Ast/Expr/InfixExpr.hpp>
|
||||||
|
#include <Ast/Expr/LambdaExpr.hpp>
|
||||||
#include <Ast/Expr/LiteralExpr.hpp>
|
#include <Ast/Expr/LiteralExpr.hpp>
|
||||||
|
#include <Ast/Expr/MemberExpr.hpp>
|
||||||
|
#include <Ast/Expr/NewExpr.hpp>
|
||||||
#include <Ast/Expr/PrefixExpr.hpp>
|
#include <Ast/Expr/PrefixExpr.hpp>
|
||||||
|
|
||||||
#include <Ast/Stmt/ControlFlowStmts.hpp>
|
#include <Ast/Stmt/ControlFlowStmts.hpp>
|
||||||
#include <Ast/Stmt/ExprStmt.hpp>
|
#include <Ast/Stmt/ExprStmt.hpp>
|
||||||
#include <Ast/Stmt/FnDefStmt.hpp>
|
#include <Ast/Stmt/FnDefStmt.hpp>
|
||||||
#include <Ast/Stmt/IfStmt.hpp>
|
#include <Ast/Stmt/IfStmt.hpp>
|
||||||
|
#include <Ast/Stmt/ImplStmt.hpp>
|
||||||
|
#include <Ast/Stmt/InterfaceDefStmt.hpp>
|
||||||
|
#include <Ast/Stmt/StructDefStmt.hpp>
|
||||||
#include <Ast/Stmt/VarDecl.hpp>
|
#include <Ast/Stmt/VarDecl.hpp>
|
||||||
#include <Ast/Stmt/WhileStmt.hpp>
|
#include <Ast/Stmt/WhileStmt.hpp>
|
||||||
#include <Ast/TypeExpr.hpp>
|
#include <Ast/TypeExpr.hpp>
|
||||||
@@ -29,7 +29,8 @@ namespace Fig
|
|||||||
IndexExpr,
|
IndexExpr,
|
||||||
CallExpr,
|
CallExpr,
|
||||||
MemberExpr, // obj.prop
|
MemberExpr, // obj.prop
|
||||||
ObjectInitExpr, // new Point{}
|
NewExpr, // new Point{}
|
||||||
|
LambdaExpr,
|
||||||
|
|
||||||
/* Statements */
|
/* Statements */
|
||||||
ExprStmt,
|
ExprStmt,
|
||||||
|
|||||||
@@ -47,9 +47,10 @@ namespace Fig
|
|||||||
type = AstType::CallExpr;
|
type = AstType::CallExpr;
|
||||||
}
|
}
|
||||||
|
|
||||||
CallExpr(Expr *_callee, FnCallArgs _args) : callee(_callee), args(std::move(_args))
|
CallExpr(Expr *_callee, FnCallArgs _args, SourceLocation _location) : callee(_callee), args(std::move(_args))
|
||||||
{
|
{
|
||||||
type = AstType::CallExpr;
|
type = AstType::CallExpr;
|
||||||
|
location = std::move(_location);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual String toString() const override
|
virtual String toString() const override
|
||||||
|
|||||||
70
src/Ast/Expr/LambdaExpr.hpp
Normal file
70
src/Ast/Expr/LambdaExpr.hpp
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
/*!
|
||||||
|
@file src/Ast/Expr/LambdaExpr.hpp
|
||||||
|
@brief Lambda表达式定义
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Ast/Base.hpp>
|
||||||
|
#include <Ast/Stmt/FnDefStmt.hpp>
|
||||||
|
|
||||||
|
namespace Fig
|
||||||
|
{
|
||||||
|
struct LambdaExpr final : public Expr
|
||||||
|
{
|
||||||
|
// func (params) [-> return type] ([=> expr] / [ {stmt} ])
|
||||||
|
|
||||||
|
DynArray<Param *> params;
|
||||||
|
TypeExpr *returnType;
|
||||||
|
AstNode *body; // expr/blockstmt
|
||||||
|
bool isExprBody;
|
||||||
|
|
||||||
|
DynArray<UpvalueInfo> upvalues;
|
||||||
|
|
||||||
|
LambdaExpr()
|
||||||
|
{
|
||||||
|
type = AstType::LambdaExpr;
|
||||||
|
}
|
||||||
|
|
||||||
|
LambdaExpr(
|
||||||
|
DynArray<Param *> _params,
|
||||||
|
TypeExpr *_returnType,
|
||||||
|
AstNode *_body,
|
||||||
|
bool _isExprBody,
|
||||||
|
SourceLocation _location) :
|
||||||
|
params(std::move(_params)),
|
||||||
|
returnType(_returnType),
|
||||||
|
body(_body),
|
||||||
|
isExprBody(_isExprBody)
|
||||||
|
{
|
||||||
|
type = AstType::LambdaExpr;
|
||||||
|
location = std::move(_location);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual String toString() const override
|
||||||
|
{
|
||||||
|
String specifying = "<LambdaExpr 'func (";
|
||||||
|
for (auto &p : params)
|
||||||
|
{
|
||||||
|
if (p != params.front())
|
||||||
|
{
|
||||||
|
specifying += ", ";
|
||||||
|
}
|
||||||
|
specifying += p->toString();
|
||||||
|
}
|
||||||
|
if (isExprBody)
|
||||||
|
{
|
||||||
|
specifying += ") => ";
|
||||||
|
specifying += body->toString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
specifying += ") {";
|
||||||
|
specifying += body->toString();
|
||||||
|
specifying.push_back(U'}');
|
||||||
|
}
|
||||||
|
specifying += "'>";
|
||||||
|
return specifying;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}; // namespace Fig
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
struct ObjectInitExpr final : public Expr
|
struct NewExpr final : public Expr
|
||||||
{
|
{
|
||||||
struct Arg
|
struct Arg
|
||||||
{
|
{
|
||||||
@@ -21,20 +21,20 @@ namespace Fig
|
|||||||
TypeExpr *typeExpr;
|
TypeExpr *typeExpr;
|
||||||
DynArray<Arg> args;
|
DynArray<Arg> args;
|
||||||
|
|
||||||
ObjectInitExpr()
|
NewExpr()
|
||||||
{
|
{
|
||||||
type = AstType::ObjectInitExpr;
|
type = AstType::NewExpr;
|
||||||
}
|
}
|
||||||
ObjectInitExpr(TypeExpr *_te, DynArray<Arg> _args, SourceLocation _loc) :
|
NewExpr(TypeExpr *_te, DynArray<Arg> _args, SourceLocation _loc) :
|
||||||
typeExpr(_te), args(std::move(_args))
|
typeExpr(_te), args(std::move(_args))
|
||||||
{
|
{
|
||||||
type = AstType::ObjectInitExpr;
|
type = AstType::NewExpr;
|
||||||
location = std::move(_loc);
|
location = std::move(_loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual String toString() const override
|
virtual String toString() const override
|
||||||
{
|
{
|
||||||
String res = "<ObjectInitExpr 'new " + typeExpr->toString() + "{";
|
String res = "<NewExpr 'new " + typeExpr->toString() + "{";
|
||||||
for (size_t i = 0; i < args.size(); ++i)
|
for (size_t i = 0; i < args.size(); ++i)
|
||||||
{
|
{
|
||||||
if (!args[i].name.empty())
|
if (!args[i].name.empty())
|
||||||
@@ -13,9 +13,12 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
struct Field
|
struct Field
|
||||||
{
|
{
|
||||||
|
bool isPublic;
|
||||||
|
bool typeInfer;
|
||||||
|
|
||||||
String name;
|
String name;
|
||||||
TypeExpr *type;
|
TypeExpr *type;
|
||||||
bool isPublic;
|
Expr *initExpr;
|
||||||
};
|
};
|
||||||
bool isPublic;
|
bool isPublic;
|
||||||
String name;
|
String name;
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ namespace Fig
|
|||||||
stream << std::format(" [{}] {}\n", i, proto->constants[i].ToString());
|
stream << std::format(" [{}] {}\n", i, proto->constants[i].ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
stream << "--- End Disassembly ---";
|
||||||
}
|
}
|
||||||
|
|
||||||
Disassembler::Format Disassembler::GetFormat(OpCode op)
|
Disassembler::Format Disassembler::GetFormat(OpCode op)
|
||||||
|
|||||||
@@ -27,7 +27,11 @@ int main()
|
|||||||
}
|
}
|
||||||
|
|
||||||
Lexer lexer(source, filePath);
|
Lexer lexer(source, filePath);
|
||||||
Parser parser(lexer, sm, filePath);
|
|
||||||
|
Diagnostics diagnostics;
|
||||||
|
Parser parser(lexer, sm, filePath, diagnostics);
|
||||||
|
|
||||||
|
diagnostics.EmitAll(sm);
|
||||||
|
|
||||||
auto pRes = parser.Parse();
|
auto pRes = parser.Parse();
|
||||||
if (!pRes)
|
if (!pRes)
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
#include <limits>
|
#include <limits>
|
||||||
#include <system_error>
|
#include <system_error>
|
||||||
|
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
static Result<Value, Error> parsePhysicalNumber(const String &raw, const SourceLocation &loc)
|
static Result<Value, Error> parsePhysicalNumber(const String &raw, const SourceLocation &loc)
|
||||||
@@ -94,7 +93,9 @@ namespace Fig
|
|||||||
parsePhysicalNumber(manager.GetSub(tok.index, tok.length), l->location);
|
parsePhysicalNumber(manager.GetSub(tok.index, tok.length), l->location);
|
||||||
if (!vRes)
|
if (!vRes)
|
||||||
return std::unexpected(vRes.error());
|
return std::unexpected(vRes.error());
|
||||||
emit(Op::iABx(OpCode::LoadK, r, static_cast<uint16_t>(addConstant(*vRes))), &l->location);
|
emit(
|
||||||
|
Op::iABx(OpCode::LoadK, r, static_cast<uint16_t>(addConstant(*vRes))),
|
||||||
|
&l->location);
|
||||||
}
|
}
|
||||||
else if (tok.type == TokenType::LiteralString)
|
else if (tok.type == TokenType::LiteralString)
|
||||||
{
|
{
|
||||||
@@ -129,7 +130,9 @@ namespace Fig
|
|||||||
// 仅在被强制指定目标(如参数装填)时发射搬运指令
|
// 仅在被强制指定目标(如参数装填)时发射搬运指令
|
||||||
if (target != sym->index)
|
if (target != sym->index)
|
||||||
{
|
{
|
||||||
emit(Op::iABx(OpCode::Mov, target, static_cast<uint16_t>(sym->index)), &i->location);
|
emit(
|
||||||
|
Op::iABx(OpCode::Mov, target, static_cast<uint16_t>(sym->index)),
|
||||||
|
&i->location);
|
||||||
}
|
}
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
@@ -137,7 +140,9 @@ namespace Fig
|
|||||||
Register r = (target == NO_REG) ? *allocateReg(i->location) : target;
|
Register r = (target == NO_REG) ? *allocateReg(i->location) : target;
|
||||||
if (sym->location == SymbolLocation::Upvalue)
|
if (sym->location == SymbolLocation::Upvalue)
|
||||||
{
|
{
|
||||||
emit(Op::iABC(OpCode::GetUpval, r, static_cast<uint8_t>(sym->index), 0), &i->location);
|
emit(
|
||||||
|
Op::iABC(OpCode::GetUpval, r, static_cast<uint8_t>(sym->index), 0),
|
||||||
|
&i->location);
|
||||||
}
|
}
|
||||||
else if (sym->location == SymbolLocation::Global)
|
else if (sym->location == SymbolLocation::Global)
|
||||||
{
|
{
|
||||||
@@ -176,7 +181,9 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
isGlobalFastCall = true;
|
isGlobalFastCall = true;
|
||||||
int protoIdx = id->resolvedSymbol->index;
|
int protoIdx = id->resolvedSymbol->index;
|
||||||
emit(Op::iABC(OpCode::FastCall,
|
emit(
|
||||||
|
Op::iABC(
|
||||||
|
OpCode::FastCall,
|
||||||
static_cast<uint8_t>(protoIdx),
|
static_cast<uint8_t>(protoIdx),
|
||||||
baseReg,
|
baseReg,
|
||||||
static_cast<uint8_t>(c->args.args.size())),
|
static_cast<uint8_t>(c->args.args.size())),
|
||||||
@@ -193,7 +200,9 @@ namespace Fig
|
|||||||
return std::unexpected(r_fn.error());
|
return std::unexpected(r_fn.error());
|
||||||
|
|
||||||
// 使用动态 Call 指令,RA 是指向堆闭包的寄存器
|
// 使用动态 Call 指令,RA 是指向堆闭包的寄存器
|
||||||
emit(Op::iABC(OpCode::Call,
|
emit(
|
||||||
|
Op::iABC(
|
||||||
|
OpCode::Call,
|
||||||
*r_fn,
|
*r_fn,
|
||||||
baseReg,
|
baseReg,
|
||||||
static_cast<uint8_t>(c->args.args.size())),
|
static_cast<uint8_t>(c->args.args.size())),
|
||||||
@@ -240,18 +249,25 @@ namespace Fig
|
|||||||
Symbol *sym = lid->resolvedSymbol;
|
Symbol *sym = lid->resolvedSymbol;
|
||||||
if (sym->location == SymbolLocation::Local)
|
if (sym->location == SymbolLocation::Local)
|
||||||
{
|
{
|
||||||
emit(Op::iABx(OpCode::Mov, static_cast<Register>(sym->index), *r_val), &lid->location);
|
emit(
|
||||||
|
Op::iABx(OpCode::Mov, static_cast<Register>(sym->index), *r_val),
|
||||||
|
&lid->location);
|
||||||
}
|
}
|
||||||
else if (sym->location == SymbolLocation::Upvalue)
|
else if (sym->location == SymbolLocation::Upvalue)
|
||||||
{
|
{
|
||||||
emit(Op::iABC(
|
emit(
|
||||||
OpCode::SetUpval, *r_val, static_cast<Register>(sym->index), 0), &lid->location);
|
Op::iABC(
|
||||||
|
OpCode::SetUpval, *r_val, static_cast<Register>(sym->index), 0),
|
||||||
|
&lid->location);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
emit(Op::iABx(OpCode::SetGlobal,
|
emit(
|
||||||
|
Op::iABx(
|
||||||
|
OpCode::SetGlobal,
|
||||||
*r_val,
|
*r_val,
|
||||||
static_cast<uint16_t>(getGlobalID(lid->name))), &lid->location);
|
static_cast<uint16_t>(getGlobalID(lid->name))),
|
||||||
|
&lid->location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return r_val;
|
return r_val;
|
||||||
@@ -290,7 +306,8 @@ namespace Fig
|
|||||||
case BinaryOperator::GreaterEqual: op = OpCode::GreaterEqual; break;
|
case BinaryOperator::GreaterEqual: op = OpCode::GreaterEqual; break;
|
||||||
case BinaryOperator::LessEqual: op = OpCode::LessEqual; break;
|
case BinaryOperator::LessEqual: op = OpCode::LessEqual; break;
|
||||||
default:
|
default:
|
||||||
return std::unexpected(Error(ErrorType::InternalError,
|
return std::unexpected(Error(
|
||||||
|
ErrorType::InternalError,
|
||||||
"unsupported binary operator",
|
"unsupported binary operator",
|
||||||
"",
|
"",
|
||||||
in->location));
|
in->location));
|
||||||
@@ -318,6 +335,65 @@ namespace Fig
|
|||||||
return r_d;
|
return r_d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case AstType::LambdaExpr: {
|
||||||
|
auto l = static_cast<LambdaExpr *>(expr);
|
||||||
|
|
||||||
|
Proto *proto = new Proto;
|
||||||
|
proto->name = l->toString();
|
||||||
|
|
||||||
|
FuncState fs(proto, current);
|
||||||
|
FuncState *old = current;
|
||||||
|
current = &fs;
|
||||||
|
|
||||||
|
if (l->isExprBody)
|
||||||
|
{
|
||||||
|
auto result = compileExpr(static_cast<Expr *>(l->body));
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit(Op::iABC(OpCode::Return, *result, 0, 0), &l->location);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto result = compileStmt(static_cast<BlockStmt *>(l->body));
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
return std::unexpected(result.error());
|
||||||
|
}
|
||||||
|
auto _r = allocateReg(l->body->location);
|
||||||
|
if (!_r)
|
||||||
|
{
|
||||||
|
return _r;
|
||||||
|
}
|
||||||
|
|
||||||
|
Register r = *_r;
|
||||||
|
emit(Op::iABC(OpCode::LoadNull, r, 0, 0), &l->body->location);
|
||||||
|
emit(Op::iABC(OpCode::Return, r, 0, 0), &l->body->location);
|
||||||
|
}
|
||||||
|
|
||||||
|
int protoIndex = (int) module->protos.size();
|
||||||
|
module->protos.push_back(proto);
|
||||||
|
|
||||||
|
current = old;
|
||||||
|
if (target == NO_REG)
|
||||||
|
{
|
||||||
|
auto _r = allocateReg(expr->location);
|
||||||
|
if (!_r)
|
||||||
|
{
|
||||||
|
return _r;
|
||||||
|
}
|
||||||
|
emit(Op::iABx(OpCode::LoadFn, *_r, protoIndex), &l->body->location);
|
||||||
|
return *_r;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
emit(Op::iABx(OpCode::LoadFn, target, protoIndex), &l->body->location);
|
||||||
|
}
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
return std::unexpected(
|
return std::unexpected(
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ namespace Fig
|
|||||||
ost << color << msg << TerminalColors::Reset;
|
ost << color << msg << TerminalColors::Reset;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ColoredPrint(const char *color, const std::string &msg, std::ostream &ost = CoreIO::GetStdErr())
|
void
|
||||||
|
ColoredPrint(const char *color, const std::string &msg, std::ostream &ost = CoreIO::GetStdErr())
|
||||||
{
|
{
|
||||||
ost << color << msg << TerminalColors::Reset;
|
ost << color << msg << TerminalColors::Reset;
|
||||||
}
|
}
|
||||||
@@ -30,7 +31,10 @@ namespace Fig
|
|||||||
std::string MultipleStr(const char *c, size_t n)
|
std::string MultipleStr(const char *c, size_t n)
|
||||||
{
|
{
|
||||||
std::string buf;
|
std::string buf;
|
||||||
for (size_t i = 0; i < n; ++i) { buf += c; }
|
for (size_t i = 0; i < n; ++i)
|
||||||
|
{
|
||||||
|
buf += c;
|
||||||
|
}
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,6 +44,7 @@ namespace Fig
|
|||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case UnusedSymbol: return "UnusedSymbol";
|
case UnusedSymbol: return "UnusedSymbol";
|
||||||
|
case UnnecessarySemicolon: return "UnnecessarySemicolon";
|
||||||
|
|
||||||
case MayBeNull: return "MaybeNull";
|
case MayBeNull: return "MaybeNull";
|
||||||
|
|
||||||
@@ -61,7 +66,8 @@ namespace Fig
|
|||||||
case TooManyConstants: return "TooManyConstants";
|
case TooManyConstants: return "TooManyConstants";
|
||||||
|
|
||||||
case RegisterOverflow: return "RegisterOverflow";
|
case RegisterOverflow: return "RegisterOverflow";
|
||||||
case InternalError: return "InternalError";
|
case InternalError:
|
||||||
|
return "InternalError";
|
||||||
// default: return "Some one forgot to add case to `ErrorTypeToString`";
|
// default: return "Some one forgot to add case to `ErrorTypeToString`";
|
||||||
}
|
}
|
||||||
return "UnknownError";
|
return "UnknownError";
|
||||||
@@ -71,8 +77,8 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
std::ostream &err = CoreIO::GetStdErr();
|
std::ostream &err = CoreIO::GetStdErr();
|
||||||
std::stringstream build_info;
|
std::stringstream build_info;
|
||||||
build_info << "\r🌘 Fig v" << Core::VERSION << " on " << Core::PLATFORM << ' ' << Core::ARCH << '['
|
build_info << "\r🌘 Fig v" << Core::VERSION << " on " << Core::PLATFORM << ' ' << Core::ARCH
|
||||||
<< Core::COMPILER << ']' << '\n'
|
<< '[' << Core::COMPILER << ']' << '\n'
|
||||||
<< " Build Time: " << Core::COMPILE_TIME;
|
<< " Build Time: " << Core::COMPILE_TIME;
|
||||||
|
|
||||||
const std::string &build_info_str = build_info.str();
|
const std::string &build_info_str = build_info.str();
|
||||||
@@ -92,26 +98,34 @@ namespace Fig
|
|||||||
|
|
||||||
uint8_t level = ErrorLevel(error.type);
|
uint8_t level = ErrorLevel(error.type);
|
||||||
// const char *level_name = (level == 1 ? "Minor" : (level == 2 ? "Medium" : "Critical"));
|
// const char *level_name = (level == 1 ? "Minor" : (level == 2 ? "Medium" : "Critical"));
|
||||||
const char *level_color = (level == 1 ? MinorColor : (level == 2 ? MediumColor : CriticalColor));
|
const char *level_color =
|
||||||
|
(level == 1 ? MinorColor : (level == 2 ? MediumColor : CriticalColor));
|
||||||
|
|
||||||
err << "🔥 "
|
err << "🔥 "
|
||||||
<< level_color
|
<< level_color
|
||||||
//<< '(' << level_name << ')'
|
//<< '(' << level_name << ')'
|
||||||
<< 'E' << static_cast<int>(error.type) << TC::Reset << ": " << level_color << ErrorTypeToString(error.type)
|
<< 'E' << static_cast<int>(error.type) << TC::Reset << ": " << level_color
|
||||||
<< TC::Reset << '\n';
|
<< ErrorTypeToString(error.type) << TC::Reset << '\n';
|
||||||
|
|
||||||
const SourceLocation &location = error.location;
|
const SourceLocation &location = error.location;
|
||||||
|
|
||||||
err << TC::DarkGray << " ┌─> Fn " << TC::Cyan << '\'' << location.packageName << '.' << location.functionName
|
err << TC::DarkGray << " ┌─> Fn " << TC::Cyan << '\'' << location.packageName << '.'
|
||||||
<< '\'' << " " << location.fileName << " (" << TC::DarkGray << location.sp.line << ":" << location.sp.column
|
<< location.functionName << '\'' << " " << location.fileName << " (" << TC::DarkGray
|
||||||
<< TC::Cyan << ')' << TC::Reset << '\n';
|
<< location.sp.line << ":" << location.sp.column << TC::Cyan << ')' << TC::Reset
|
||||||
|
<< '\n';
|
||||||
err << TC::DarkGray << " │" << '\n' << " │" << TC::Reset << '\n';
|
err << TC::DarkGray << " │" << '\n' << " │" << TC::Reset << '\n';
|
||||||
|
|
||||||
// 尝试打印上3行 下2行
|
// 尝试打印上3行 下2行
|
||||||
|
|
||||||
int64_t line_start = location.sp.line - 3, line_end = location.sp.line + 2;
|
int64_t line_start = location.sp.line - 3, line_end = location.sp.line + 2;
|
||||||
while (!srcManager.HasLine(line_end)) { --line_end; }
|
while (!srcManager.HasLine(line_end))
|
||||||
while (!srcManager.HasLine(line_start)) { ++line_start; }
|
{
|
||||||
|
--line_end;
|
||||||
|
}
|
||||||
|
while (!srcManager.HasLine(line_start))
|
||||||
|
{
|
||||||
|
++line_start;
|
||||||
|
}
|
||||||
|
|
||||||
const auto &getLineNumWidth = [](size_t l) {
|
const auto &getLineNumWidth = [](size_t l) {
|
||||||
unsigned int cnt = 0;
|
unsigned int cnt = 0;
|
||||||
@@ -127,30 +141,39 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
unsigned int offset = 2 + 2 + 1;
|
unsigned int offset = 2 + 2 + 1;
|
||||||
// ' └─ '
|
// ' └─ '
|
||||||
if (i == location.sp.line) { err << TC::DarkGray << " └─ " << TC::Reset; }
|
if (i == location.sp.line)
|
||||||
else if (i < location.sp.line) { err << TC::DarkGray << " │ " << TC::Reset; }
|
{
|
||||||
|
err << TC::DarkGray << " └─ " << TC::Reset;
|
||||||
|
}
|
||||||
|
else if (i < location.sp.line)
|
||||||
|
{
|
||||||
|
err << TC::DarkGray << " │ " << TC::Reset;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
err << MultipleStr(" ", offset);
|
err << MultipleStr(" ", offset);
|
||||||
}
|
}
|
||||||
unsigned int cur_line_number_width = getLineNumWidth(i);
|
unsigned int cur_line_number_width = getLineNumWidth(i);
|
||||||
|
|
||||||
err << MultipleStr(" ", max_line_number_width - cur_line_number_width) << TC::Yellow << i << TC::Reset;
|
err << MultipleStr(" ", max_line_number_width - cur_line_number_width) << TC::Yellow
|
||||||
|
<< i << TC::Reset;
|
||||||
err << " │ " << srcManager.GetLine(i) << '\n';
|
err << " │ " << srcManager.GetLine(i) << '\n';
|
||||||
if (i == location.sp.line)
|
if (i == location.sp.line)
|
||||||
{
|
{
|
||||||
unsigned int error_col_offset = offset + 1 + max_line_number_width + 2;
|
unsigned int error_col_offset = offset + 1 + max_line_number_width + 2;
|
||||||
err << MultipleStr(" ", error_col_offset) << MultipleStr(" ", location.sp.column - 1) << TC::LightGreen
|
err << MultipleStr(" ", error_col_offset)
|
||||||
|
<< MultipleStr(" ", location.sp.column - 1) << TC::LightGreen
|
||||||
<< MultipleStr("^", location.sp.tok_length) << TC::Reset << '\n';
|
<< MultipleStr("^", location.sp.tok_length) << TC::Reset << '\n';
|
||||||
|
|
||||||
err << MultipleStr(" ", error_col_offset)
|
err << MultipleStr(" ", error_col_offset)
|
||||||
<< MultipleStr(" ", location.sp.column - 1 + location.sp.tok_length / 2) << "╰─ " << level_color
|
<< MultipleStr(" ", location.sp.column - 1 + location.sp.tok_length / 2)
|
||||||
<< error.message << TC::Reset << "\n\n";
|
<< "╰─ " << level_color << error.message << TC::Reset << "\n\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err << "\n";
|
err << "\n";
|
||||||
err << "❓ " << TC::DarkGray << "Thrower: " << error.thrower_loc.function_name() << " ("
|
err << "❓ " << TC::DarkGray << "Thrower: " << error.thrower_loc.function_name() << " ("
|
||||||
<< error.thrower_loc.file_name() << ":" << error.thrower_loc.line() << ")" << TC::Reset << "\n";
|
<< error.thrower_loc.file_name() << ":" << error.thrower_loc.line() << ")" << TC::Reset
|
||||||
|
<< "\n";
|
||||||
err << "💡 " << TC::Blue << "Suggestion: " << error.suggestion << TC::Reset;
|
err << "💡 " << TC::Blue << "Suggestion: " << error.suggestion << TC::Reset;
|
||||||
err << '\n';
|
err << '\n';
|
||||||
}
|
}
|
||||||
@@ -158,7 +181,7 @@ namespace Fig
|
|||||||
void ReportError(const Error &error, const SourceManager &srcManager)
|
void ReportError(const Error &error, const SourceManager &srcManager)
|
||||||
{
|
{
|
||||||
assert(srcManager.read && "ReportError: srcManager doesn't read source");
|
assert(srcManager.read && "ReportError: srcManager doesn't read source");
|
||||||
assert(srcManager.HasLine(error.location.sp.line));
|
// assert(srcManager.HasLine(error.location.sp.line));
|
||||||
|
|
||||||
PrintSystemInfos();
|
PrintSystemInfos();
|
||||||
PrintErrorInfo(error, srcManager);
|
PrintErrorInfo(error, srcManager);
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
/* Minor */
|
/* Minor */
|
||||||
UnusedSymbol = 0,
|
UnusedSymbol = 0,
|
||||||
|
UnnecessarySemicolon,
|
||||||
|
TrailingComma,
|
||||||
|
|
||||||
/* Medium */
|
/* Medium */
|
||||||
MayBeNull = 1001,
|
MayBeNull = 1001,
|
||||||
@@ -51,7 +53,7 @@ namespace Fig
|
|||||||
TooManyLocals,
|
TooManyLocals,
|
||||||
TooManyConstants,
|
TooManyConstants,
|
||||||
|
|
||||||
// --- 新增:编译器内部与VM约束 ---
|
// 编译器内部约束
|
||||||
RegisterOverflow,
|
RegisterOverflow,
|
||||||
InternalError,
|
InternalError,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -138,9 +138,12 @@ namespace Fig
|
|||||||
manager.LoadFromMemory(sourceCode);
|
manager.LoadFromMemory(sourceCode);
|
||||||
|
|
||||||
Lexer lexer(sourceCode, "");
|
Lexer lexer(sourceCode, "");
|
||||||
Parser parser(lexer, manager, "");
|
|
||||||
|
|
||||||
// 1. 语法检查拦截
|
Diagnostics diagnostics;
|
||||||
|
|
||||||
|
Parser parser(lexer, manager, "", diagnostics);
|
||||||
|
|
||||||
|
// 语法检查拦截
|
||||||
auto parserResult = parser.Parse();
|
auto parserResult = parser.Parse();
|
||||||
if (!parserResult)
|
if (!parserResult)
|
||||||
{
|
{
|
||||||
@@ -148,6 +151,11 @@ namespace Fig
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto &diag : diagnostics.GetErrors())
|
||||||
|
{
|
||||||
|
SendDiagnostics(uri, &diag);
|
||||||
|
}
|
||||||
|
|
||||||
Program *program = *parserResult;
|
Program *program = *parserResult;
|
||||||
|
|
||||||
Analyzer analyzer(manager);
|
Analyzer analyzer(manager);
|
||||||
@@ -160,7 +168,12 @@ namespace Fig
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 一切完美,发射空数组清空过去的错误红线
|
for (auto &diag : analyzer.GetDiagnostics().GetErrors())
|
||||||
|
{
|
||||||
|
SendDiagnostics(uri, &diag);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 一切完美,发射空数组清空过去的错误红线
|
||||||
SendDiagnostics(uri, nullptr);
|
SendDiagnostics(uri, nullptr);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ namespace Fig
|
|||||||
StateProtector p(this, {State::ParsingLiteralExpr});
|
StateProtector p(this, {State::ParsingLiteralExpr});
|
||||||
|
|
||||||
const Token &literal_token = consumeToken();
|
const Token &literal_token = consumeToken();
|
||||||
LiteralExpr *node = arena.Allocate<LiteralExpr>(literal_token, makeSourceLocation(literal_token));
|
LiteralExpr *node =
|
||||||
|
arena.Allocate<LiteralExpr>(literal_token, makeSourceLocation(literal_token));
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
Result<Expr *, Error> Parser::parseIdentiExpr() // 当前token为Identifier调用
|
Result<Expr *, Error> Parser::parseIdentiExpr() // 当前token为Identifier调用
|
||||||
@@ -65,8 +66,8 @@ namespace Fig
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<Expr *, Error> Parser::parseIndexExpr(
|
Result<Expr *, Error>
|
||||||
Expr *base) // 由 parseExpression调用, 当前token为 `[`
|
Parser::parseIndexExpr(Expr *base) // 由 parseExpression调用, 当前token为 `[`
|
||||||
{
|
{
|
||||||
StateProtector p(this, {State::ParsingIndexExpr});
|
StateProtector p(this, {State::ParsingIndexExpr});
|
||||||
|
|
||||||
@@ -80,7 +81,8 @@ namespace Fig
|
|||||||
|
|
||||||
if (currentToken().type != TokenType::RightBracket) // `]`
|
if (currentToken().type != TokenType::RightBracket) // `]`
|
||||||
{
|
{
|
||||||
return std::unexpected(Error(ErrorType::SyntaxError,
|
return std::unexpected(Error(
|
||||||
|
ErrorType::SyntaxError,
|
||||||
"unclosed brackets",
|
"unclosed brackets",
|
||||||
"insert `]`",
|
"insert `]`",
|
||||||
makeSourceLocation(lbracket_token)));
|
makeSourceLocation(lbracket_token)));
|
||||||
@@ -91,12 +93,13 @@ namespace Fig
|
|||||||
return indexExpr;
|
return indexExpr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<Expr *, Error> Parser::parseCallExpr(
|
Result<Expr *, Error>
|
||||||
Expr *callee) // 由 parseExpression调用, 当前token为 `(`
|
Parser::parseCallExpr(Expr *callee) // 由 parseExpression调用, 当前token为 `(`
|
||||||
{
|
{
|
||||||
StateProtector p(this, {State::ParsingCallExpr});
|
StateProtector p(this, {State::ParsingCallExpr});
|
||||||
|
|
||||||
const Token &lparen_token = consumeToken(); // consume `(`
|
const Token &lparen_token = consumeToken(); // consume `(`
|
||||||
|
const SourceLocation &location = makeSourceLocation(lparen_token);
|
||||||
|
|
||||||
FnCallArgs callArgs;
|
FnCallArgs callArgs;
|
||||||
|
|
||||||
@@ -104,14 +107,15 @@ namespace Fig
|
|||||||
if (currentToken().type == TokenType::RightParen)
|
if (currentToken().type == TokenType::RightParen)
|
||||||
{
|
{
|
||||||
consumeToken(); // consume `)`
|
consumeToken(); // consume `)`
|
||||||
return arena.Allocate<CallExpr>(callee, callArgs);
|
return arena.Allocate<CallExpr>(callee, callArgs, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (currentToken().type == TokenType::EndOfFile)
|
if (currentToken().type == TokenType::EndOfFile)
|
||||||
{
|
{
|
||||||
return std::unexpected(Error(ErrorType::SyntaxError,
|
return std::unexpected(Error(
|
||||||
|
ErrorType::SyntaxError,
|
||||||
"fn call has unclosed parenthese",
|
"fn call has unclosed parenthese",
|
||||||
"insert `)`",
|
"insert `)`",
|
||||||
makeSourceLocation(lparen_token)));
|
makeSourceLocation(lparen_token)));
|
||||||
@@ -131,7 +135,8 @@ namespace Fig
|
|||||||
|
|
||||||
if (currentToken().type != TokenType::Comma)
|
if (currentToken().type != TokenType::Comma)
|
||||||
{
|
{
|
||||||
return std::unexpected(Error(ErrorType::SyntaxError,
|
return std::unexpected(Error(
|
||||||
|
ErrorType::SyntaxError,
|
||||||
"expected `,` or `)` in argument list",
|
"expected `,` or `)` in argument list",
|
||||||
"insert `,`",
|
"insert `,`",
|
||||||
makeSourceLocation(currentToken())));
|
makeSourceLocation(currentToken())));
|
||||||
@@ -140,7 +145,186 @@ namespace Fig
|
|||||||
consumeToken(); // consume `,`
|
consumeToken(); // consume `,`
|
||||||
}
|
}
|
||||||
|
|
||||||
return arena.Allocate<CallExpr>(callee, callArgs);
|
return arena.Allocate<CallExpr>(callee, callArgs, location);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<Expr *, Error> Parser::parseNewExpr()
|
||||||
|
{
|
||||||
|
// new type{...}
|
||||||
|
StateProtector p(this, {State::ParsingNewExpr});
|
||||||
|
|
||||||
|
SourceLocation location = makeSourceLocation(consumeToken()); // consume `new`
|
||||||
|
|
||||||
|
SET_STOP_AT(TokenType::LeftBrace); // {
|
||||||
|
auto type_result = parseTypeExpr();
|
||||||
|
if (!type_result)
|
||||||
|
{
|
||||||
|
return std::unexpected(type_result.error());
|
||||||
|
}
|
||||||
|
TypeExpr *type = *type_result;
|
||||||
|
|
||||||
|
if (!match(TokenType::LeftBrace))
|
||||||
|
{
|
||||||
|
return std::unexpected(makeUnexpectTokenError("NewExpr", "lbrace {", currentToken()));
|
||||||
|
}
|
||||||
|
|
||||||
|
const Token &lb_token = prevToken();
|
||||||
|
|
||||||
|
/*
|
||||||
|
Positional:
|
||||||
|
new Point{1, 2}
|
||||||
|
Named:
|
||||||
|
new Point{x = 1, y = 2}
|
||||||
|
*/
|
||||||
|
|
||||||
|
DynArray<NewExpr::Arg> args;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (isEOF)
|
||||||
|
{
|
||||||
|
return std::unexpected(Error(
|
||||||
|
ErrorType::SyntaxError,
|
||||||
|
"unclosed `{` in new expr",
|
||||||
|
"insert '}'",
|
||||||
|
makeSourceLocation(lb_token)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if (args.empty() && match(TokenType::RightBrace)) // 空参
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentToken().isIdentifier() && peekToken().type == TokenType::Assign)
|
||||||
|
{
|
||||||
|
const Token &name_token = consumeToken();
|
||||||
|
const String &name = srcManager.GetSub(name_token.index, name_token.length);
|
||||||
|
consumeToken(); // consume `=`
|
||||||
|
|
||||||
|
SET_STOP_AT(TokenType::Comma, TokenType::RightBrace); // , / }
|
||||||
|
auto result = parseExpression();
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
args.push_back(NewExpr::Arg{
|
||||||
|
name,
|
||||||
|
*result
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SET_STOP_AT(TokenType::Comma, TokenType::RightBrace); // , / }
|
||||||
|
auto result = parseExpression();
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
args.push_back(NewExpr::Arg{
|
||||||
|
.value = *result
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (match(TokenType::Comma))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (match(TokenType::RightBrace))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NewExpr *newExpr = arena.Allocate<NewExpr>(type, args, location);
|
||||||
|
return newExpr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<Expr *, Error> Parser::parseLambdaExpr()
|
||||||
|
{
|
||||||
|
StateProtector p(this, {State::ParsingLambdaExpr});
|
||||||
|
|
||||||
|
SourceLocation location = makeSourceLocation(consumeToken()); // consume `func`
|
||||||
|
|
||||||
|
if (currentToken().isIdentifier())
|
||||||
|
{
|
||||||
|
return std::unexpected(Error(
|
||||||
|
ErrorType::SyntaxError,
|
||||||
|
"lambda expression should not have a name",
|
||||||
|
"remove the name",
|
||||||
|
makeSourceLocation(currentToken())));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentToken().type != TokenType::LeftParen)
|
||||||
|
{
|
||||||
|
return std::unexpected(
|
||||||
|
makeUnexpectTokenError("fn def stmt", "lparen '('", currentToken()));
|
||||||
|
}
|
||||||
|
|
||||||
|
DynArray<Param *> params;
|
||||||
|
|
||||||
|
auto paraResult = parseFnParams();
|
||||||
|
if (!paraResult)
|
||||||
|
{
|
||||||
|
return std::unexpected(paraResult.error());
|
||||||
|
}
|
||||||
|
params = *paraResult;
|
||||||
|
|
||||||
|
TypeExpr *returnType = nullptr;
|
||||||
|
Token rightArrowToken;
|
||||||
|
if (match(TokenType::RightArrow)) // ->
|
||||||
|
{
|
||||||
|
rightArrowToken = consumeToken();
|
||||||
|
|
||||||
|
auto result = parseTypeExpr();
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
return std::unexpected(result.error());
|
||||||
|
}
|
||||||
|
returnType = *result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (match(TokenType::DoubleArrow)) // =>
|
||||||
|
{
|
||||||
|
if (returnType)
|
||||||
|
{
|
||||||
|
return std::unexpected(Error(
|
||||||
|
ErrorType::SyntaxError,
|
||||||
|
"use of expr body but specified return type in lambda expr",
|
||||||
|
"remove `-> ...`",
|
||||||
|
makeSourceLocation(rightArrowToken)));
|
||||||
|
}
|
||||||
|
auto result = parseExpression();
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expr *expr = *result;
|
||||||
|
LambdaExpr *lambda =
|
||||||
|
arena.Allocate<LambdaExpr>(params, returnType, expr, true, location);
|
||||||
|
return lambda;
|
||||||
|
}
|
||||||
|
else if (currentToken().type == TokenType::LeftBrace)
|
||||||
|
{
|
||||||
|
auto result = parseBlockStmt();
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
return std::unexpected(result.error());
|
||||||
|
}
|
||||||
|
|
||||||
|
LambdaExpr *lambda =
|
||||||
|
arena.Allocate<LambdaExpr>(params, returnType, *result, false, location);
|
||||||
|
return lambda;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return std::unexpected(
|
||||||
|
makeUnexpectTokenError("LambdaExpr", "darrow => / lbrace {", currentToken()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<Expr *, Error> Parser::parseExpression(BindingPower rbp)
|
Result<Expr *, Error> Parser::parseExpression(BindingPower rbp)
|
||||||
@@ -186,17 +370,39 @@ namespace Fig
|
|||||||
const Token &rparen_token = consumeToken(); // consume `)`
|
const Token &rparen_token = consumeToken(); // consume `)`
|
||||||
if (rparen_token.type != TokenType::RightParen)
|
if (rparen_token.type != TokenType::RightParen)
|
||||||
{
|
{
|
||||||
return std::unexpected(Error(ErrorType::SyntaxError,
|
return std::unexpected(Error(
|
||||||
|
ErrorType::SyntaxError,
|
||||||
"unclosed parenthese",
|
"unclosed parenthese",
|
||||||
"insert `)`",
|
"insert `)`",
|
||||||
makeSourceLocation(lparen_token)));
|
makeSourceLocation(lparen_token)));
|
||||||
}
|
}
|
||||||
lhs = *expr_result;
|
lhs = *expr_result;
|
||||||
}
|
}
|
||||||
|
else if (token.type == TokenType::Function)
|
||||||
|
{
|
||||||
|
auto result = parseLambdaExpr();
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
lhs = *result;
|
||||||
|
}
|
||||||
|
else if (token.type == TokenType::New)
|
||||||
|
{
|
||||||
|
auto result = parseNewExpr();
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
lhs = *result;
|
||||||
|
}
|
||||||
|
|
||||||
if (!lhs)
|
if (!lhs)
|
||||||
{
|
{
|
||||||
return std::unexpected(Error(ErrorType::ExpectedExpression,
|
return std::unexpected(Error(
|
||||||
|
ErrorType::ExpectedExpression,
|
||||||
"expected expression",
|
"expected expression",
|
||||||
"insert expressions",
|
"insert expressions",
|
||||||
makeSourceLocation(prevToken())));
|
makeSourceLocation(prevToken())));
|
||||||
@@ -253,10 +459,11 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return std::unexpected(Error(ErrorType::ExpectedExpression,
|
// return std::unexpected(Error(ErrorType::ExpectedExpression,
|
||||||
"expression unexpectedly ended",
|
// "expression unexpectedly ended",
|
||||||
"insert expressions",
|
// "insert expressions",
|
||||||
makeSourceLocation(token)));
|
// makeSourceLocation(token)));
|
||||||
|
return lhs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return lhs;
|
return lhs;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include <Ast/Ast.hpp>
|
#include <Ast/Ast.hpp>
|
||||||
#include <Deps/Deps.hpp>
|
#include <Deps/Deps.hpp>
|
||||||
|
#include <Error/Diagnostics.hpp>
|
||||||
#include <Error/Error.hpp>
|
#include <Error/Error.hpp>
|
||||||
#include <Lexer/Lexer.hpp>
|
#include <Lexer/Lexer.hpp>
|
||||||
#include <Token/Token.hpp>
|
#include <Token/Token.hpp>
|
||||||
@@ -33,6 +34,8 @@ namespace Fig
|
|||||||
String fileName;
|
String fileName;
|
||||||
bool isEOF = false;
|
bool isEOF = false;
|
||||||
|
|
||||||
|
Diagnostics &diagnostics;
|
||||||
|
|
||||||
// 惰性获取下一个 Token,跳过注释
|
// 惰性获取下一个 Token,跳过注释
|
||||||
Token nextToken()
|
Token nextToken()
|
||||||
{
|
{
|
||||||
@@ -116,12 +119,16 @@ namespace Fig
|
|||||||
enum StateType : std::uint8_t
|
enum StateType : std::uint8_t
|
||||||
{
|
{
|
||||||
Standby,
|
Standby,
|
||||||
|
|
||||||
ParsingLiteralExpr,
|
ParsingLiteralExpr,
|
||||||
ParsingIdentiExpr,
|
ParsingIdentiExpr,
|
||||||
ParsingInfixExpr,
|
ParsingInfixExpr,
|
||||||
ParsingPrefixExpr,
|
ParsingPrefixExpr,
|
||||||
ParsingIndexExpr,
|
ParsingIndexExpr,
|
||||||
ParsingCallExpr,
|
ParsingCallExpr,
|
||||||
|
ParsingLambdaExpr,
|
||||||
|
ParsingNewExpr,
|
||||||
|
|
||||||
ParsingVarDecl,
|
ParsingVarDecl,
|
||||||
ParsingIf,
|
ParsingIf,
|
||||||
ParsingWhile,
|
ParsingWhile,
|
||||||
@@ -129,6 +136,9 @@ namespace Fig
|
|||||||
ParsingReturn,
|
ParsingReturn,
|
||||||
ParsingBreak,
|
ParsingBreak,
|
||||||
ParsingContinue,
|
ParsingContinue,
|
||||||
|
ParsingStructDef,
|
||||||
|
|
||||||
|
ParsingTypeParameters,
|
||||||
ParsingNamedTypeExpr,
|
ParsingNamedTypeExpr,
|
||||||
ParsingFnTypeExpr,
|
ParsingFnTypeExpr,
|
||||||
} type = StateType::Standby;
|
} type = StateType::Standby;
|
||||||
@@ -138,7 +148,8 @@ namespace Fig
|
|||||||
private:
|
private:
|
||||||
const std::unordered_set<TokenType> &getBaseTerminators()
|
const std::unordered_set<TokenType> &getBaseTerminators()
|
||||||
{
|
{
|
||||||
static const std::unordered_set<TokenType> baseTerminators = {TokenType::Semicolon,
|
static const std::unordered_set<TokenType> baseTerminators{
|
||||||
|
TokenType::Semicolon,
|
||||||
TokenType::RightParen,
|
TokenType::RightParen,
|
||||||
TokenType::RightBracket,
|
TokenType::RightBracket,
|
||||||
TokenType::RightBrace,
|
TokenType::RightBrace,
|
||||||
@@ -201,32 +212,55 @@ namespace Fig
|
|||||||
SourceLocation makeSourceLocation(const Token &tok)
|
SourceLocation makeSourceLocation(const Token &tok)
|
||||||
{
|
{
|
||||||
auto [line, column] = srcManager.GetLineColumn(tok.index);
|
auto [line, column] = srcManager.GetLineColumn(tok.index);
|
||||||
// 物理防爆盾:防止因解析错位导致的异常列号引起终端 OOM
|
// 防止因解析错位导致的异常列号引起终端 OOM
|
||||||
if (column > 5000)
|
if (column > 5000)
|
||||||
column = 1;
|
column = 1;
|
||||||
return SourceLocation(SourcePosition(line, column, tok.length),
|
return SourceLocation(
|
||||||
|
SourcePosition(line, column, tok.length),
|
||||||
fileName,
|
fileName,
|
||||||
"[internal parser]",
|
"[internal parser]",
|
||||||
magic_enum::enum_name(currentState().type).data());
|
magic_enum::enum_name(currentState().type).data());
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Error makeUnexpectTokenError(const String &stmt, const String &exp, const Token &got)
|
inline Error makeUnexpectTokenError(
|
||||||
|
const String &stmt,
|
||||||
|
const String &exp,
|
||||||
|
const Token &got,
|
||||||
|
std::source_location th_loc = std::source_location::current())
|
||||||
{
|
{
|
||||||
return Error(ErrorType::SyntaxError,
|
return Error(
|
||||||
|
ErrorType::SyntaxError,
|
||||||
std::format(
|
std::format(
|
||||||
"expect '{}' in {}, got `{}`", exp, stmt, magic_enum::enum_name(got.type)),
|
"expect '{}' in {}, got `{}`", exp, stmt, magic_enum::enum_name(got.type)),
|
||||||
"none",
|
"none",
|
||||||
makeSourceLocation(got));
|
makeSourceLocation(got),
|
||||||
|
th_loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Error makeExpectSemicolonError()
|
inline Error
|
||||||
|
makeExpectSemicolonError(std::source_location th_loc = std::source_location::current())
|
||||||
{
|
{
|
||||||
return Error(ErrorType::SyntaxError,
|
return Error(
|
||||||
|
ErrorType::SyntaxError,
|
||||||
"expect ';' after statement",
|
"expect ';' after statement",
|
||||||
"insert ';'",
|
"insert ';'",
|
||||||
makeSourceLocation(currentToken()));
|
makeSourceLocation(currentToken()),
|
||||||
|
th_loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline Error makeExpectSemicolonError(
|
||||||
|
const Token &token, std::source_location th_loc = std::source_location::current())
|
||||||
|
{
|
||||||
|
return Error(
|
||||||
|
ErrorType::SyntaxError,
|
||||||
|
"expect ';' after statement",
|
||||||
|
"insert ';'",
|
||||||
|
makeSourceLocation(token),
|
||||||
|
th_loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<decltype(StructDefStmt::typeParameters), Error> parseTypeParameters();
|
||||||
|
|
||||||
Result<TypeExpr *, Error> parseTypeExpr();
|
Result<TypeExpr *, Error> parseTypeExpr();
|
||||||
Result<TypeExpr *, Error> parseNamedTypeExpr();
|
Result<TypeExpr *, Error> parseNamedTypeExpr();
|
||||||
Result<TypeExpr *, Error> parseFnTypeExpr();
|
Result<TypeExpr *, Error> parseFnTypeExpr();
|
||||||
@@ -239,6 +273,7 @@ namespace Fig
|
|||||||
Result<Expr *, Error> parseIndexExpr(Expr *);
|
Result<Expr *, Error> parseIndexExpr(Expr *);
|
||||||
Result<Expr *, Error> parseCallExpr(Expr *);
|
Result<Expr *, Error> parseCallExpr(Expr *);
|
||||||
Result<Expr *, Error> parseNewExpr();
|
Result<Expr *, Error> parseNewExpr();
|
||||||
|
Result<Expr *, Error> parseLambdaExpr();
|
||||||
|
|
||||||
Result<BlockStmt *, Error> parseBlockStmt();
|
Result<BlockStmt *, Error> parseBlockStmt();
|
||||||
Result<VarDecl *, Error> parseVarDecl(bool);
|
Result<VarDecl *, Error> parseVarDecl(bool);
|
||||||
@@ -255,8 +290,8 @@ namespace Fig
|
|||||||
Result<Stmt *, Error> parseStatement();
|
Result<Stmt *, Error> parseStatement();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Parser(Lexer &_lexer, SourceManager &_src, String _file) :
|
Parser(Lexer &_lexer, SourceManager &_src, String _file, Diagnostics &_diagnostics) :
|
||||||
lexer(_lexer), srcManager(_src), fileName(std::move(_file))
|
lexer(_lexer), srcManager(_src), fileName(std::move(_file)), diagnostics(_diagnostics)
|
||||||
{
|
{
|
||||||
pushState(State());
|
pushState(State());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,13 +18,19 @@ int main()
|
|||||||
}
|
}
|
||||||
|
|
||||||
Lexer lexer(source, fileName);
|
Lexer lexer(source, fileName);
|
||||||
Parser parser(lexer, srcManager, fileName);
|
|
||||||
|
Diagnostics diagnostics;
|
||||||
|
Parser parser(lexer, srcManager, fileName, diagnostics);
|
||||||
|
|
||||||
auto result = parser.Parse();
|
auto result = parser.Parse();
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
ReportError(result.error(), srcManager);
|
ReportError(result.error(), srcManager);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
diagnostics.EmitAll(srcManager);
|
||||||
|
|
||||||
Program *program = *result;
|
Program *program = *result;
|
||||||
for (Stmt *stmt : program->nodes)
|
for (Stmt *stmt : program->nodes)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
if (isEOF)
|
if (isEOF)
|
||||||
{
|
{
|
||||||
return std::unexpected(Error(ErrorType::SyntaxError,
|
return std::unexpected(Error(
|
||||||
|
ErrorType::SyntaxError,
|
||||||
"unclosed braces in block stmt",
|
"unclosed braces in block stmt",
|
||||||
"insert '}'",
|
"insert '}'",
|
||||||
location));
|
location));
|
||||||
@@ -75,7 +76,8 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
if (typeSpeicifer)
|
if (typeSpeicifer)
|
||||||
{
|
{
|
||||||
return std::unexpected(Error(ErrorType::SyntaxError,
|
return std::unexpected(Error(
|
||||||
|
ErrorType::SyntaxError,
|
||||||
"used type infer but specifying the type",
|
"used type infer but specifying the type",
|
||||||
"change `:=` to '='",
|
"change `:=` to '='",
|
||||||
makeSourceLocation(prevToken())));
|
makeSourceLocation(prevToken())));
|
||||||
@@ -115,7 +117,8 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
if (!match(TokenType::RightParen))
|
if (!match(TokenType::RightParen))
|
||||||
{
|
{
|
||||||
return std::unexpected(Error(ErrorType::SyntaxError,
|
return std::unexpected(Error(
|
||||||
|
ErrorType::SyntaxError,
|
||||||
"unclosed parenthese in if condition",
|
"unclosed parenthese in if condition",
|
||||||
"insert `)`",
|
"insert `)`",
|
||||||
makeSourceLocation(lpToken)));
|
makeSourceLocation(lpToken)));
|
||||||
@@ -155,7 +158,8 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
if (alternate)
|
if (alternate)
|
||||||
{
|
{
|
||||||
return std::unexpected(Error(ErrorType::SyntaxError,
|
return std::unexpected(Error(
|
||||||
|
ErrorType::SyntaxError,
|
||||||
"else if after else",
|
"else if after else",
|
||||||
"remove else if",
|
"remove else if",
|
||||||
elseLocation));
|
elseLocation));
|
||||||
@@ -175,7 +179,8 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
if (!match(TokenType::RightParen))
|
if (!match(TokenType::RightParen))
|
||||||
{
|
{
|
||||||
return std::unexpected(Error(ErrorType::SyntaxError,
|
return std::unexpected(Error(
|
||||||
|
ErrorType::SyntaxError,
|
||||||
"unclosed parenthese in if condition",
|
"unclosed parenthese in if condition",
|
||||||
"insert `)`",
|
"insert `)`",
|
||||||
makeSourceLocation(lpToken)));
|
makeSourceLocation(lpToken)));
|
||||||
@@ -210,7 +215,8 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
if (alternate)
|
if (alternate)
|
||||||
{
|
{
|
||||||
return std::unexpected(Error(ErrorType::SyntaxError,
|
return std::unexpected(Error(
|
||||||
|
ErrorType::SyntaxError,
|
||||||
"duplicate else in if stmt",
|
"duplicate else in if stmt",
|
||||||
"remove it",
|
"remove it",
|
||||||
elseLocation));
|
elseLocation));
|
||||||
@@ -252,7 +258,8 @@ namespace Fig
|
|||||||
|
|
||||||
if (!match(TokenType::RightParen))
|
if (!match(TokenType::RightParen))
|
||||||
{
|
{
|
||||||
return std::unexpected(Error(ErrorType::SyntaxError,
|
return std::unexpected(Error(
|
||||||
|
ErrorType::SyntaxError,
|
||||||
"unclosed parenthese in while condition",
|
"unclosed parenthese in while condition",
|
||||||
"insert ')'",
|
"insert ')'",
|
||||||
makeSourceLocation(lpToken)));
|
makeSourceLocation(lpToken)));
|
||||||
@@ -289,8 +296,6 @@ namespace Fig
|
|||||||
|
|
||||||
Result<DynArray<Param *>, Error> Parser::parseFnParams()
|
Result<DynArray<Param *>, Error> Parser::parseFnParams()
|
||||||
{
|
{
|
||||||
StateProtector p(this, {State::ParsingFnDefStmt});
|
|
||||||
|
|
||||||
const Token &lpToken = consumeToken();
|
const Token &lpToken = consumeToken();
|
||||||
DynArray<Param *> params;
|
DynArray<Param *> params;
|
||||||
|
|
||||||
@@ -298,7 +303,8 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
if (isEOF)
|
if (isEOF)
|
||||||
{
|
{
|
||||||
return std::unexpected(Error(ErrorType::SyntaxError,
|
return std::unexpected(Error(
|
||||||
|
ErrorType::SyntaxError,
|
||||||
"unclosed parenthese in function parameters",
|
"unclosed parenthese in function parameters",
|
||||||
"insert ')'",
|
"insert ')'",
|
||||||
makeSourceLocation(lpToken)));
|
makeSourceLocation(lpToken)));
|
||||||
@@ -353,6 +359,7 @@ namespace Fig
|
|||||||
|
|
||||||
Result<FnDefStmt *, Error> Parser::parseFnDefStmt(bool isPublic)
|
Result<FnDefStmt *, Error> Parser::parseFnDefStmt(bool isPublic)
|
||||||
{
|
{
|
||||||
|
StateProtector p(this, {State::ParsingFnDefStmt});
|
||||||
SourceLocation location = makeSourceLocation(consumeToken());
|
SourceLocation location = makeSourceLocation(consumeToken());
|
||||||
|
|
||||||
if (!currentToken().isIdentifier())
|
if (!currentToken().isIdentifier())
|
||||||
@@ -389,19 +396,49 @@ namespace Fig
|
|||||||
returnType = *result;
|
returnType = *result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentToken().type != TokenType::LeftBrace)
|
|
||||||
{
|
|
||||||
return std::unexpected(
|
|
||||||
makeUnexpectTokenError("fn def stmt", "function body '{'", currentToken()));
|
|
||||||
}
|
|
||||||
BlockStmt *body = nullptr;
|
BlockStmt *body = nullptr;
|
||||||
auto bodyResult = parseBlockStmt();
|
if (match(TokenType::DoubleArrow)) // =>
|
||||||
|
{
|
||||||
|
auto result = parseExpression();
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
return std::unexpected(result.error());
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (!match(TokenType::Semicolon)) // ;
|
||||||
|
// {
|
||||||
|
// return std::unexpected(makeExpectSemicolonError(prevToken()));
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (match(TokenType::Semicolon))
|
||||||
|
{
|
||||||
|
diagnostics.Report(Error(
|
||||||
|
ErrorType::UnnecessarySemicolon,
|
||||||
|
"`;` is unnecessary in this context",
|
||||||
|
"try remove `;`",
|
||||||
|
makeSourceLocation(prevToken())));
|
||||||
|
}
|
||||||
|
|
||||||
|
Expr *expr = *result;
|
||||||
|
ReturnStmt *returnStmt = arena.Allocate<ReturnStmt>(expr, expr->location);
|
||||||
|
|
||||||
|
body = arena.Allocate<BlockStmt>();
|
||||||
|
body->nodes.push_back(returnStmt);
|
||||||
|
}
|
||||||
|
else if (currentToken().type == TokenType::LeftBrace)
|
||||||
|
{
|
||||||
|
auto bodyResult = parseBlockStmt();
|
||||||
if (!bodyResult)
|
if (!bodyResult)
|
||||||
{
|
{
|
||||||
return std::unexpected(bodyResult.error());
|
return std::unexpected(bodyResult.error());
|
||||||
}
|
}
|
||||||
body = *bodyResult;
|
body = *bodyResult;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return std::unexpected(
|
||||||
|
makeUnexpectTokenError("fn def stmt", "function body '=>' / '{'", currentToken()));
|
||||||
|
}
|
||||||
|
|
||||||
FnDefStmt *fnDef =
|
FnDefStmt *fnDef =
|
||||||
arena.Allocate<FnDefStmt>(isPublic, name, params, returnType, body, location);
|
arena.Allocate<FnDefStmt>(isPublic, name, params, returnType, body, location);
|
||||||
@@ -429,6 +466,127 @@ namespace Fig
|
|||||||
return returnStmt;
|
return returnStmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<Stmt *, Error> Parser::parseStructDef(bool isPublic)
|
||||||
|
{
|
||||||
|
StateProtector p(this, {State::ParsingStructDef});
|
||||||
|
|
||||||
|
SourceLocation location = makeSourceLocation(consumeToken()); // consume `struct`
|
||||||
|
if (!currentToken().isIdentifier())
|
||||||
|
{
|
||||||
|
return std::unexpected(
|
||||||
|
makeUnexpectTokenError("StructDef", "struct name", currentToken()));
|
||||||
|
}
|
||||||
|
|
||||||
|
const Token &name_tok = consumeToken(); // consume name
|
||||||
|
const String &name = srcManager.GetSub(name_tok.index, name_tok.length);
|
||||||
|
|
||||||
|
StructDefStmt *stDef = arena.Allocate<StructDefStmt>();
|
||||||
|
|
||||||
|
if (currentToken().type == TokenType::Less) // <
|
||||||
|
{
|
||||||
|
auto result = parseTypeParameters();
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
return std::unexpected(result.error());
|
||||||
|
}
|
||||||
|
|
||||||
|
stDef->typeParameters = *result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!match(TokenType::LeftBrace))
|
||||||
|
{
|
||||||
|
return std::unexpected(
|
||||||
|
makeUnexpectTokenError("StructDef", "lbrace '{'", currentToken()));
|
||||||
|
}
|
||||||
|
|
||||||
|
const Token &lb_tok = prevToken(); // `{`
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (isEOF)
|
||||||
|
{
|
||||||
|
return std::unexpected(Error(
|
||||||
|
ErrorType::SyntaxError,
|
||||||
|
"unclosed braces in struct def",
|
||||||
|
"insert '}'",
|
||||||
|
makeSourceLocation(lb_tok)));
|
||||||
|
}
|
||||||
|
if (match(TokenType::RightBrace))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// (public) field_name (: Type) (= expr) / (:= expr)
|
||||||
|
|
||||||
|
bool isPublic = match(TokenType::Public);
|
||||||
|
if (currentToken().isIdentifier())
|
||||||
|
{
|
||||||
|
const Token &name_tok = consumeToken();
|
||||||
|
const String &field_name = srcManager.GetSub(name_tok.index, name_tok.length);
|
||||||
|
|
||||||
|
if (match(TokenType::Walrus)) // :=
|
||||||
|
{
|
||||||
|
auto result = parseExpression();
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
return std::unexpected(result.error());
|
||||||
|
}
|
||||||
|
|
||||||
|
stDef->fields.push_back(
|
||||||
|
StructDefStmt::Field{isPublic, true, field_name, nullptr, *result});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TypeExpr *type = nullptr;
|
||||||
|
Expr *initExpr = nullptr;
|
||||||
|
|
||||||
|
if (match(TokenType::Colon)) // :
|
||||||
|
{
|
||||||
|
auto result = parseTypeExpr();
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
return std::unexpected(result.error());
|
||||||
|
}
|
||||||
|
type = *result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (match(TokenType::Assign))
|
||||||
|
{
|
||||||
|
auto result = parseExpression();
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
return std::unexpected(result.error());
|
||||||
|
}
|
||||||
|
initExpr = *result;
|
||||||
|
}
|
||||||
|
stDef->fields.push_back(
|
||||||
|
StructDefStmt::Field{isPublic, false, field_name, type, initExpr});
|
||||||
|
}
|
||||||
|
if (!match(TokenType::Semicolon))
|
||||||
|
{
|
||||||
|
return std::unexpected(makeExpectSemicolonError());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (currentToken().type == TokenType::Function)
|
||||||
|
{
|
||||||
|
auto result = parseFnDefStmt(isPublic);
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
stDef->methods.push_back(*result);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return std::unexpected(
|
||||||
|
makeUnexpectTokenError("StructDef", "field or method", currentToken()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return stDef;
|
||||||
|
}
|
||||||
|
|
||||||
Result<Stmt *, Error> Parser::parseStatement()
|
Result<Stmt *, Error> Parser::parseStatement()
|
||||||
{
|
{
|
||||||
StateProtector p(this, {State::Standby});
|
StateProtector p(this, {State::Standby});
|
||||||
@@ -446,6 +604,11 @@ namespace Fig
|
|||||||
return parseFnDefStmt(true);
|
return parseFnDefStmt(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (currentToken().type == TokenType::Struct)
|
||||||
|
{
|
||||||
|
return parseStructDef(true);
|
||||||
|
}
|
||||||
|
|
||||||
return std::unexpected(
|
return std::unexpected(
|
||||||
makeUnexpectTokenError("public", "var/const/func/struct", currentToken()));
|
makeUnexpectTokenError("public", "var/const/func/struct", currentToken()));
|
||||||
}
|
}
|
||||||
@@ -470,11 +633,16 @@ namespace Fig
|
|||||||
return parseWhileStmt();
|
return parseWhileStmt();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentToken().type == TokenType::Function)
|
if (currentToken().type == TokenType::Function && peekToken().isIdentifier())
|
||||||
{
|
{
|
||||||
return parseFnDefStmt(false);
|
return parseFnDefStmt(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (currentToken().type == TokenType::Struct)
|
||||||
|
{
|
||||||
|
return parseStructDef(false);
|
||||||
|
}
|
||||||
|
|
||||||
if (currentToken().type == TokenType::Return)
|
if (currentToken().type == TokenType::Return)
|
||||||
{
|
{
|
||||||
return parseReturnStmt();
|
return parseReturnStmt();
|
||||||
@@ -507,6 +675,15 @@ namespace Fig
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (currentToken().type == TokenType::Semicolon)
|
||||||
|
{
|
||||||
|
return std::unexpected(Error(
|
||||||
|
ErrorType::SyntaxError,
|
||||||
|
"null statement is not allowed here",
|
||||||
|
"remove `;`",
|
||||||
|
makeSourceLocation(currentToken())));
|
||||||
|
}
|
||||||
|
|
||||||
const auto &expr_result = parseExpression();
|
const auto &expr_result = parseExpression();
|
||||||
if (!expr_result)
|
if (!expr_result)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,6 +9,46 @@
|
|||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
|
Result<decltype(StructDefStmt::typeParameters), Error> Parser::parseTypeParameters()
|
||||||
|
{
|
||||||
|
StateProtector p(this, {State::ParsingTypeParameters});
|
||||||
|
decltype(StructDefStmt::typeParameters) tp;
|
||||||
|
|
||||||
|
const Token &lab = consumeToken(); // consume `<`
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (isEOF)
|
||||||
|
{
|
||||||
|
return std::unexpected(Error(
|
||||||
|
ErrorType::SyntaxError,
|
||||||
|
"unclosed `<` in type parameters",
|
||||||
|
"insert '>'",
|
||||||
|
makeSourceLocation(lab)));
|
||||||
|
}
|
||||||
|
if (match(TokenType::Greater)) // >
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!currentToken().isIdentifier())
|
||||||
|
{
|
||||||
|
return std::unexpected(
|
||||||
|
makeUnexpectTokenError("TypeParams", "tp name", currentToken()));
|
||||||
|
}
|
||||||
|
|
||||||
|
const Token &name_tok = consumeToken();
|
||||||
|
const String &name = srcManager.GetSub(name_tok.index, name_tok.length);
|
||||||
|
tp.push_back(name);
|
||||||
|
|
||||||
|
if (!match(TokenType::Comma))
|
||||||
|
{
|
||||||
|
return std::unexpected(makeUnexpectTokenError(
|
||||||
|
"TypeParams", "comma or type parameter", currentToken()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tp;
|
||||||
|
}
|
||||||
|
|
||||||
// 解析基础命名类型与泛型: List<Int>
|
// 解析基础命名类型与泛型: List<Int>
|
||||||
Result<TypeExpr *, Error> Parser::parseNamedTypeExpr()
|
Result<TypeExpr *, Error> Parser::parseNamedTypeExpr()
|
||||||
{
|
{
|
||||||
@@ -137,7 +177,8 @@ namespace Fig
|
|||||||
// type (?)
|
// type (?)
|
||||||
if (currentToken().type == TokenType::Question) // ?
|
if (currentToken().type == TokenType::Question) // ?
|
||||||
{
|
{
|
||||||
base = arena.Allocate<NullableTypeExpr>(base, makeSourceLocation(consumeToken())); // consume `?`
|
base = arena.Allocate<NullableTypeExpr>(
|
||||||
|
base, makeSourceLocation(consumeToken())); // consume `?`
|
||||||
}
|
}
|
||||||
|
|
||||||
return base;
|
return base;
|
||||||
|
|||||||
@@ -209,7 +209,10 @@ namespace Fig
|
|||||||
String source(buf);
|
String source(buf);
|
||||||
|
|
||||||
Lexer lexer(buf, fileName);
|
Lexer lexer(buf, fileName);
|
||||||
Parser parser(lexer, manager, fileName);
|
|
||||||
|
Diagnostics diagnostics;
|
||||||
|
|
||||||
|
Parser parser(lexer, manager, fileName, diagnostics);
|
||||||
|
|
||||||
auto _program = parser.Parse();
|
auto _program = parser.Parse();
|
||||||
if (!_program)
|
if (!_program)
|
||||||
@@ -223,13 +226,15 @@ namespace Fig
|
|||||||
Analyzer analyzer(manager);
|
Analyzer analyzer(manager);
|
||||||
auto result = analyzer.Analyze(program);
|
auto result = analyzer.Analyze(program);
|
||||||
|
|
||||||
|
analyzer.GetDiagnostics().EmitAll(manager);
|
||||||
|
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
PrintError(result.error(), source);
|
PrintError(result.error(), source);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Compiler compiler(manager, analyzer.GetDiagnostics());
|
Compiler compiler(manager, diagnostics);
|
||||||
|
|
||||||
auto compile_result = compiler.Compile(program);
|
auto compile_result = compiler.Compile(program);
|
||||||
if (!compile_result)
|
if (!compile_result)
|
||||||
@@ -238,6 +243,8 @@ namespace Fig
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
diagnostics.EmitAll(manager);
|
||||||
|
|
||||||
CompiledModule *compiledModule = *compile_result;
|
CompiledModule *compiledModule = *compile_result;
|
||||||
|
|
||||||
auto exe_result = vm.Execute(compiledModule);
|
auto exe_result = vm.Execute(compiledModule);
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
#include <Ast/Ast.hpp>
|
#include <Ast/Ast.hpp>
|
||||||
#include <Ast/Expr/MemberExpr.hpp>
|
#include <Ast/Expr/MemberExpr.hpp>
|
||||||
#include <Ast/Expr/ObjectInitExpr.hpp>
|
|
||||||
#include <Ast/Stmt/ImplStmt.hpp>
|
#include <Ast/Stmt/ImplStmt.hpp>
|
||||||
#include <Ast/Stmt/InterfaceDefStmt.hpp>
|
#include <Ast/Stmt/InterfaceDefStmt.hpp>
|
||||||
#include <Ast/Stmt/StructDefStmt.hpp>
|
#include <Ast/Stmt/StructDefStmt.hpp>
|
||||||
@@ -82,8 +81,11 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
auto *s = static_cast<StructDefStmt *>(stmt);
|
auto *s = static_cast<StructDefStmt *>(stmt);
|
||||||
if (globalTypes.contains(s->name))
|
if (globalTypes.contains(s->name))
|
||||||
|
{
|
||||||
return std::unexpected(
|
return std::unexpected(
|
||||||
Error(ErrorType::RedeclarationError, "type redeclared", "", s->location));
|
Error(ErrorType::RedeclarationError, "type redeclared", "", s->location));
|
||||||
|
}
|
||||||
|
|
||||||
auto *t = arena.Allocate<StructType>(s->name);
|
auto *t = arena.Allocate<StructType>(s->name);
|
||||||
typeCtx.allTypes.push_back(t);
|
typeCtx.allTypes.push_back(t);
|
||||||
globalTypes[s->name] = t;
|
globalTypes[s->name] = t;
|
||||||
@@ -92,10 +94,14 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
auto *f = static_cast<FnDefStmt *>(stmt);
|
auto *f = static_cast<FnDefStmt *>(stmt);
|
||||||
if (f->name == "main")
|
if (f->name == "main")
|
||||||
|
{
|
||||||
hasMain = true;
|
hasMain = true;
|
||||||
|
}
|
||||||
if (globalSymbols.contains(f->name))
|
if (globalSymbols.contains(f->name))
|
||||||
|
{
|
||||||
return std::unexpected(
|
return std::unexpected(
|
||||||
Error(ErrorType::RedeclarationError, "func redeclared", "", f->location));
|
Error(ErrorType::RedeclarationError, "func redeclared", "", f->location));
|
||||||
|
}
|
||||||
Symbol *sym =
|
Symbol *sym =
|
||||||
arena.Allocate<Symbol>(f->name, Type{}, SymbolLocation::Global, 0, true);
|
arena.Allocate<Symbol>(f->name, Type{}, SymbolLocation::Global, 0, true);
|
||||||
globalSymbols[f->name] = sym;
|
globalSymbols[f->name] = sym;
|
||||||
@@ -118,7 +124,9 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
auto res = resolveTypeExpr(f.type);
|
auto res = resolveTypeExpr(f.type);
|
||||||
if (!res)
|
if (!res)
|
||||||
|
{
|
||||||
return std::unexpected(res.error());
|
return std::unexpected(res.error());
|
||||||
|
}
|
||||||
st->AddField(f.name, *res, f.isPublic);
|
st->AddField(f.name, *res, f.isPublic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -185,10 +193,11 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
Type declT = v->typeSpecifier ? *resolveTypeExpr(v->typeSpecifier) : initT;
|
Type declT = v->typeSpecifier ? *resolveTypeExpr(v->typeSpecifier) : initT;
|
||||||
|
|
||||||
// 🔥 强类型校验:赋值拦截
|
// 赋值拦截
|
||||||
if (v->initExpr && !initT.isAssignableTo(declT))
|
if (v->initExpr && !initT.isAssignableTo(declT))
|
||||||
{
|
{
|
||||||
return std::unexpected(Error(ErrorType::TypeError,
|
return std::unexpected(Error(
|
||||||
|
ErrorType::TypeError,
|
||||||
"cannot assign '" + initT.toString() + "' to type '" + declT.toString()
|
"cannot assign '" + initT.toString() + "' to type '" + declT.toString()
|
||||||
+ "'",
|
+ "'",
|
||||||
"",
|
"",
|
||||||
@@ -210,7 +219,7 @@ namespace Fig
|
|||||||
case AstType::FnDefStmt: {
|
case AstType::FnDefStmt: {
|
||||||
auto *f = static_cast<FnDefStmt *>(stmt);
|
auto *f = static_cast<FnDefStmt *>(stmt);
|
||||||
|
|
||||||
// 3.10: 局部闭包延迟类型推导
|
// 局部闭包延迟类型推导
|
||||||
|
|
||||||
if (!f->resolvedSymbol) // 闭包?
|
if (!f->resolvedSymbol) // 闭包?
|
||||||
{
|
{
|
||||||
@@ -243,7 +252,8 @@ namespace Fig
|
|||||||
ScopeGuard scopeGuard(env, true);
|
ScopeGuard scopeGuard(env, true);
|
||||||
for (auto *p : f->params)
|
for (auto *p : f->params)
|
||||||
{
|
{
|
||||||
env.current->locals[p->name] = arena.Allocate<Symbol>(p->name,
|
env.current->locals[p->name] = arena.Allocate<Symbol>(
|
||||||
|
p->name,
|
||||||
p->resolvedType,
|
p->resolvedType,
|
||||||
SymbolLocation::Local,
|
SymbolLocation::Local,
|
||||||
env.current->nextLocalId++,
|
env.current->nextLocalId++,
|
||||||
@@ -279,7 +289,8 @@ namespace Fig
|
|||||||
return std::unexpected(c.error());
|
return std::unexpected(c.error());
|
||||||
else if (!c->isAssignableTo(typeCtx.GetBasic(TypeTag::Bool)))
|
else if (!c->isAssignableTo(typeCtx.GetBasic(TypeTag::Bool)))
|
||||||
{
|
{
|
||||||
return std::unexpected(Error(ErrorType::TypeError,
|
return std::unexpected(Error(
|
||||||
|
ErrorType::TypeError,
|
||||||
"condition must be Bool",
|
"condition must be Bool",
|
||||||
"",
|
"",
|
||||||
elif->cond->location));
|
elif->cond->location));
|
||||||
@@ -330,11 +341,15 @@ namespace Fig
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AstType::BreakStmt:
|
case AstType::BreakStmt:
|
||||||
case AstType::ContinueStmt:
|
case AstType::ContinueStmt: {
|
||||||
if (state.loopDepth <= 0)
|
if (state.loopDepth <= 0)
|
||||||
|
{
|
||||||
return std::unexpected(
|
return std::unexpected(
|
||||||
Error(ErrorType::SyntaxError, "outside loop", "", stmt->location));
|
Error(ErrorType::SyntaxError, "outside loop", "", stmt->location));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case AstType::ReturnStmt: {
|
case AstType::ReturnStmt: {
|
||||||
auto *rs = static_cast<ReturnStmt *>(stmt);
|
auto *rs = static_cast<ReturnStmt *>(stmt);
|
||||||
Type retT = typeCtx.GetBasic(TypeTag::Null);
|
Type retT = typeCtx.GetBasic(TypeTag::Null);
|
||||||
@@ -345,10 +360,11 @@ 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,
|
||||||
"cannot return '" + retT.toString() + "' from function expecting '"
|
"cannot return '" + retT.toString() + "' from function expecting '"
|
||||||
+ state.currentFn->resolvedReturnType.toString() + "'",
|
+ state.currentFn->resolvedReturnType.toString() + "'",
|
||||||
"",
|
"",
|
||||||
@@ -407,7 +423,8 @@ namespace Fig
|
|||||||
auto *st = static_cast<StructType *>(targetType.base);
|
auto *st = static_cast<StructType *>(targetType.base);
|
||||||
if (!st->fieldMap.contains(m->name))
|
if (!st->fieldMap.contains(m->name))
|
||||||
{
|
{
|
||||||
return std::unexpected(Error(ErrorType::TypeError,
|
return std::unexpected(Error(
|
||||||
|
ErrorType::TypeError,
|
||||||
"struct '" + st->name + "' has no field named '" + m->name + "'",
|
"struct '" + st->name + "' has no field named '" + m->name + "'",
|
||||||
"",
|
"",
|
||||||
m->location));
|
m->location));
|
||||||
@@ -415,14 +432,18 @@ namespace Fig
|
|||||||
// 字段类型
|
// 字段类型
|
||||||
return expr->resolvedType = st->fields[st->fieldMap[m->name]].type;
|
return expr->resolvedType = st->fields[st->fieldMap[m->name]].type;
|
||||||
}
|
}
|
||||||
case AstType::ObjectInitExpr: {
|
case AstType::NewExpr: {
|
||||||
auto *o = static_cast<ObjectInitExpr *>(expr);
|
auto *o = static_cast<NewExpr *>(expr);
|
||||||
auto res = resolveTypeExpr(o->typeExpr);
|
auto res = resolveTypeExpr(o->typeExpr);
|
||||||
if (!res)
|
if (!res)
|
||||||
|
{
|
||||||
return std::unexpected(res.error());
|
return std::unexpected(res.error());
|
||||||
|
}
|
||||||
if (!res->base || res->base->tag != TypeTag::Struct)
|
if (!res->base || res->base->tag != TypeTag::Struct)
|
||||||
|
{
|
||||||
return std::unexpected(
|
return std::unexpected(
|
||||||
Error(ErrorType::TypeError, "requires struct", "", o->location));
|
Error(ErrorType::TypeError, "requires struct", "", o->location));
|
||||||
|
}
|
||||||
auto *st = static_cast<StructType *>(res->base);
|
auto *st = static_cast<StructType *>(res->base);
|
||||||
for (auto &arg : o->args)
|
for (auto &arg : o->args)
|
||||||
{
|
{
|
||||||
@@ -431,7 +452,9 @@ namespace Fig
|
|||||||
Error(ErrorType::TypeError, "unknown field", "", arg.value->location));
|
Error(ErrorType::TypeError, "unknown field", "", arg.value->location));
|
||||||
auto r = analyzeExpr(arg.value);
|
auto r = analyzeExpr(arg.value);
|
||||||
if (!r)
|
if (!r)
|
||||||
|
{
|
||||||
return std::unexpected(r.error());
|
return std::unexpected(r.error());
|
||||||
|
}
|
||||||
// 字段赋值类型检查
|
// 字段赋值类型检查
|
||||||
if (!arg.name.empty()
|
if (!arg.name.empty()
|
||||||
&& !r->isAssignableTo(st->fields[st->fieldMap[arg.name]].type))
|
&& !r->isAssignableTo(st->fields[st->fieldMap[arg.name]].type))
|
||||||
@@ -456,7 +479,8 @@ namespace Fig
|
|||||||
if (in->op == BinaryOperator::Assign)
|
if (in->op == BinaryOperator::Assign)
|
||||||
{
|
{
|
||||||
if (!r.isAssignableTo(l))
|
if (!r.isAssignableTo(l))
|
||||||
return std::unexpected(Error(ErrorType::TypeError,
|
return std::unexpected(Error(
|
||||||
|
ErrorType::TypeError,
|
||||||
"cannot assign '" + r.toString() + "' to '" + l.toString() + "'",
|
"cannot assign '" + r.toString() + "' to '" + l.toString() + "'",
|
||||||
"",
|
"",
|
||||||
in->location));
|
in->location));
|
||||||
@@ -511,11 +535,13 @@ namespace Fig
|
|||||||
Error(ErrorType::TypeError, "callee is not a function", "", c->location));
|
Error(ErrorType::TypeError, "callee is not a function", "", c->location));
|
||||||
|
|
||||||
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::SyntaxError,
|
return std::unexpected(Error(
|
||||||
|
ErrorType::SyntaxError,
|
||||||
std::format(
|
std::format(
|
||||||
"expected {} arguments, go {}", ft->paramTypes.size(), argTypes.size()),
|
"expected {} arguments, got {}", ft->paramTypes.size(), argTypes.size()),
|
||||||
"none",
|
"none",
|
||||||
c->location));
|
c->location));
|
||||||
}
|
}
|
||||||
@@ -523,7 +549,8 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
if (!argTypes[i].isAssignableTo(ft->paramTypes[i]))
|
if (!argTypes[i].isAssignableTo(ft->paramTypes[i]))
|
||||||
{
|
{
|
||||||
return std::unexpected(Error(ErrorType::TypeError,
|
return std::unexpected(Error(
|
||||||
|
ErrorType::TypeError,
|
||||||
"argument " + std::to_string(i + 1) + " expects '"
|
"argument " + std::to_string(i + 1) + " expects '"
|
||||||
+ ft->paramTypes[i].toString() + "', got '" + argTypes[i].toString()
|
+ ft->paramTypes[i].toString() + "', got '" + argTypes[i].toString()
|
||||||
+ "'",
|
+ "'",
|
||||||
@@ -533,13 +560,86 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
return expr->resolvedType = ft->retType;
|
return expr->resolvedType = ft->retType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case AstType::LambdaExpr: {
|
||||||
|
auto l = static_cast<LambdaExpr *>(expr);
|
||||||
|
|
||||||
|
Type returnType = typeCtx.GetBasic(TypeTag::Any);
|
||||||
|
|
||||||
|
if (l->returnType)
|
||||||
|
{
|
||||||
|
auto tres = resolveTypeExpr(l->returnType);
|
||||||
|
if (!tres)
|
||||||
|
{
|
||||||
|
return tres;
|
||||||
|
}
|
||||||
|
|
||||||
|
returnType = *tres;
|
||||||
|
}
|
||||||
|
|
||||||
|
FnDefStmt *f = arena.Allocate<FnDefStmt>(
|
||||||
|
false, "LambdaFn", l->params, l->returnType, nullptr, l->location);
|
||||||
|
|
||||||
|
FnStateGuard fnGuard(state.currentFn, f);
|
||||||
|
ScopeGuard scopeGuard(env, true);
|
||||||
|
|
||||||
|
DynArray<Type> paramTypes;
|
||||||
|
for (auto *p : l->params)
|
||||||
|
{
|
||||||
|
auto pres = resolveTypeExpr(p->typeSpecifier);
|
||||||
|
if (!pres)
|
||||||
|
{
|
||||||
|
return pres;
|
||||||
|
}
|
||||||
|
p->resolvedType = *pres;
|
||||||
|
paramTypes.push_back(*pres);
|
||||||
|
|
||||||
|
env.current->locals[p->name] = arena.Allocate<Symbol>(
|
||||||
|
p->name,
|
||||||
|
p->resolvedType,
|
||||||
|
SymbolLocation::Local,
|
||||||
|
env.current->nextLocalId++,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (l->isExprBody)
|
||||||
|
{
|
||||||
|
Expr *expr = static_cast<Expr *>(l->body);
|
||||||
|
if (auto r = analyzeExpr(expr); !r)
|
||||||
|
{
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
if (!expr->resolvedType.isAssignableTo(state.currentFn->resolvedReturnType))
|
||||||
|
{
|
||||||
|
return std::unexpected(Error(
|
||||||
|
ErrorType::TypeError,
|
||||||
|
"cannot return '" + state.currentFn->resolvedReturnType.toString()
|
||||||
|
+ "' from lambda function expecting '"
|
||||||
|
+ state.currentFn->resolvedReturnType.toString() + "'",
|
||||||
|
"",
|
||||||
|
expr->location));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Stmt *stmt = static_cast<Stmt *>(l->body);
|
||||||
|
if (auto r = analyzeStmt(stmt); !r)
|
||||||
|
{
|
||||||
|
return std::unexpected(r.error());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return l->resolvedType = typeCtx.CreateFuncType(paramTypes, returnType);
|
||||||
|
}
|
||||||
|
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return expr->resolvedType = typeCtx.GetBasic(TypeTag::Any);
|
return expr->resolvedType = typeCtx.GetBasic(TypeTag::Any);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<Symbol *, Error> Analyzer::resolveSymbolInternal(
|
Result<Symbol *, Error>
|
||||||
const String &name, const SourceLocation &loc, Scope *s)
|
Analyzer::resolveSymbolInternal(const String &name, const SourceLocation &loc, Scope *s)
|
||||||
{
|
{
|
||||||
Scope *curr = s;
|
Scope *curr = s;
|
||||||
while (curr)
|
while (curr)
|
||||||
|
|||||||
@@ -20,7 +20,12 @@ void runTest(const std::string &path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Lexer lexer(source, String(path));
|
Lexer lexer(source, String(path));
|
||||||
Parser parser(lexer, srcManager, String(path));
|
|
||||||
|
Diagnostics diagnostics;
|
||||||
|
|
||||||
|
Parser parser(lexer, srcManager, String(path), diagnostics);
|
||||||
|
|
||||||
|
diagnostics.EmitAll(srcManager);
|
||||||
|
|
||||||
auto pRes = parser.Parse();
|
auto pRes = parser.Parse();
|
||||||
if (!pRes)
|
if (!pRes)
|
||||||
|
|||||||
@@ -54,7 +54,10 @@ 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);
|
|
||||||
|
Diagnostics diagnostics;
|
||||||
|
|
||||||
|
Parser parser(lexer, manager, fileName, diagnostics);
|
||||||
|
|
||||||
auto parse_result = parser.Parse();
|
auto parse_result = parser.Parse();
|
||||||
if (!parse_result)
|
if (!parse_result)
|
||||||
@@ -73,7 +76,6 @@ namespace Fig::Entry
|
|||||||
std::exit(1);
|
std::exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Diagnostics diagnostics;
|
|
||||||
Compiler compiler(manager, diagnostics);
|
Compiler compiler(manager, diagnostics);
|
||||||
|
|
||||||
auto compile_result = compiler.Compile(program);
|
auto compile_result = compiler.Compile(program);
|
||||||
@@ -91,7 +93,6 @@ namespace Fig::Entry
|
|||||||
{
|
{
|
||||||
Disassembler disassembler;
|
Disassembler disassembler;
|
||||||
disassembler.DisassembleModule(compiledModule);
|
disassembler.DisassembleModule(compiledModule);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VM vm;
|
VM vm;
|
||||||
@@ -103,6 +104,11 @@ namespace Fig::Entry
|
|||||||
std::exit(1);
|
std::exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (conf.pregs)
|
||||||
|
{
|
||||||
|
vm.PrintRegisters();
|
||||||
|
}
|
||||||
|
|
||||||
delete compiledModule;
|
delete compiledModule;
|
||||||
}
|
}
|
||||||
}; // namespace Fig::Entry
|
}; // namespace Fig::Entry
|
||||||
@@ -17,6 +17,7 @@ namespace Fig::Entry
|
|||||||
Normal
|
Normal
|
||||||
} mode;
|
} mode;
|
||||||
bool dump;
|
bool dump;
|
||||||
|
bool pregs;
|
||||||
};
|
};
|
||||||
void RunFromPath(const String &, const Config &conf);
|
void RunFromPath(const String &, const Config &conf);
|
||||||
};
|
};
|
||||||
14
src/main.cpp
14
src/main.cpp
@@ -23,6 +23,7 @@ int main(int argc, char **argv)
|
|||||||
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");
|
argparser.AddFlag("dump").Help("Dump the bytecode");
|
||||||
|
argparser.AddFlag("pregs").Help("Print vm non-null registers");
|
||||||
|
|
||||||
auto res = argparser.Parse(argc, argv);
|
auto res = argparser.Parse(argc, argv);
|
||||||
if (!res)
|
if (!res)
|
||||||
@@ -37,6 +38,7 @@ int main(int argc, char **argv)
|
|||||||
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");
|
bool dump = args.HasFlag("dump");
|
||||||
|
bool pregs = args.HasFlag("pregs");
|
||||||
|
|
||||||
if (showHelp)
|
if (showHelp)
|
||||||
{
|
{
|
||||||
@@ -46,10 +48,12 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
if (showVersion)
|
if (showVersion)
|
||||||
{
|
{
|
||||||
out << std::format("Fig {}, copyright (c) 2025-2026 PuqiAR, under the {} License\n",
|
out << std::format(
|
||||||
|
"Fig {}, copyright (c) 2025-2026 PuqiAR, under the {} License\n",
|
||||||
Core::VERSION,
|
Core::VERSION,
|
||||||
Core::LICENSE);
|
Core::LICENSE);
|
||||||
out << std::format("Build time: {} [{} x{} on {}]\n",
|
out << std::format(
|
||||||
|
"Build time: {} [{} x{} on {}]\n",
|
||||||
Core::COMPILE_TIME,
|
Core::COMPILE_TIME,
|
||||||
Core::COMPILER,
|
Core::COMPILER,
|
||||||
Core::ARCH,
|
Core::ARCH,
|
||||||
@@ -79,11 +83,7 @@ int main(int argc, char **argv)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entry::Config config
|
Entry::Config config{.mode = Entry::Config::Normal, .dump = dump, .pregs = pregs};
|
||||||
{
|
|
||||||
.mode = Entry::Config::Normal,
|
|
||||||
.dump = dump
|
|
||||||
};
|
|
||||||
|
|
||||||
const String &path = positionals.front();
|
const String &path = positionals.front();
|
||||||
Entry::RunFromPath(path, config);
|
Entry::RunFromPath(path, config);
|
||||||
|
|||||||
Reference in New Issue
Block a user