refact:实现参数解析器和入口点
- 新增了一个名为 ArgumentParser 的类来处理命令行参数,其中包括用于显示帮助、显示版本和显示许可证的标志。 - 更新了 main.cpp 以使用 ArgumentParser 来改进命令行界面。 - 创建了 Entry.cpp 和 Entry.hpp 来封装虚拟机执行逻辑,从而实现更好的关注点分离。 - 调整了 xmake.lua 以包含 ArgumentParser 和 Entry 组件的新源文件。 - 强化了命令行使用的错误处理和用户反馈。
This commit is contained in:
9
LICENSE
9
LICENSE
@@ -13,15 +13,6 @@ furnished to do so, subject to the following conditions:
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
2. This project includes code from the following projects with their respective licenses:
|
||||
- argparse (MIT License)
|
||||
Copyright (c) 2018 Pranav Srinivas Kumar <pranav.srinivas.kumar@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
- magic_enum (MIT License)
|
||||
Copyright (c) 2019 - 2024 Daniil Goncharov
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ namespace Fig
|
||||
|
||||
const std::string LICENSE_TEXT =
|
||||
R"(
|
||||
MIT License (Fig)
|
||||
MIT License (Fig)
|
||||
|
||||
Copyright (c) 2026 PuqiAR <im@puqiar.top>
|
||||
|
||||
@@ -95,15 +95,6 @@ furnished to do so, subject to the following conditions:
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
2. This project includes code from the following projects with their respective licenses:
|
||||
- argparse (MIT License)
|
||||
Copyright (c) 2018 Pranav Srinivas Kumar <pranav.srinivas.kumar@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
- magic_enum (MIT License)
|
||||
Copyright (c) 2019 - 2024 Daniil Goncharov
|
||||
|
||||
@@ -145,6 +136,7 @@ furnished to do so, subject to the following conditions:
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
)";
|
||||
|
||||
}; // namespace Core
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace Fig
|
||||
|
||||
void PrintInfo()
|
||||
{
|
||||
out << std::format("Fig {} copyright (c) 2025-2026 PuqiAR, under the {} License",
|
||||
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",
|
||||
|
||||
@@ -87,7 +87,7 @@ namespace Fig
|
||||
{String("try"), TokenType::Try},
|
||||
{String("catch"), TokenType::Catch},
|
||||
{String("throw"), TokenType::Throw},
|
||||
{String("Finally"), TokenType::Finally},
|
||||
{String("finally"), TokenType::Finally},
|
||||
{String("as"), TokenType::As},
|
||||
{String("true"), TokenType::LiteralTrue},
|
||||
{String("false"), TokenType::LiteralFalse},
|
||||
|
||||
336
src/Utils/ArgParser/ArgParser.hpp
Normal file
336
src/Utils/ArgParser/ArgParser.hpp
Normal file
@@ -0,0 +1,336 @@
|
||||
#pragma once
|
||||
|
||||
#include <Deps/Deps.hpp>
|
||||
#include <expected>
|
||||
#include <format>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include <string_view>
|
||||
|
||||
namespace Fig::ArgParser
|
||||
{
|
||||
|
||||
enum class ParseErrorCode
|
||||
{
|
||||
UnknownOption,
|
||||
MissingValue,
|
||||
MissingRequired,
|
||||
InvalidFormat
|
||||
};
|
||||
|
||||
struct ParseError
|
||||
{
|
||||
ParseErrorCode code;
|
||||
String context;
|
||||
|
||||
String Format() const
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case ParseErrorCode::UnknownOption:
|
||||
return String(std::format("Unknown option: {}", context.toStdString()));
|
||||
case ParseErrorCode::MissingValue:
|
||||
return String(
|
||||
std::format("Missing value for option: {}", context.toStdString()));
|
||||
case ParseErrorCode::MissingRequired:
|
||||
return String(
|
||||
std::format("Missing required option: {}", context.toStdString()));
|
||||
case ParseErrorCode::InvalidFormat:
|
||||
return String(
|
||||
std::format("Invalid argument format: {}", context.toStdString()));
|
||||
default: return String("Unknown parse error");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class OptionDef
|
||||
{
|
||||
public:
|
||||
OptionDef(char short_name, String long_name) :
|
||||
short_name_(short_name), long_name_(std::move(long_name))
|
||||
{
|
||||
}
|
||||
|
||||
OptionDef &Help(String help_text)
|
||||
{
|
||||
help_ = std::move(help_text);
|
||||
return *this;
|
||||
}
|
||||
|
||||
OptionDef &DefaultValue(String value)
|
||||
{
|
||||
default_value_ = std::move(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
OptionDef &Required(bool required = true)
|
||||
{
|
||||
required_ = required;
|
||||
return *this;
|
||||
}
|
||||
|
||||
OptionDef &TakesValue(bool takes_value = true)
|
||||
{
|
||||
takes_value_ = takes_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
char short_name_;
|
||||
String long_name_;
|
||||
String help_;
|
||||
std::optional<String> default_value_;
|
||||
bool required_ = false;
|
||||
bool takes_value_ = false;
|
||||
};
|
||||
|
||||
class ParseResult
|
||||
{
|
||||
public:
|
||||
bool HasFlag(const String &long_name) const
|
||||
{
|
||||
auto it = options_.find(long_name);
|
||||
return it != options_.end() && it->second == String("true");
|
||||
}
|
||||
|
||||
std::optional<String> GetOption(const String &long_name) const
|
||||
{
|
||||
if (auto it = options_.find(long_name); it != options_.end())
|
||||
return it->second;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const DynArray<String> &GetPositionals() const
|
||||
{
|
||||
return positionals_;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class ArgumentParser;
|
||||
HashMap<String, String> options_;
|
||||
DynArray<String> positionals_;
|
||||
};
|
||||
|
||||
class ArgumentParser
|
||||
{
|
||||
public:
|
||||
explicit ArgumentParser(String prog_name, String description = String("")) :
|
||||
prog_name_(std::move(prog_name)), description_(std::move(description))
|
||||
{
|
||||
}
|
||||
|
||||
OptionDef &AddFlag(char short_name, const String &long_name)
|
||||
{
|
||||
return registerOption(short_name, long_name).TakesValue(false);
|
||||
}
|
||||
|
||||
OptionDef &AddFlag(const String &long_name)
|
||||
{
|
||||
return registerOption('\0', long_name).TakesValue(false);
|
||||
}
|
||||
|
||||
OptionDef &AddOption(char short_name, const String &long_name)
|
||||
{
|
||||
return registerOption(short_name, long_name).TakesValue(true);
|
||||
}
|
||||
|
||||
OptionDef &AddOption(const String &long_name)
|
||||
{
|
||||
return registerOption('\0', long_name).TakesValue(true);
|
||||
}
|
||||
|
||||
Result<ParseResult, ParseError> Parse(int argc, const char *const *argv) const
|
||||
{
|
||||
if (argc <= 0)
|
||||
return ParseResult{};
|
||||
|
||||
return parseInternal(
|
||||
std::span<const char *const>{argv + 1, static_cast<size_t>(argc - 1)})
|
||||
.and_then([this](ParseResult res) { return validateRequired(std::move(res)); })
|
||||
.and_then([this](ParseResult res) { return applyDefaults(std::move(res)); });
|
||||
}
|
||||
|
||||
String FormatHelp() const
|
||||
{
|
||||
std::string help =
|
||||
std::format("Usage: {} [OPTIONS] [ARGS...]\n\n", prog_name_.toStdString());
|
||||
|
||||
if (!description_.empty())
|
||||
help += std::format("{}\n\n", description_.toStdString());
|
||||
|
||||
help += "Options:\n";
|
||||
for (const auto &opt : options_)
|
||||
{
|
||||
std::string flags;
|
||||
if (opt.short_name_ != '\0')
|
||||
flags = std::format("-{}, --{}", opt.short_name_, opt.long_name_.toStdString());
|
||||
else
|
||||
flags = std::format(" --{}", opt.long_name_.toStdString());
|
||||
|
||||
if (opt.takes_value_)
|
||||
flags += " <val>";
|
||||
|
||||
std::string desc = opt.help_.toStdString();
|
||||
if (opt.default_value_)
|
||||
desc += std::format(" (default: {})", opt.default_value_->toStdString());
|
||||
if (opt.required_)
|
||||
desc += " [required]";
|
||||
|
||||
help += std::format(" {:<25} {}\n", flags, desc);
|
||||
}
|
||||
|
||||
return String(help);
|
||||
}
|
||||
|
||||
private:
|
||||
OptionDef ®isterOption(char short_name, const String &long_name)
|
||||
{
|
||||
size_t idx = options_.size();
|
||||
options_.emplace_back(short_name, long_name);
|
||||
long_map_[long_name] = idx;
|
||||
if (short_name != '\0')
|
||||
short_map_[short_name] = idx;
|
||||
return options_.back();
|
||||
}
|
||||
|
||||
Result<ParseResult, ParseError> parseInternal(std::span<const char *const> args) const
|
||||
{
|
||||
ParseResult result;
|
||||
bool only_positionals = false;
|
||||
|
||||
for (size_t i = 0; i < args.size(); ++i)
|
||||
{
|
||||
std::string_view arg{args[i]};
|
||||
|
||||
if (only_positionals)
|
||||
{
|
||||
result.positionals_.emplace_back(String(std::string(arg)));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg == "--")
|
||||
{
|
||||
only_positionals = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg.starts_with("--"))
|
||||
{
|
||||
auto kv = arg.substr(2);
|
||||
if (kv.empty())
|
||||
return std::unexpected(
|
||||
ParseError{ParseErrorCode::InvalidFormat, String("--")});
|
||||
|
||||
auto eq_pos = kv.find('=');
|
||||
auto key = kv.substr(0, eq_pos);
|
||||
auto key_s = String(std::string(key));
|
||||
|
||||
auto it = long_map_.find(key_s);
|
||||
if (it == long_map_.end())
|
||||
return std::unexpected(
|
||||
ParseError{ParseErrorCode::UnknownOption, String(std::string(arg))});
|
||||
|
||||
const auto &def = options_[it->second];
|
||||
|
||||
if (def.takes_value_)
|
||||
{
|
||||
if (eq_pos != std::string_view::npos)
|
||||
{
|
||||
result.options_[def.long_name_] =
|
||||
String(std::string(kv.substr(eq_pos + 1)));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i + 1 >= args.size())
|
||||
return std::unexpected(ParseError{
|
||||
ParseErrorCode::MissingValue, String(std::string(arg))});
|
||||
result.options_[def.long_name_] = String(std::string(args[++i]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (eq_pos != std::string_view::npos)
|
||||
return std::unexpected(ParseError{
|
||||
ParseErrorCode::InvalidFormat, String(std::string(arg))});
|
||||
result.options_[def.long_name_] = String("true");
|
||||
}
|
||||
}
|
||||
else if (arg.starts_with('-') && arg.size() > 1)
|
||||
{
|
||||
auto group = arg.substr(1);
|
||||
for (size_t j = 0; j < group.size(); ++j)
|
||||
{
|
||||
char c = group[j];
|
||||
auto it = short_map_.find(c);
|
||||
if (it == short_map_.end())
|
||||
return std::unexpected(ParseError{
|
||||
ParseErrorCode::UnknownOption, String(std::string(1, c))});
|
||||
|
||||
const auto &def = options_[it->second];
|
||||
|
||||
if (def.takes_value_)
|
||||
{
|
||||
if (j + 1 < group.size())
|
||||
{
|
||||
result.options_[def.long_name_] =
|
||||
String(std::string(group.substr(j + 1)));
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i + 1 >= args.size())
|
||||
return std::unexpected(ParseError{ParseErrorCode::MissingValue,
|
||||
String(std::format("-{}", c))});
|
||||
result.options_[def.long_name_] = String(std::string(args[++i]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.options_[def.long_name_] = String("true");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.positionals_.emplace_back(String(std::string(arg)));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Result<ParseResult, ParseError> validateRequired(ParseResult res) const
|
||||
{
|
||||
for (const auto &opt : options_)
|
||||
{
|
||||
if (opt.required_ && res.options_.find(opt.long_name_) == res.options_.end())
|
||||
{
|
||||
std::string flag =
|
||||
opt.short_name_ != '\0' ?
|
||||
std::format("-{}/--{}", opt.short_name_, opt.long_name_.toStdString()) :
|
||||
std::format("--{}", opt.long_name_.toStdString());
|
||||
return std::unexpected(
|
||||
ParseError{ParseErrorCode::MissingRequired, String(flag)});
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
Result<ParseResult, ParseError> applyDefaults(ParseResult res) const
|
||||
{
|
||||
for (const auto &opt : options_)
|
||||
{
|
||||
if (opt.default_value_ && res.options_.find(opt.long_name_) == res.options_.end())
|
||||
{
|
||||
res.options_[opt.long_name_] = *opt.default_value_;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
String prog_name_;
|
||||
String description_;
|
||||
DynArray<OptionDef> options_;
|
||||
HashMap<String, size_t> long_map_;
|
||||
HashMap<char, size_t> short_map_;
|
||||
};
|
||||
|
||||
} // namespace Fig::ArgParser
|
||||
File diff suppressed because it is too large
Load Diff
100
src/VM/Entry.cpp
Normal file
100
src/VM/Entry.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
/*!
|
||||
@file src/VM/Entry.hpp
|
||||
@brief vm入口实现
|
||||
@author PuqiAR (im@puqiar.top)
|
||||
@date 2026-03-13
|
||||
*/
|
||||
|
||||
|
||||
#include <VM/Entry.hpp>
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
#include <Core/Core.hpp>
|
||||
#include <SourceManager/SourceManager.hpp>
|
||||
|
||||
#include <Lexer/Lexer.hpp>
|
||||
#include <Parser/Parser.hpp>
|
||||
#include <Sema/Analyzer.hpp>
|
||||
#include <Compiler/Compiler.hpp>
|
||||
#include <VM/VM.hpp>
|
||||
|
||||
namespace Fig::Entry
|
||||
{
|
||||
void RunFromPath(const String &path)
|
||||
{
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
fs::path _fspath(path.toStdString());
|
||||
|
||||
if (!fs::exists(_fspath))
|
||||
{
|
||||
CoreIO::GetStdErr() << "File not found: " << path << '\n';
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
if (!_fspath.has_extension() || _fspath.extension() != ".fig")
|
||||
{
|
||||
CoreIO::GetStdErr() << "Not a valid Fig-lang source code\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
String fileName(_fspath.filename().string());
|
||||
|
||||
SourceManager manager(path);
|
||||
manager.Read();
|
||||
|
||||
if (!manager.read)
|
||||
{
|
||||
CoreIO::GetStdErr() << "Could not read file: " << path << '\n';
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
const String &source = manager.GetSource();
|
||||
|
||||
Lexer lexer(source, fileName);
|
||||
Parser parser(lexer, manager, fileName);
|
||||
|
||||
auto parse_result = parser.Parse();
|
||||
if (!parse_result)
|
||||
{
|
||||
ReportError(parse_result.error(), manager);
|
||||
std::exit(1);
|
||||
}
|
||||
Program *program = *parse_result;
|
||||
|
||||
Analyzer analyer(manager);
|
||||
auto analyze_result = analyer.Analyze(program);
|
||||
|
||||
if (!analyze_result)
|
||||
{
|
||||
ReportError(analyze_result.error(), manager);
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
Diagnostics diagnostics;
|
||||
Compiler compiler(manager, diagnostics);
|
||||
|
||||
auto compile_result = compiler.Compile(program);
|
||||
diagnostics.EmitAll(manager);
|
||||
|
||||
if (!compile_result)
|
||||
{
|
||||
ReportError(compile_result.error(), manager);
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
CompiledModule *compiledModule = *compile_result;
|
||||
|
||||
VM vm;
|
||||
|
||||
auto execute_result = vm.Execute(compiledModule);
|
||||
if (!execute_result)
|
||||
{
|
||||
ReportError(execute_result.error(), manager);
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
delete compiledModule;
|
||||
}
|
||||
}; // namespace Fig::Entry
|
||||
13
src/VM/Entry.hpp
Normal file
13
src/VM/Entry.hpp
Normal file
@@ -0,0 +1,13 @@
|
||||
/*!
|
||||
@file src/VM/Entry.hpp
|
||||
@brief vm入口定义
|
||||
@author PuqiAR (im@puqiar.top)
|
||||
@date 2026-03-13
|
||||
*/
|
||||
|
||||
#include <Deps/Deps.hpp>
|
||||
|
||||
namespace Fig::Entry
|
||||
{
|
||||
void RunFromPath(const String &);
|
||||
};
|
||||
127
src/main.cpp
127
src/main.cpp
@@ -1,87 +1,84 @@
|
||||
#include <Bytecode/Disassembler.hpp>
|
||||
#include <Compiler/Compiler.hpp>
|
||||
/*
|
||||
The Fig Programming Language
|
||||
Copyright © 2025-2026 PuqiAR (im@puqiar.top). All rights reserved.
|
||||
|
||||
Under MIT License, see /LICENSE for more
|
||||
*/
|
||||
|
||||
#include <Core/Core.hpp>
|
||||
#include <Deps/Deps.hpp>
|
||||
#include <Lexer/Lexer.hpp>
|
||||
#include <Parser/Parser.hpp>
|
||||
#include <Sema/Analyzer.hpp>
|
||||
#include <SourceManager/SourceManager.hpp>
|
||||
#include <VM/VM.hpp>
|
||||
#include <VM/Entry.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <print>
|
||||
#include <Utils/ArgParser/ArgParser.hpp>
|
||||
|
||||
int main()
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
using namespace Fig;
|
||||
|
||||
String fileName = "test.fig";
|
||||
String filePath = "T:/Files/Maker/Code/MyCodingLanguage/The Fig Project/Fig/test.fig";
|
||||
std::ostream &err = CoreIO::GetStdErr();
|
||||
std::ostream &out = CoreIO::GetStdOut();
|
||||
|
||||
SourceManager manager(filePath);
|
||||
manager.Read();
|
||||
ArgParser::ArgumentParser argparser("Fig", "Fig Toolchain");
|
||||
|
||||
if (!manager.read)
|
||||
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");
|
||||
|
||||
auto res = argparser.Parse(argc, argv);
|
||||
if (!res)
|
||||
{
|
||||
std::cerr << "CRITICAL: Could not read source file: " << filePath << "\n";
|
||||
err << res.error().Format() << '\n';
|
||||
return 1;
|
||||
}
|
||||
|
||||
Lexer lexer(manager.GetSource(), fileName);
|
||||
Parser parser(lexer, manager, fileName);
|
||||
auto &args = *res;
|
||||
|
||||
auto pRes = parser.Parse();
|
||||
if (!pRes)
|
||||
bool showHelp = args.HasFlag("help");
|
||||
bool showVersion = args.HasFlag("version");
|
||||
bool showLicense = args.HasFlag("license");
|
||||
|
||||
if (showHelp)
|
||||
{
|
||||
ReportError(pRes.error(), manager);
|
||||
out << argparser.FormatHelp() << '\n';
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (showVersion)
|
||||
{
|
||||
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",
|
||||
Core::COMPILE_TIME,
|
||||
Core::COMPILER,
|
||||
Core::ARCH,
|
||||
Core::PLATFORM);
|
||||
}
|
||||
else if (showLicense)
|
||||
{
|
||||
out << Core::LICENSE_TEXT << '\n';
|
||||
}
|
||||
|
||||
auto &positionals = args.GetPositionals();
|
||||
const auto &posSize = positionals.size();
|
||||
|
||||
if (posSize != 1 && (showHelp || showVersion || showLicense))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (posSize > 1)
|
||||
{
|
||||
err << "Error: Too more positionals, expect 1. Use Fig [Fig source code file (.fig)]\n";
|
||||
return 1;
|
||||
}
|
||||
Program *program = *pRes;
|
||||
|
||||
Analyzer analyzer(manager);
|
||||
auto aRes = analyzer.Analyze(program);
|
||||
if (!aRes)
|
||||
else if (posSize == 0)
|
||||
{
|
||||
ReportError(aRes.error(), manager);
|
||||
return 1;
|
||||
}
|
||||
std::cout << "Analyzer: Program OK\n";
|
||||
|
||||
Diagnostics diag;
|
||||
Compiler compiler(manager, diag);
|
||||
auto cRes = compiler.Compile(program);
|
||||
if (!cRes)
|
||||
{
|
||||
ReportError(cRes.error(), manager);
|
||||
err << "Error: No input source file\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
CompiledModule *compiledModule = *cRes;
|
||||
const String &path = positionals.front();
|
||||
Entry::RunFromPath(path);
|
||||
|
||||
Disassembler::DisassembleModule(compiledModule);
|
||||
|
||||
VM vm;
|
||||
using Clock = std::chrono::high_resolution_clock;
|
||||
Clock clock;
|
||||
|
||||
std::cout << "\n--- VM Execution Start ---\n";
|
||||
auto start = clock.now();
|
||||
auto result_ = vm.Execute(compiledModule);
|
||||
auto end = clock.now();
|
||||
|
||||
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
|
||||
|
||||
if (!result_)
|
||||
{
|
||||
ReportError(result_.error(), manager);
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::cout << "Result: " << (*result_).ToString() << "\n";
|
||||
std::cout << "Execution Cost: " << duration.count() << "ms\n";
|
||||
|
||||
vm.PrintRegisters();
|
||||
vm.PrintGlobals();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
12
xmake.lua
12
xmake.lua
@@ -116,20 +116,26 @@ target("ReplTest")
|
||||
|
||||
target("Fig")
|
||||
add_files("src/Core/*.cpp")
|
||||
add_files("src/Token/Token.cpp")
|
||||
add_files("src/Error/Error.cpp")
|
||||
|
||||
add_files("src/Token/Token.cpp")
|
||||
add_files("src/Lexer/Lexer.cpp")
|
||||
|
||||
add_files("src/Ast/Operator.cpp")
|
||||
add_files("src/Bytecode/Disassembler.cpp")
|
||||
add_files("src/Parser/ExprParser.cpp")
|
||||
add_files("src/Parser/StmtParser.cpp")
|
||||
add_files("src/Parser/TypeExprParser.cpp")
|
||||
add_files("src/Parser/Parser.cpp")
|
||||
add_files("src/Object/Object.cpp")
|
||||
|
||||
add_files("src/Sema/Type.cpp")
|
||||
add_files("src/Sema/Analyzer.cpp")
|
||||
|
||||
add_files("src/Compiler/ExprCompiler.cpp")
|
||||
add_files("src/Compiler/StmtCompiler.cpp")
|
||||
add_files("src/Compiler/Compiler.cpp")
|
||||
add_files("src/Bytecode/Disassembler.cpp")
|
||||
|
||||
add_files("src/Object/Object.cpp")
|
||||
add_files("src/VM/VM.cpp")
|
||||
add_files("src/VM/Entry.cpp")
|
||||
add_files("src/main.cpp")
|
||||
|
||||
Reference in New Issue
Block a user