From 98de782760aec8d2ba63ffc91f98833a185ab656 Mon Sep 17 00:00:00 2001 From: PuqiAR Date: Thu, 30 Apr 2026 21:24:11 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0repl=E5=85=A5?= =?UTF-8?q?=E5=8F=A3=EF=BC=8C-r/--repl=E3=80=82=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E8=AE=A1=E6=97=B6=E9=80=89=E9=A1=B9=E3=80=82=20=20--=20?= =?UTF-8?q?=E6=88=91=E5=8F=91=E7=8E=B0=E4=B8=80=E4=B8=AA=E9=97=AE=E9=A2=98?= =?UTF-8?q?=EF=BC=8Canalyzer=E6=B2=A1=E6=B3=95=E4=BF=9D=E5=AD=98=E7=8E=AF?= =?UTF-8?q?=E5=A2=83=E3=80=82=E5=AE=8C=E4=BA=86=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Bytecode/Disassembler.cpp | 2 +- src/Compiler/ExprCompiler.cpp | 151 +++++++++++++++++++++++++--------- src/Repl/Repl.hpp | 68 ++++++++++++--- src/VM/Entry.cpp | 93 ++++++++++++++++++++- src/VM/Entry.hpp | 3 + src/VM/VM.hpp | 4 +- src/main.cpp | 11 ++- 7 files changed, 274 insertions(+), 58 deletions(-) diff --git a/src/Bytecode/Disassembler.cpp b/src/Bytecode/Disassembler.cpp index b666233..d34f49a 100644 --- a/src/Bytecode/Disassembler.cpp +++ b/src/Bytecode/Disassembler.cpp @@ -75,7 +75,7 @@ namespace Fig stream << std::format(" [{}] {}\n", i, proto->constants[i].ToString()); } } - stream << "--- End Disassembly ---"; + stream << "--- End Disassembly ---\n"; } Disassembler::Format Disassembler::GetFormat(OpCode op) diff --git a/src/Compiler/ExprCompiler.cpp b/src/Compiler/ExprCompiler.cpp index 79797c7..ab6a1a9 100644 --- a/src/Compiler/ExprCompiler.cpp +++ b/src/Compiler/ExprCompiler.cpp @@ -1,6 +1,6 @@ /*! @file src/Compiler/ExprCompiler.cpp - @brief 表达式编译器实现:引入水位线(Watermark)与零拷贝复用机制 + @brief 表达式编译器实现:水位线控制Register与零拷贝复用机制 */ #include @@ -19,46 +19,69 @@ namespace Fig char buffer[128]; int j = 0; bool isFloat = false; + for (size_t i = 0; i < raw.length() && j < 127; ++i) { char32_t c = raw[i]; if (c == '_') 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') isFloat = true; buffer[j++] = (char) c; } 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) { + // 如果既有浮点标记又是0x开头,可能是16进制浮点 + auto fmt = + (isHexOrBin && base == 16) ? std::chars_format::hex : std::chars_format::general; + double dVal; - auto [ptr, ec] = std::from_chars(buffer, buffer + j, dVal); - if (ec != std::errc()) - return std::unexpected(Error(ErrorType::SyntaxError, "float overflow", "", loc)); + auto [ptr, ec] = std::from_chars(start, buffer + j, dVal, fmt); + + if (ec != std::errc() || ptr != buffer + j) + return std::unexpected( + Error(ErrorType::SyntaxError, "invalid float literal", "", loc)); + return Value::FromDouble(dVal); } - else + else if (isHexOrBin) { - int base = 10; - 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; - } - } + // 16进制或2进制整数 int64_t iVal; 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::min() && iVal <= std::numeric_limits::max()) @@ -70,6 +93,27 @@ namespace Fig return Value::FromDouble(static_cast(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::min() + && dVal <= std::numeric_limits::max()) + { + return Value::FromInt(static_cast(dVal)); + } + else + { + return Value::FromDouble(dVal); + } + } } Result Compiler::compileExpr(Expr *expr, Register target) @@ -287,30 +331,61 @@ namespace Fig OpCode op; switch (in->op) { - case BinaryOperator::Add: op = isInt ? OpCode::IntFastAdd : OpCode::Add; break; - case BinaryOperator::Subtract: - op = isInt ? OpCode::IntFastSub : OpCode::Sub; + case BinaryOperator::Add: { + op = (isInt ? (OpCode::IntFastAdd) : (OpCode::Add)); break; - case BinaryOperator::Multiply: - op = isInt ? OpCode::IntFastMul : OpCode::Mul; + } + case BinaryOperator::Subtract: { + op = (isInt ? (OpCode::IntFastSub) : (OpCode::Sub)); break; - case BinaryOperator::Divide: - op = isInt ? OpCode::IntFastDiv : OpCode::Div; + } + case BinaryOperator::Multiply: { + op = (isInt ? (OpCode::IntFastMul) : (OpCode::Mul)); break; - case BinaryOperator::Modulo: op = OpCode::Mod; break; - 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: + } + case BinaryOperator::Divide: { + op = (isInt ? (OpCode::IntFastDiv) : (OpCode::Div)); + break; + } + case BinaryOperator::Modulo: { + op = OpCode::Mod; + break; + } + 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", "", in->location)); + } } // 释放左右操作数产生的临时寄存器 diff --git a/src/Repl/Repl.hpp b/src/Repl/Repl.hpp index 0935c7e..1d8db4c 100644 --- a/src/Repl/Repl.hpp +++ b/src/Repl/Repl.hpp @@ -38,15 +38,18 @@ namespace Fig 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::LICENSE); - out << std::format("Build time: {} [{} x{} on {}]\n", + out << std::format( + "Build time: {} [{} x{} on {}]\n", Core::COMPILE_TIME, Core::COMPILER, Core::ARCH, 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 << '\n'; } void ClearConsole() @@ -146,17 +149,58 @@ namespace Fig ++rline; } } + // void PrintError(const Error &error, const String &source) + // { + // err << "Oops! An error occurred!"; + // err << "🔥 " << 'E' << static_cast(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) { - err << "Oops! An error occurred!"; - err << "🔥 " << 'E' << static_cast(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()); + 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 *CriticalColor = "\033[38;2;255;107;107m"; + + namespace TC = TerminalColors; + std::ostream &err = CoreIO::GetStdErr(); + + uint8_t level = ErrorLevel(error.type); + // 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(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 @@ -208,7 +252,7 @@ namespace Fig String source(buf); - Lexer lexer(buf, fileName); + Lexer lexer(buf, fileName); Diagnostics diagnostics; diff --git a/src/VM/Entry.cpp b/src/VM/Entry.cpp index 4992fce..1d023d5 100644 --- a/src/VM/Entry.cpp +++ b/src/VM/Entry.cpp @@ -7,6 +7,7 @@ #include +#include #include #include @@ -16,16 +17,50 @@ #include #include #include +#include #include #include - namespace Fig::Entry { void RunFromPath(const String &path, const Config &conf) { 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()); if (!fs::exists(_fspath)) @@ -53,22 +88,29 @@ namespace Fig::Entry const String &source = manager.GetSource(); - Lexer lexer(source, fileName); + Lexer lexer(source, fileName); Diagnostics diagnostics; Parser parser(lexer, manager, fileName, diagnostics); + auto parse_start = clock::now(); auto parse_result = parser.Parse(); + auto parse_end = clock::now(); + if (!parse_result) { ReportError(parse_result.error(), manager); std::exit(1); } + Program *program = *parse_result; Analyzer analyer(manager); - auto analyze_result = analyer.Analyze(program); + + auto analyze_start = clock::now(); + auto analyze_result = analyer.Analyze(program); + auto analyze_end = clock::now(); if (!analyze_result) { @@ -76,9 +118,12 @@ namespace Fig::Entry std::exit(1); } - Compiler compiler(manager, diagnostics); + Compiler compiler(manager, diagnostics); + auto compile_start = clock::now(); auto compile_result = compiler.Compile(program); + auto compile_end = clock::now(); + diagnostics.EmitAll(manager); if (!compile_result) @@ -97,7 +142,10 @@ namespace Fig::Entry VM vm; + auto execute_start = clock::now(); auto execute_result = vm.Execute(compiledModule); + auto execute_end = clock::now(); + if (!execute_result) { ReportError(execute_result.error(), manager); @@ -109,6 +157,43 @@ namespace Fig::Entry 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; } + + 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 \ No newline at end of file diff --git a/src/VM/Entry.hpp b/src/VM/Entry.hpp index e5b33d1..a4492f0 100644 --- a/src/VM/Entry.hpp +++ b/src/VM/Entry.hpp @@ -18,6 +18,9 @@ namespace Fig::Entry } mode; bool dump; bool pregs; + bool time; }; + void RunFromPath(const String &, const Config &conf); + std::uint32_t RunRepl(); }; \ No newline at end of file diff --git a/src/VM/VM.hpp b/src/VM/VM.hpp index a699bf1..48708ee 100644 --- a/src/VM/VM.hpp +++ b/src/VM/VM.hpp @@ -329,7 +329,7 @@ namespace Fig Op::iAsBx(OpCode::Exit_MaxRecursionDepthExceeded, 0, 0); return &POISON_MAX_RECURSION_DEPTH_EXCEED_INST; } - + [[likely]] *currentFrame = CallFrame{nullptr, proto, proto->code.data(), base}; return currentFrame->ip; } @@ -343,7 +343,7 @@ namespace Fig Op::iAsBx(OpCode::Exit_MaxRecursionDepthExceeded, 0, 0); return &POISON_MAX_RECURSION_DEPTH_EXCEED_INST; } - + [[likely]] *currentFrame = CallFrame{closure, closure->proto, closure->proto->code.data(), base}; return currentFrame->ip; } diff --git a/src/main.cpp b/src/main.cpp index fc62882..882d7a7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,11 +19,13 @@ int main(int argc, char **argv) ArgParser::ArgumentParser argparser("Fig", "Fig Toolchain"); + argparser.AddFlag('r', "repl"); argparser.AddFlag('h', "help").Help("Print the help message"); argparser.AddFlag('v', "version").Help("Show toolchain version"); argparser.AddFlag("license").Help("Print the license text"); argparser.AddFlag("dump").Help("Dump the bytecode"); argparser.AddFlag("pregs").Help("Print vm non-null registers"); + argparser.AddFlag("time").Help("Print the execution time"); auto res = argparser.Parse(argc, argv); if (!res) @@ -34,11 +36,13 @@ int main(int argc, char **argv) auto &args = *res; + bool runRepl = args.HasFlag("repl"); bool showHelp = args.HasFlag("help"); bool showVersion = args.HasFlag("version"); bool showLicense = args.HasFlag("license"); bool dump = args.HasFlag("dump"); bool pregs = args.HasFlag("pregs"); + bool time = args.HasFlag("time"); if (showHelp) { @@ -72,6 +76,11 @@ int main(int argc, char **argv) return 0; } + if (runRepl) + { + return Entry::RunRepl(); + } + if (posSize > 1) { err << "Error: Too more positionals, expect 1. Use Fig [Fig source code file (.fig)]\n"; @@ -83,7 +92,7 @@ int main(int argc, char **argv) return 1; } - Entry::Config config{.mode = Entry::Config::Normal, .dump = dump, .pregs = pregs}; + Entry::Config config{.mode = Entry::Config::Normal, .dump = dump, .pregs = pregs, .time = time}; const String &path = positionals.front(); Entry::RunFromPath(path, config);