Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cli/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ set(PLCLI_SOURCES
source/subcommands/run.cpp
source/subcommands/docs.cpp
source/subcommands/info.cpp
source/subcommands/lint.cpp
)

if (LIBPL_BUILD_CLI_AS_EXECUTABLE)
Expand Down
4 changes: 3 additions & 1 deletion cli/source/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ namespace pl::cli {
void addRunSubcommand(CLI::App *app);
void addDocsSubcommand(CLI::App *app);
void addInfoSubcommand(CLI::App *app);
void addLintSubcommand(CLI::App *app);

}

Expand All @@ -30,6 +31,7 @@ namespace pl::cli {
sub::addRunSubcommand(&app);
sub::addDocsSubcommand(&app);
sub::addInfoSubcommand(&app);
sub::addLintSubcommand(&app);

// Print help message if not enough arguments were provided
if (args.size() == 0) {
Expand Down Expand Up @@ -76,4 +78,4 @@ namespace pl::cli {

return pl::cli::executeCommandLineInterface(args);
}
#endif
#endif
79 changes: 79 additions & 0 deletions cli/source/subcommands/lint.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#include <pl/pattern_language.hpp>
#include <pl/formatters.hpp>
#include <wolv/io/file.hpp>

#include <pl/cli/helpers/utils.hpp>

#include <CLI/CLI.hpp>
#include <CLI/App.hpp>
#include <fmt/format.h>

#include <nlohmann/json.hpp>

namespace pl::cli::sub {

void addLintSubcommand(CLI::App *app) {
static std::fs::path patternFilePath;
static std::vector<std::fs::path> includePaths;
static std::vector<std::string> defines;

static bool outputJson = false;

auto subcommand = app->add_subcommand("lint", "Compiles the given pattern");

// Add command line arguments
subcommand->add_option("-p,--pattern,PATTERN_FILE", patternFilePath, "Pattern file")->required()->check(CLI::ExistingFile);
subcommand->add_option("-I,--includes", includePaths, "Include file paths")->take_all()->check(CLI::ExistingDirectory);
subcommand->add_option("-D,--define", defines, "Define a preprocessor macro")->take_all();
subcommand->add_flag("-j,--json", outputJson, "Output JSON instead of text")->default_val(false);

subcommand->callback([] {
// Open pattern file
wolv::io::File patternFile(patternFilePath, wolv::io::File::Mode::Read);
if (!patternFile.isValid()) {
::fmt::print("Failed to open file '{}'\n", patternFilePath.string());
std::exit(EXIT_FAILURE);
}

// Create and configure Pattern Language runtime
pl::PatternLanguage runtime;

runtime.setIncludePaths(includePaths);

for (const auto &define : defines)
runtime.addDefine(define);

const auto code = patternFile.readString();
const auto source = wolv::util::toUTF8String(patternFile.getPath());
auto _ = runtime.parseString(code, source);

auto compileErrors = runtime.getCompileErrors();
::nlohmann::json errors = ::nlohmann::json::array();
if (compileErrors.size() > 0) {
for (const auto &error : compileErrors) {
if (outputJson) {
::nlohmann::json obj;
obj["message"] = error.getMessage();
obj["description"] = error.getDescription();

::nlohmann::json loc;
const auto &location = error.getLocation();
loc["line"] = location.line;
loc["column"] = location.column;
loc["source"] = location.source->source;
obj["location"] = loc;

errors.emplace_back(obj);
} else {
::fmt::print("{}\n", error.format());
}
}
}

if(outputJson) {
::fmt::print("{}\n", errors.dump());
}
});
}

}