Skip to content

Commit 8c3085a

Browse files
committed
wip
1 parent b55c276 commit 8c3085a

File tree

6 files changed

+150
-52
lines changed

6 files changed

+150
-52
lines changed

CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
cmake_minimum_required(VERSION 3.16) # 3.16+ because of target_precompiled_header
1717
project(aaltitoad VERSION 1.3.0)
1818
set(THREADS_PREFER_PTHREAD_FLAG ON)
19-
set(CMAKE_CXX_STANDARD 20)
19+
set(CMAKE_CXX_STANDARD 23)
2020
set(CXX_STANDARD_REQUIRED ON)
2121
set(SPDLOG_BUILD_SHARED)
2222
set(CONFIG_IN_FILE src/config.h.in)
@@ -123,6 +123,7 @@ add_library(huppaal_parser SHARED
123123
src/parser/hawk/scoped_template_builder/scoped_template_builder.cpp
124124
src/parser/hawk/scoped_template_builder/scoped_interpreter.cpp
125125
src/parser/hawk/diagnostics.cpp
126+
src/parser/hawk/compiler.cpp
126127
src/parser/hawk/huppaal/parser.cpp)
127128
target_link_libraries(huppaal_parser PUBLIC aaltitoad expr nlohmann_json::nlohmann_json)
128129

@@ -131,6 +132,7 @@ add_library(graphedit_parser SHARED
131132
src/parser/hawk/scoped_template_builder/scoped_template_builder.cpp
132133
src/parser/hawk/scoped_template_builder/scoped_interpreter.cpp
133134
src/parser/hawk/diagnostics.cpp
135+
src/parser/hawk/compiler.cpp
134136
src/parser/hawk/graphedit/parser.cpp
135137
src/parser/hawk/graphedit/model.cpp)
136138
target_link_libraries(graphedit_parser PUBLIC aaltitoad expr nlohmann_json::nlohmann_json)

src/parser/hawk/compiler.cpp

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
11
#include "compiler.h"
22
#include <overload>
3-
#include <variant>
43

54
namespace aaltitoad::hawk {
6-
compiler::compiler(const frontend::scanner& scanner, const frontend::parser& parser, const middleend::semantic_analyzer& analyzer, const middleend::optimizer& optimizer, const backend::generator& generator)
7-
: scanner{scanner}, parser{parser}, analyzer{analyzer}, optimizer{optimizer}, generator{generator}, symbols{}, diagnostic_factory{}
8-
{
9-
5+
compiler::compiler(
6+
std::unique_ptr<scanner_t>&& scanner,
7+
std::unique_ptr<parser_t>&& parser,
8+
std::unique_ptr<semantic_analyzer_t>&& analyzer,
9+
std::unique_ptr<optimizer_t>&& optimizer,
10+
std::unique_ptr<generator_t>&& generator)
11+
:
12+
scanner{std::move(scanner)},
13+
parser{std::move(parser)},
14+
analyzer{std::move(analyzer)},
15+
optimizer{std::move(optimizer)},
16+
generator{std::move(generator)},
17+
symbols{},
18+
diagnostic_factory{} {
1019
}
1120

1221
void compiler::add_symbols(const expr::symbol_table_t& symbols) {
@@ -17,15 +26,18 @@ namespace aaltitoad::hawk {
1726
symbols.clear();
1827
}
1928

20-
auto compiler::compile(const std::string& path) -> result<ntta_t> {
21-
auto stream = scanner.scan(*this, path);
22-
std::visit(ya::overload(
23-
[](const std::string& stream){},
24-
[](const error& err){}
25-
), stream);
26-
auto ast = parser.parse(*this, stream);
27-
auto dast = analyzer.analyze(*this, ast);
28-
optimizer.optimize(*this, dast);
29-
return generator.generate(*this, dast);
29+
auto compiler::compile(const std::vector<std::string>& paths, const std::vector<std::string>& ignore_list) -> std::expected<ntta_t, error> {
30+
auto stream = scanner->scan(*this, paths, ignore_list);
31+
if(!stream)
32+
return std::unexpected{stream.error()};
33+
auto ast = parser->parse(*this, stream.value());
34+
if(!ast)
35+
return std::unexpected{ast.error()};
36+
auto dast_r = analyzer->analyze(*this, ast.value());
37+
if(!dast_r)
38+
return std::unexpected{dast_r.error()};
39+
auto dast = dast_r.value();
40+
optimizer->optimize(*this, dast);
41+
return generator->generate(*this, dast);
3042
}
3143
}

src/parser/hawk/compiler.h

Lines changed: 41 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3,62 +3,68 @@
33
#include "ntta/tta.h"
44
#include "parser/hawk/diagnostics.h"
55
#include "symbol_table.h"
6+
#include <expected>
67
#include <string>
8+
#include <vector>
79

810
namespace aaltitoad::hawk {
911
class compiler;
1012

1113
struct error {
1214
diagnostic diagnostic;
1315
};
14-
template<typename ok>
15-
using result = std::variant<error, ok>; // TODO: Consider making this a simple yalibs thing
1616

17-
namespace frontend {
18-
struct scanner {
19-
virtual auto scan(compiler& ctx, const std::string& path) const noexcept -> result<std::string> = 0; // TODO: probably shouldnt be a string output...
20-
};
17+
struct scanner_t {
18+
scanner_t() = default;
19+
virtual ~scanner_t() = default;
20+
virtual auto scan(compiler& ctx,
21+
const std::vector<std::string>& filepaths,
22+
const std::vector<std::string>& ignore_list) const noexcept -> std::expected<std::string, error> = 0;
23+
};
2124

22-
struct parser {
23-
virtual auto parse(compiler& ctx, const std::string& stream) const noexcept -> result<int> = 0; // TODO: Should be an AST output
24-
};
25-
}
25+
struct parser_t {
26+
parser_t() = default;
27+
virtual ~parser_t() = default;
28+
virtual auto parse(compiler& ctx, const std::string& stream) const noexcept -> std::expected<int, error> = 0; // TODO: Should be an AST output
29+
};
2630

27-
namespace middleend {
28-
struct semantic_analyzer {
29-
virtual auto analyze(compiler& ctx, const int& ast) const noexcept -> result<int> = 0; // TODO: Should be an ast output
30-
};
31+
struct semantic_analyzer_t {
32+
semantic_analyzer_t() = default;
33+
virtual ~semantic_analyzer_t() = default;
34+
virtual auto analyze(compiler& ctx, const int& ast) const noexcept -> std::expected<int, error> = 0; // TODO: Should be an ast output
35+
};
3136

32-
struct optimizer {
33-
// Note that optimizers are not allowed to return errors, but can throw exceptions.
34-
virtual void optimize(compiler& ctx, int& ast) const = 0;
35-
};
36-
}
37+
struct optimizer_t {
38+
optimizer_t() = default;
39+
virtual ~optimizer_t() = default;
40+
virtual void optimize(compiler& ctx, int& ast) const = 0;
41+
};
3742

38-
namespace backend {
39-
struct generator {
40-
virtual auto generate(compiler& ctx, const int& ast) const noexcept -> result<ntta_t> = 0;
41-
};
42-
}
43+
struct generator_t {
44+
generator_t() = default;
45+
virtual ~generator_t() = default;
46+
virtual auto generate(compiler& ctx, const int& ast) const noexcept -> std::expected<ntta_t, error> = 0;
47+
};
4348

4449
class compiler {
4550
public:
46-
compiler(const frontend::scanner& scanner,
47-
const frontend::parser& parser,
48-
const middleend::semantic_analyzer& analyzer,
49-
const middleend::optimizer& optimizer,
50-
const backend::generator& generator);
51+
compiler(
52+
std::unique_ptr<scanner_t>&& scanner,
53+
std::unique_ptr<parser_t>&& parser,
54+
std::unique_ptr<semantic_analyzer_t>&& analyzer,
55+
std::unique_ptr<optimizer_t>&& optimizer,
56+
std::unique_ptr<generator_t>&& generator);
5157
void add_symbols(const expr::symbol_table_t& symbols);
5258
void clear_symbols();
5359
auto get_diagnostic_factory() -> diagnostic_factory&;
54-
auto compile(const std::string& path) -> result<ntta_t>;
60+
auto compile(const std::vector<std::string>& paths, const std::vector<std::string>& ignore_list) -> std::expected<ntta_t, error>;
5561

5662
private:
57-
const frontend::scanner& scanner;
58-
const frontend::parser& parser;
59-
const middleend::semantic_analyzer& analyzer;
60-
const middleend::optimizer& optimizer;
61-
const backend::generator& generator;
63+
std::unique_ptr<scanner_t> scanner;
64+
std::unique_ptr<parser_t> parser;
65+
std::unique_ptr<semantic_analyzer_t> analyzer;
66+
std::unique_ptr<optimizer_t> optimizer;
67+
std::unique_ptr<generator_t> generator;
6268
expr::symbol_table_t symbols;
6369
diagnostic_factory diagnostic_factory;
6470
};

src/parser/hawk/diagnostics.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace aaltitoad::hawk {
1717
// TODO: suggestion generator
1818
public:
1919
diagnostic_factory() = default;
20-
auto without_context() const -> diagnostic_factory&;
20+
auto without_context() -> diagnostic_factory&;
2121
auto with_model_key(const std::string& key) -> diagnostic_factory&;
2222
auto with_context(const std::string& element) -> diagnostic_factory&;
2323
auto with_context(const std::initializer_list<std::string>& elements) -> diagnostic_factory&;

src/parser/hawk/huppaal/parser.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,71 @@ namespace aaltitoad::hawk::huppaal {
7474
auto parser::should_ignore(const std::filesystem::directory_entry& entry, const std::string& ignore_regex) -> bool {
7575
return std::regex_match(entry.path().c_str(), std::regex{ignore_regex});
7676
}
77+
78+
auto json_parser_t::scan(compiler& ctx, const std::vector<std::string>& filepaths, const std::vector<std::string>& ignore_list) const noexcept -> std::expected<std::string, error> {
79+
// BOOKMARK: What should the scanner actually return?
80+
// Traditionally, a scanner would give a linear token stream. If we were to take the metaphor directly, we would
81+
// return something like a list of "tokens" i.e. different kindas of nodes and edges, i.e. an adjacency list.
82+
// But isn't that just excactly what the AST would be equivalent to (the parser's output)?
83+
// Say that we do that. The scanner outputs a list of unchecked tokens and reports errors if there are
84+
// unrecognized vertex types, missing keys, etc.
85+
// Then what would the parser do? - Checking graph consistency and semantics is the job of the semantic analyzer
86+
// not the parser, so we can't do that...
87+
// Traditionally, the parser would take the token stream and do LALR walking and generate an AST. But our AST
88+
// (no decorations) _is_ the adjacency list. - maybe the parser step should ensure compileability of the expr
89+
// strings? No. That would require a scoped parser, and that is a semantic analyzer thing.
90+
// WHAT DOES THE PARSER DO?
91+
//
92+
// Okay... Maybe the scanner doesnt output the adjacency list then. The question is then: What thing do we need
93+
// to generate an adjacency list? Just a json structure? I mean... The only thing that seems icky about that is
94+
// that we would make the compiler dependent on nlohmann, but is that a problem? It would ensure a valid json
95+
// syntax. Compared to a traditional scanner, would that fit?
96+
//
97+
// Let's see. A C scanner would gladly accept this nonsense: hello int "world" void = 2 = = ==
98+
// The C parser would say that the token stream is fucking stupid, but that's fine. It's valid scanner input.
99+
// Comparatively, if our scanner gets: `{ "hello": 321 }` - that would also be valid scanner input. Again, the
100+
// parser will flip it's shit, because that is clearly not a hawk graph.
101+
//
102+
// I think that is good. - also, welcome to my blog
103+
for(const auto& filepath : filepaths) {
104+
for(const auto& entry: std::filesystem::directory_iterator(filepath)) {
105+
try {
106+
if(should_ignore(entry, ignore_list)) {
107+
spdlog::trace("ignoring file {}", entry.path().c_str());
108+
continue;
109+
}
110+
111+
std::ifstream input_filestream(entry.path());
112+
auto json_file = nlohmann::json::parse(input_filestream,
113+
/* callback */ nullptr,
114+
/* allow exceptions */ true,
115+
/* ignore_comments */ true);
116+
if(json_file.contains("name")) {
117+
spdlog::trace("loading file {0}", entry.path().c_str());
118+
} else if(json_file.contains("parts")) {
119+
spdlog::trace("loading parts file {0}", entry.path().c_str());
120+
} else
121+
spdlog::trace("ignoring file {0} (not a valid model file)", entry.path().c_str());
122+
} catch (std::exception& e) {
123+
spdlog::error("unable to parse json file {0}: {1}", entry.path().c_str(), e.what());
124+
return std::unexpected(error()); // TODO: Create a real diagnostic
125+
}
126+
}
127+
}
128+
}
129+
130+
auto json_parser_t::parse(compiler& ctx, const std::string& stream) const noexcept -> std::expected<int, error> {
131+
132+
}
133+
134+
auto json_parser_t::should_ignore(const std::filesystem::directory_entry& entry, const std::vector<std::string>& ignore_list) const -> bool {
135+
return std::any_of(ignore_list.begin(), ignore_list.end(),
136+
[&entry, this](const std::string& ig){ return should_ignore(entry, ig); });
137+
}
138+
139+
auto json_parser_t::should_ignore(const std::filesystem::directory_entry& entry, const std::string& ignore_regex) const -> bool {
140+
return std::regex_match(entry.path().c_str(), std::regex{ignore_regex});
141+
}
77142
}
78143

79144
extern "C" {

src/parser/hawk/huppaal/parser.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#define AALTITOAD_HAWK_PARSER_H
2020
#include "lsp.pb.h"
2121
#include "plugin_system/parser.h"
22+
#include "parser/hawk/compiler.h"
2223
#include <nlohmann/json.hpp>
2324

2425
namespace aaltitoad::hawk::huppaal {
@@ -35,6 +36,18 @@ namespace aaltitoad::hawk::huppaal {
3536
auto should_ignore(const std::filesystem::directory_entry& entry, const std::string& ignore_regex) -> bool;
3637
auto load_part(const nlohmann::json& json_file) -> std::string;
3738
};
39+
40+
class json_parser_t : public scanner_t, aaltitoad::hawk::parser_t {
41+
public:
42+
~json_parser_t() override = default;
43+
auto scan(compiler& ctx,
44+
const std::vector<std::string>& filepaths,
45+
const std::vector<std::string>& ignore_list) const noexcept -> std::expected<std::string, error> override;
46+
auto parse(compiler& ctx, const std::string& stream) const noexcept -> std::expected<int, error> override;
47+
private:
48+
auto should_ignore(const std::filesystem::directory_entry& entry, const std::vector<std::string>& ignore_list) const -> bool;
49+
auto should_ignore(const std::filesystem::directory_entry& entry, const std::string& ignore_regex) const -> bool;
50+
};
3851
}
3952

4053
#endif //AALTITOAD_HAWK_PARSER_H

0 commit comments

Comments
 (0)