Compare commits

..

5 Commits

Author SHA1 Message Date
4f87078a87 Plan 2026-06-01 18:52:06 +08:00
9338c21449 *(无用) feat: 在VM.cpp中添加likely属性以优化分支预测
refact: 在xmake.lua中优化构建设置
2026-05-10 21:25:05 +08:00
98de782760 feat: 增加repl入口,-r/--repl。 添加计时选项。 -- 我发现一个问题,analyzer没法保存环境。完了。 2026-04-30 21:24:11 +08:00
fafa2b4946 feat: 在解析器中实现 Lambda 和 new 表达式
- 增加了对 Lambda 表达式的初步解析支持,包括参数处理和返回类型。Lambda闭包尚未支持。
- 引入了用于对象初始化的新的表达式,支持可选的命名参数。
- 改进了表达式语法错误的错误报告。
- 更新了解析器和分析器以处理新的表达式类型并验证其语义。
- 修改了现有测试以涵盖新功能并确保其正确性。
- 改进了各种解析和语义错误的诊断。
2026-04-12 10:07:51 +08:00
570a87c3cd feat: 增加函数类型表达式支持,更新解析器和分析器 2026-03-18 17:30:09 +08:00
33 changed files with 1420 additions and 217 deletions

View File

@@ -6,7 +6,7 @@ Language: Cpp
AccessModifierOffset: -4 AccessModifierOffset: -4
# 开括号(开圆括号、开尖括号、开方括号)后的对齐: Align, DontAlign, AlwaysBreak(总是在开括号后换行) # 开括号(开圆括号、开尖括号、开方括号)后的对齐: Align, DontAlign, AlwaysBreak(总是在开括号后换行)
AlignAfterOpenBracket: DontAlign AlignAfterOpenBracket: AlwaysBreak
# 连续赋值时,对齐所有等号 # 连续赋值时,对齐所有等号
AlignConsecutiveAssignments: true AlignConsecutiveAssignments: true

View File

@@ -1,11 +1,11 @@
from time import time as tt from time import time as tt
def fib(x:int) -> int: def fib(x:int) -> int:
if x <= 1: return x; if x <= 1: return x
return fib(x-1) + fib(x-2) return fib(x-1) + fib(x-2)
if __name__ == '__main__': if __name__ == '__main__':
t0 = tt() t0 = tt()
result = fib(30) result = fib(35)
t1 = tt() t1 = tt()
print('cost: ',t1-t0, 'result:', result) print('cost: ',t1-t0, 'result:', result)

View File

@@ -1,5 +1,7 @@
# Fig # Fig
## tmd赶工代码质量太差了暑假我要重构
<picture> <picture>
<source media="(prefers-color-scheme: dark)" srcset="./Logo/LogoDark.svg"> <source media="(prefers-color-scheme: dark)" srcset="./Logo/LogoDark.svg">
<img src="./Logo/Logo.svg" alt="Fig Logo" width="200"> <img src="./Logo/Logo.svg" alt="Fig Logo" width="200">

View File

@@ -1,5 +1,7 @@
# Fig # Fig
## tmd赶工代码质量太差了暑假我要重构
<picture> <picture>
<source media="(prefers-color-scheme: dark)" srcset="./Logo/LogoDark.svg"> <source media="(prefers-color-scheme: dark)" srcset="./Logo/LogoDark.svg">
<img src="./Logo/Logo.svg" alt="Fig Logo" width="200"> <img src="./Logo/Logo.svg" alt="Fig Logo" width="200">

View File

@@ -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>

View File

@@ -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,
@@ -48,7 +49,8 @@ namespace Fig
/* Type Expressions */ /* Type Expressions */
TypeExpr, TypeExpr,
NamedTypeExpr, NamedTypeExpr,
NullableTypeExpr NullableTypeExpr,
FnTypeExpr,
}; };
struct AstNode struct AstNode

View File

@@ -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

View 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

View File

@@ -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())

View File

@@ -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;

View File

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

View File

@@ -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 ---\n";
} }
Disassembler::Format Disassembler::GetFormat(OpCode op) Disassembler::Format Disassembler::GetFormat(OpCode op)

View File

@@ -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)

View File

@@ -1,6 +1,6 @@
/*! /*!
@file src/Compiler/ExprCompiler.cpp @file src/Compiler/ExprCompiler.cpp
@brief 表达式编译器实现:引入水位线(Watermark)与零拷贝复用机制 @brief 表达式编译器实现:水位线控制Register与零拷贝复用机制
*/ */
#include <Ast/Expr/CallExpr.hpp> #include <Ast/Expr/CallExpr.hpp>
@@ -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)
@@ -20,46 +19,69 @@ namespace Fig
char buffer[128]; char buffer[128];
int j = 0; int j = 0;
bool isFloat = false; bool isFloat = false;
for (size_t i = 0; i < raw.length() && j < 127; ++i) for (size_t i = 0; i < raw.length() && j < 127; ++i)
{ {
char32_t c = raw[i]; char32_t c = raw[i];
if (c == '_') if (c == '_')
continue; continue;
// 检查开头的无效字符
if (j == 0 && (c == '.' || c == 'e' || c == 'E'))
return std::unexpected(
Error(ErrorType::SyntaxError, "unexpected leading character", "", loc));
if (c == '.' || c == 'e' || c == 'E') if (c == '.' || c == 'e' || c == 'E')
isFloat = true; isFloat = true;
buffer[j++] = (char) c; buffer[j++] = (char) c;
} }
buffer[j] = '\0'; buffer[j] = '\0';
// 检查16进制/2进制前缀
bool isHexOrBin = false;
int base = 10;
const char *start = buffer;
if (j >= 2 && buffer[0] == '0')
{
if (buffer[1] == 'x' || buffer[1] == 'X')
{
base = 16;
start += 2;
isHexOrBin = true;
}
else if (buffer[1] == 'b' || buffer[1] == 'B')
{
base = 2;
start += 2;
isHexOrBin = true;
}
}
if (isFloat) if (isFloat)
{ {
// 如果既有浮点标记又是0x开头可能是16进制浮点
auto fmt =
(isHexOrBin && base == 16) ? std::chars_format::hex : std::chars_format::general;
double dVal; double dVal;
auto [ptr, ec] = std::from_chars(buffer, buffer + j, dVal); auto [ptr, ec] = std::from_chars(start, buffer + j, dVal, fmt);
if (ec != std::errc())
return std::unexpected(Error(ErrorType::SyntaxError, "float overflow", "", loc)); if (ec != std::errc() || ptr != buffer + j)
return std::unexpected(
Error(ErrorType::SyntaxError, "invalid float literal", "", loc));
return Value::FromDouble(dVal); return Value::FromDouble(dVal);
} }
else else if (isHexOrBin)
{ {
int base = 10; // 16进制或2进制整数
const char *start = buffer;
if (j > 2 && buffer[0] == '0')
{
if (buffer[1] == 'x' || buffer[1] == 'X')
{
base = 16;
start += 2;
}
else if (buffer[1] == 'b' || buffer[1] == 'B')
{
base = 2;
start += 2;
}
}
int64_t iVal; int64_t iVal;
auto [ptr, ec] = std::from_chars(start, buffer + j, iVal, base); auto [ptr, ec] = std::from_chars(start, buffer + j, iVal, base);
if (ec != std::errc())
return std::unexpected(Error(ErrorType::SyntaxError, "integer overflow", "", loc)); if (ec != std::errc() || ptr != buffer + j)
return std::unexpected(
Error(ErrorType::SyntaxError, "integer overflow or invalid literal", "", loc));
if (iVal >= std::numeric_limits<int32_t>::min() if (iVal >= std::numeric_limits<int32_t>::min()
&& iVal <= std::numeric_limits<int32_t>::max()) && iVal <= std::numeric_limits<int32_t>::max())
@@ -71,6 +93,27 @@ namespace Fig
return Value::FromDouble(static_cast<double>(iVal)); return Value::FromDouble(static_cast<double>(iVal));
} }
} }
else
{
// 10进制数字可能是整数或浮点数
double dVal;
auto [ptr, ec] = std::from_chars(start, buffer + j, dVal, std::chars_format::general);
if (ec != std::errc() || ptr != buffer + j)
return std::unexpected(
Error(ErrorType::SyntaxError, "invalid number literal", "", loc));
// 检查是否是整数(没有小数部分且不超出int32范围)
if (dVal == std::floor(dVal) && dVal >= std::numeric_limits<int32_t>::min()
&& dVal <= std::numeric_limits<int32_t>::max())
{
return Value::FromInt(static_cast<int32_t>(dVal));
}
else
{
return Value::FromDouble(dVal);
}
}
} }
Result<Register, Error> Compiler::compileExpr(Expr *expr, Register target) Result<Register, Error> Compiler::compileExpr(Expr *expr, Register target)
@@ -94,7 +137,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 +174,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 +184,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,10 +225,12 @@ namespace Fig
{ {
isGlobalFastCall = true; isGlobalFastCall = true;
int protoIdx = id->resolvedSymbol->index; int protoIdx = id->resolvedSymbol->index;
emit(Op::iABC(OpCode::FastCall, emit(
static_cast<uint8_t>(protoIdx), Op::iABC(
baseReg, OpCode::FastCall,
static_cast<uint8_t>(c->args.args.size())), static_cast<uint8_t>(protoIdx),
baseReg,
static_cast<uint8_t>(c->args.args.size())),
&c->location); &c->location);
} }
} }
@@ -193,10 +244,12 @@ namespace Fig
return std::unexpected(r_fn.error()); return std::unexpected(r_fn.error());
// 使用动态 Call 指令RA 是指向堆闭包的寄存器 // 使用动态 Call 指令RA 是指向堆闭包的寄存器
emit(Op::iABC(OpCode::Call, emit(
*r_fn, Op::iABC(
baseReg, OpCode::Call,
static_cast<uint8_t>(c->args.args.size())), *r_fn,
baseReg,
static_cast<uint8_t>(c->args.args.size())),
&c->location); &c->location);
} }
@@ -240,18 +293,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(
*r_val, Op::iABx(
static_cast<uint16_t>(getGlobalID(lid->name))), &lid->location); OpCode::SetGlobal,
*r_val,
static_cast<uint16_t>(getGlobalID(lid->name))),
&lid->location);
} }
} }
return r_val; return r_val;
@@ -271,29 +331,61 @@ namespace Fig
OpCode op; OpCode op;
switch (in->op) switch (in->op)
{ {
case BinaryOperator::Add: op = isInt ? OpCode::IntFastAdd : OpCode::Add; break; case BinaryOperator::Add: {
case BinaryOperator::Subtract: op = (isInt ? (OpCode::IntFastAdd) : (OpCode::Add));
op = isInt ? OpCode::IntFastSub : OpCode::Sub;
break; break;
case BinaryOperator::Multiply: }
op = isInt ? OpCode::IntFastMul : OpCode::Mul; case BinaryOperator::Subtract: {
op = (isInt ? (OpCode::IntFastSub) : (OpCode::Sub));
break; break;
case BinaryOperator::Divide: }
op = isInt ? OpCode::IntFastDiv : OpCode::Div; case BinaryOperator::Multiply: {
op = (isInt ? (OpCode::IntFastMul) : (OpCode::Mul));
break; break;
case BinaryOperator::Modulo: op = OpCode::Mod; break; }
case BinaryOperator::BitXor: op = OpCode::BitXor; break; case BinaryOperator::Divide: {
case BinaryOperator::Equal: op = OpCode::Equal; break; op = (isInt ? (OpCode::IntFastDiv) : (OpCode::Div));
case BinaryOperator::NotEqual: op = OpCode::NotEqual; break; break;
case BinaryOperator::Greater: op = OpCode::Greater; break; }
case BinaryOperator::Less: op = OpCode::Less; break; case BinaryOperator::Modulo: {
case BinaryOperator::GreaterEqual: op = OpCode::GreaterEqual; break; op = OpCode::Mod;
case BinaryOperator::LessEqual: op = OpCode::LessEqual; break; break;
default: }
return std::unexpected(Error(ErrorType::InternalError, case BinaryOperator::BitXor: {
op = OpCode::BitXor;
break;
}
case BinaryOperator::Equal: {
op = OpCode::Equal;
break;
}
case BinaryOperator::NotEqual: {
op = OpCode::NotEqual;
break;
}
case BinaryOperator::Greater: {
op = OpCode::Greater;
break;
}
case BinaryOperator::Less: {
op = OpCode::Less;
break;
}
case BinaryOperator::GreaterEqual: {
op = OpCode::GreaterEqual;
break;
}
case BinaryOperator::LessEqual: {
op = OpCode::LessEqual;
break;
}
default: {
return std::unexpected(Error(
ErrorType::InternalError,
"unsupported binary operator", "unsupported binary operator",
"", "",
in->location)); in->location));
}
} }
// 释放左右操作数产生的临时寄存器 // 释放左右操作数产生的临时寄存器
@@ -318,6 +410,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(

View File

@@ -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";
@@ -69,10 +75,10 @@ namespace Fig
void PrintSystemInfos() void PrintSystemInfos()
{ {
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();
@@ -83,35 +89,43 @@ namespace Fig
void PrintErrorInfo(const Error &error, const SourceManager &srcManager) void PrintErrorInfo(const Error &error, const SourceManager &srcManager)
{ {
static constexpr const char *MinorColor = "\033[38;2;138;227;198m"; static constexpr const char *MinorColor = "\033[38;2;138;227;198m";
static constexpr const char *MediumColor = "\033[38;2;255;199;95m"; static constexpr const char *MediumColor = "\033[38;2;255;199;95m";
static constexpr const char *CriticalColor = "\033[38;2;255;107;107m"; static constexpr const char *CriticalColor = "\033[38;2;255;107;107m";
namespace TC = TerminalColors; namespace TC = TerminalColors;
std::ostream &err = CoreIO::GetStdErr(); std::ostream &err = CoreIO::GetStdErr();
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);

View File

@@ -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,
}; };

View File

@@ -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);
} }
}; };

View File

@@ -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;

View File

@@ -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,7 +136,11 @@ namespace Fig
ParsingReturn, ParsingReturn,
ParsingBreak, ParsingBreak,
ParsingContinue, ParsingContinue,
ParsingStructDef,
ParsingTypeParameters,
ParsingNamedTypeExpr, ParsingNamedTypeExpr,
ParsingFnTypeExpr,
} type = StateType::Standby; } type = StateType::Standby;
std::unordered_set<TokenType> stopAt = {}; std::unordered_set<TokenType> stopAt = {};
}; };
@@ -137,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,
@@ -200,34 +212,58 @@ 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<Expr *, Error> parseExpression(BindingPower = 0); Result<Expr *, Error> parseExpression(BindingPower = 0);
Result<Expr *, Error> parseLiteralExpr(); Result<Expr *, Error> parseLiteralExpr();
@@ -237,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);
@@ -253,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());
} }

View File

@@ -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)
{ {

View File

@@ -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) BlockStmt *body = nullptr;
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)
{
return std::unexpected(bodyResult.error());
}
body = *bodyResult;
}
else
{ {
return std::unexpected( return std::unexpected(
makeUnexpectTokenError("fn def stmt", "function body '{'", currentToken())); makeUnexpectTokenError("fn def stmt", "function body '=>' / '{'", currentToken()));
} }
BlockStmt *body = nullptr;
auto bodyResult = parseBlockStmt();
if (!bodyResult)
{
return std::unexpected(bodyResult.error());
}
body = *bodyResult;
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)
{ {

View File

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

View File

@@ -38,15 +38,18 @@ namespace Fig
void PrintInfo() void PrintInfo()
{ {
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,
Core::PLATFORM); Core::PLATFORM);
out << "Type '#exit' to exit, '#clear' to clear the the screen, '#license' to see the full license, '#logo' to see a GREAT logo\n"; out << "Type '#exit' to exit, '#clear' to clear the the screen, '#license' to see the full license, '#logo' to see a GREAT logo\n";
out << '\n';
} }
void ClearConsole() void ClearConsole()
@@ -146,17 +149,58 @@ namespace Fig
++rline; ++rline;
} }
} }
// void PrintError(const Error &error, const String &source)
// {
// err << "Oops! An error occurred!";
// err << "🔥 " << 'E' << static_cast<int>(error.type) << ": " << error.message << '\n';
// err << "Line " << rline << ", `" << source << "`\n";
// err << "Suggestion: " << error.suggestion << '\n';
// err << std::format(
// "Thrower: {} ({}:{}:{})\n",
// error.thrower_loc.function_name(),
// error.thrower_loc.file_name(),
// error.thrower_loc.line(),
// error.thrower_loc.column());
// }
void PrintError(const Error &error, const String &source) void PrintError(const Error &error, const String &source)
{ {
err << "Oops! An error occurred!"; static constexpr const char *MinorColor = "\033[38;2;138;227;198m";
err << "🔥 " << 'E' << static_cast<int>(error.type) << ": " << error.message << '\n'; static constexpr const char *MediumColor = "\033[38;2;255;199;95m";
err << "Line " << rline << ", `" << source << "`\n"; static constexpr const char *CriticalColor = "\033[38;2;255;107;107m";
err << "Suggestion: " << error.suggestion << '\n';
err << std::format("Thrower: {} ({}:{}:{})\n", namespace TC = TerminalColors;
error.thrower_loc.function_name(), std::ostream &err = CoreIO::GetStdErr();
error.thrower_loc.file_name(),
error.thrower_loc.line(), uint8_t level = ErrorLevel(error.type);
error.thrower_loc.column()); // const char *level_name = (level == 1 ? "Minor" : (level == 2 ? "Medium" :
// "Critical"));
const char *const &level_color =
(level == 1 ? MinorColor : (level == 2 ? MediumColor : CriticalColor));
err << "\n";
err << "🔥 "
<< level_color
//<< '(' << level_name << ')'
<< 'E' << static_cast<int>(error.type) << TC::Reset << ": " << level_color
<< ErrorTypeToString(error.type) << TC::Reset << '\n';
const SourceLocation &location = error.location;
err << TC::DarkGray << " ┌─> Fn " << TC::Cyan << '\'' << location.packageName << '.'
<< location.functionName << '\'' << " " << location.fileName << " (" << TC::DarkGray
<< location.sp.line << ":" << location.sp.column << TC::Cyan << ')' << TC::Reset
<< '\n';
err << TC::DarkGray << "" << '\n' << "" << TC::Reset << '\n';
err << TC::DarkGray << " └─ " << TC::Reset;
err << source << "\n";
err << "\n";
err << "" << TC::DarkGray << "Thrower: " << error.thrower_loc.function_name() << " ("
<< error.thrower_loc.file_name() << ":" << error.thrower_loc.line() << ")"
<< TC::Reset << "\n";
err << "💡 " << TC::Blue << "Suggestion: " << error.suggestion << TC::Reset;
err << '\n';
} }
unsigned int Start() // exit code: unsigned int unsigned int Start() // exit code: unsigned int
@@ -208,8 +252,11 @@ 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 +270,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 +287,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);

View File

@@ -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,19 +535,22 @@ 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::TypeError, return std::unexpected(Error(
"expected " + std::to_string(ft->paramTypes.size()) + " arguments, got " ErrorType::SyntaxError,
+ std::to_string(argTypes.size()), std::format(
"", "expected {} arguments, got {}", 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)
{ {
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)
@@ -607,13 +707,46 @@ namespace Fig
return std::unexpected( return std::unexpected(
Error(ErrorType::UseUndeclaredIdentifier, "unknown type", "", texpr->location)); Error(ErrorType::UseUndeclaredIdentifier, "unknown type", "", texpr->location));
} }
if (texpr->type == AstType::NullableTypeExpr) else if (texpr->type == AstType::NullableTypeExpr)
{ {
auto res = resolveTypeExpr(static_cast<NullableTypeExpr *>(texpr)->inner); auto res = resolveTypeExpr(static_cast<NullableTypeExpr *>(texpr)->inner);
if (res) if (!res)
res->isNullable = true; {
return res;
}
res->isNullable = true;
return res; return res;
} }
else if (texpr->type == AstType::FnTypeExpr)
{
auto f = static_cast<FnTypeExpr *>(texpr);
DynArray<Type> paraTypes;
Type returnType = typeCtx.GetBasic(TypeTag::Any);
for (auto &pt : f->paraTypes)
{
auto result = resolveTypeExpr(pt);
if (!result)
{
return result;
}
paraTypes.push_back(*result);
}
if (f->returnType)
{
auto result = resolveTypeExpr(f->returnType);
if (!result)
{
return result;
}
returnType = *result;
}
return typeCtx.CreateFuncType(paraTypes, returnType);
}
return typeCtx.GetBasic(TypeTag::Any); return typeCtx.GetBasic(TypeTag::Any);
} }
} // namespace Fig } // namespace Fig

View File

@@ -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)

View File

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

View File

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

View File

@@ -5,26 +5,62 @@
@date 2026-03-13 @date 2026-03-13
*/ */
#include <VM/Entry.hpp> #include <VM/Entry.hpp>
#include <chrono>
#include <filesystem> #include <filesystem>
#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 <Repl/Repl.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;
using clock = std::chrono::steady_clock;
auto format_print_time = [](std::chrono::nanoseconds nsecs) {
auto &out = CoreIO::GetStdOut();
auto count = nsecs.count();
auto old_flags = out.flags();
auto old_precision = out.precision();
if (count < 1'000)
{
// < 1μs 纳秒
out << count << "ns";
}
else if (count < 1'000'000)
{
// 1μs ~ 1ms 微秒 保留 2 位小数
out << std::fixed << std::setprecision(2) << (count / 1'000.0) << "μs";
}
else if (count < 1'000'000'000)
{
// 1ms ~ 1s 毫秒 保留 2 位小数
out << std::fixed << std::setprecision(2) << (count / 1'000'000.0) << "ms";
}
else
{
// >= 1s 秒 保留 3 位小数
out << std::fixed << std::setprecision(3) << (count / 1'000'000'000.0) << "s";
}
out.flags(old_flags);
out.precision(old_precision);
};
fs::path _fspath(path.toStdString()); fs::path _fspath(path.toStdString());
if (!fs::exists(_fspath)) if (!fs::exists(_fspath))
@@ -49,22 +85,32 @@ namespace Fig::Entry
CoreIO::GetStdErr() << "Could not read file: " << path << '\n'; CoreIO::GetStdErr() << "Could not read file: " << path << '\n';
std::exit(1); std::exit(1);
} }
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_start = clock::now();
auto parse_result = parser.Parse(); auto parse_result = parser.Parse();
auto parse_end = clock::now();
if (!parse_result) if (!parse_result)
{ {
ReportError(parse_result.error(), manager); ReportError(parse_result.error(), manager);
std::exit(1); std::exit(1);
} }
Program *program = *parse_result; Program *program = *parse_result;
Analyzer analyer(manager); Analyzer analyer(manager);
auto analyze_start = clock::now();
auto analyze_result = analyer.Analyze(program); auto analyze_result = analyer.Analyze(program);
auto analyze_end = clock::now();
if (!analyze_result) if (!analyze_result)
{ {
@@ -72,10 +118,12 @@ namespace Fig::Entry
std::exit(1); std::exit(1);
} }
Diagnostics diagnostics;
Compiler compiler(manager, diagnostics); Compiler compiler(manager, diagnostics);
auto compile_start = clock::now();
auto compile_result = compiler.Compile(program); auto compile_result = compiler.Compile(program);
auto compile_end = clock::now();
diagnostics.EmitAll(manager); diagnostics.EmitAll(manager);
if (!compile_result) if (!compile_result)
@@ -86,15 +134,66 @@ namespace Fig::Entry
CompiledModule *compiledModule = *compile_result; CompiledModule *compiledModule = *compile_result;
if (conf.dump)
{
Disassembler disassembler;
disassembler.DisassembleModule(compiledModule);
}
VM vm; VM vm;
auto execute_start = clock::now();
auto execute_result = vm.Execute(compiledModule); auto execute_result = vm.Execute(compiledModule);
auto execute_end = clock::now();
if (!execute_result) if (!execute_result)
{ {
ReportError(execute_result.error(), manager); ReportError(execute_result.error(), manager);
std::exit(1); std::exit(1);
} }
if (conf.pregs)
{
vm.PrintRegisters();
}
if (conf.time)
{
auto parse_time = parse_end - parse_start;
CoreIO::GetStdOut() << "Parse: ";
format_print_time(parse_time);
CoreIO::GetStdOut() << " | ";
auto analyze_time = analyze_end - analyze_start;
CoreIO::GetStdOut() << "Analyze: ";
format_print_time(analyze_time);
CoreIO::GetStdOut() << " | ";
auto compile_time = compile_end - compile_start;
CoreIO::GetStdOut() << "Compile: ";
format_print_time(compile_time);
CoreIO::GetStdOut() << " | ";
auto execute_time = execute_end - execute_start;
CoreIO::GetStdOut() << "Execute: ";
format_print_time(execute_time);
CoreIO::GetStdOut() << " | ";
auto total = parse_time + analyze_time + compile_time + execute_time;
CoreIO::GetStdOut() << "Total: ";
format_print_time(total);
CoreIO::GetStdOut() << '\n';
}
delete compiledModule; delete compiledModule;
} }
std::uint32_t RunRepl()
{
Repl repl(CoreIO::GetStdCin(), CoreIO::GetStdOut(), CoreIO::GetStdErr());
std::uint32_t result = repl.Start();
CoreIO::GetStdOut() << "Repl exited with code " << result << '\n';
return result;
}
}; // namespace Fig::Entry }; // namespace Fig::Entry

View File

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

View File

@@ -209,8 +209,9 @@ namespace Fig
"none", "none",
*currentFrame->proto->locations[ipIdx])); *currentFrame->proto->locations[ipIdx]));
} }
else else [[likely]]
{ {
Object *obj = callee.AsObject(); Object *obj = callee.AsObject();
if (!obj->isFunction()) if (!obj->isFunction())
{ {

View File

@@ -329,7 +329,7 @@ namespace Fig
Op::iAsBx(OpCode::Exit_MaxRecursionDepthExceeded, 0, 0); Op::iAsBx(OpCode::Exit_MaxRecursionDepthExceeded, 0, 0);
return &POISON_MAX_RECURSION_DEPTH_EXCEED_INST; return &POISON_MAX_RECURSION_DEPTH_EXCEED_INST;
} }
[[likely]]
*currentFrame = CallFrame{nullptr, proto, proto->code.data(), base}; *currentFrame = CallFrame{nullptr, proto, proto->code.data(), base};
return currentFrame->ip; return currentFrame->ip;
} }
@@ -343,7 +343,7 @@ namespace Fig
Op::iAsBx(OpCode::Exit_MaxRecursionDepthExceeded, 0, 0); Op::iAsBx(OpCode::Exit_MaxRecursionDepthExceeded, 0, 0);
return &POISON_MAX_RECURSION_DEPTH_EXCEED_INST; return &POISON_MAX_RECURSION_DEPTH_EXCEED_INST;
} }
[[likely]]
*currentFrame = CallFrame{closure, closure->proto, closure->proto->code.data(), base}; *currentFrame = CallFrame{closure, closure->proto, closure->proto->code.data(), base};
return currentFrame->ip; return currentFrame->ip;
} }

View File

@@ -19,9 +19,13 @@ int main(int argc, char **argv)
ArgParser::ArgumentParser argparser("Fig", "Fig Toolchain"); ArgParser::ArgumentParser argparser("Fig", "Fig Toolchain");
argparser.AddFlag('r', "repl");
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");
argparser.AddFlag("pregs").Help("Print vm non-null registers");
argparser.AddFlag("time").Help("Print the execution time");
auto res = argparser.Parse(argc, argv); auto res = argparser.Parse(argc, argv);
if (!res) if (!res)
@@ -32,9 +36,13 @@ int main(int argc, char **argv)
auto &args = *res; auto &args = *res;
bool runRepl = args.HasFlag("repl");
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");
bool pregs = args.HasFlag("pregs");
bool time = args.HasFlag("time");
if (showHelp) if (showHelp)
{ {
@@ -44,10 +52,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,
@@ -66,6 +76,11 @@ int main(int argc, char **argv)
return 0; return 0;
} }
if (runRepl)
{
return Entry::RunRepl();
}
if (posSize > 1) if (posSize > 1)
{ {
err << "Error: Too more positionals, expect 1. Use Fig [Fig source code file (.fig)]\n"; err << "Error: Too more positionals, expect 1. Use Fig [Fig source code file (.fig)]\n";
@@ -77,8 +92,10 @@ int main(int argc, char **argv)
return 1; return 1;
} }
Entry::Config config{.mode = Entry::Config::Normal, .dump = dump, .pregs = pregs, .time = time};
const String &path = positionals.front(); const String &path = positionals.front();
Entry::RunFromPath(path); Entry::RunFromPath(path, config);
return 0; return 0;
} }

View File

@@ -15,6 +15,10 @@ elseif is_plat("windows") then
add_ldflags("-Wl,--stack,268435456") add_ldflags("-Wl,--stack,268435456")
end end
if is_mode("release") then
set_optimize("fastest")
end
set_languages("c++23") set_languages("c++23")
add_includedirs("src") add_includedirs("src")