Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
sillydan1 committed Jul 25, 2024
1 parent ea25860 commit 8f11c35
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 135 deletions.
32 changes: 16 additions & 16 deletions src/parser/hawk/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@

namespace aaltitoad::hawk {
compiler::compiler(
std::unique_ptr<scanner_t>&& scanner,
std::unique_ptr<parser_t>&& parser,
std::unique_ptr<semantic_analyzer_t>&& analyzer,
std::unique_ptr<optimizer_t>&& optimizer,
std::unique_ptr<generator_t>&& generator)
std::unique_ptr<scanner>&& _scanner,
std::unique_ptr<parser>&& _parser,
std::unique_ptr<semantic_analyzer>&& _analyzer,
std::unique_ptr<optimizer>&& _optimizer,
std::unique_ptr<generator>&& _generator)
:
scanner{std::move(scanner)},
parser{std::move(parser)},
analyzer{std::move(analyzer)},
optimizer{std::move(optimizer)},
generator{std::move(generator)},
_scanner{std::move(_scanner)},
_parser{std::move(_parser)},
_analyzer{std::move(_analyzer)},
_optimizer{std::move(_optimizer)},
_generator{std::move(_generator)},
symbols{},
diagnostic_factory{} {
_diagnostic_factory{} {
}

void compiler::add_symbols(const expr::symbol_table_t& symbols) {
Expand All @@ -27,17 +27,17 @@ namespace aaltitoad::hawk {
}

auto compiler::compile(const std::vector<std::string>& paths, const std::vector<std::string>& ignore_list) -> std::expected<ntta_t, error> {
auto stream = scanner->scan(*this, paths, ignore_list);
auto stream = _scanner->scan(*this, paths, ignore_list);
if(!stream)
return std::unexpected{stream.error()};
auto ast = parser->parse(*this, stream.value());
auto ast = _parser->parse(*this, stream.value());
if(!ast)
return std::unexpected{ast.error()};
auto dast_r = analyzer->analyze(*this, ast.value());
auto dast_r = _analyzer->analyze(*this, ast.value());
if(!dast_r)
return std::unexpected{dast_r.error()};
auto dast = dast_r.value();
optimizer->optimize(*this, dast);
return generator->generate(*this, dast);
_optimizer->optimize(*this, dast);
return _generator->generate(*this, dast);
}
}
70 changes: 37 additions & 33 deletions src/parser/hawk/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,71 +9,75 @@
#include <vector>

namespace aaltitoad::hawk {
// TODO: How to handle warnings?
class compiler;

struct error {
std::vector<diagnostic> diagnostics;
};

struct scanner_t {
struct result_t {
struct scanner {
struct result {
std::vector<scanning::template_t> templates;
std::vector<diagnostic> diagnostics;
};

scanner_t() = default;
virtual ~scanner_t() = default;
scanner() = default;
virtual ~scanner() = default;
virtual auto scan(compiler& ctx,
const std::vector<std::string>& filepaths,
const std::vector<std::string>& ignore_list) const noexcept -> std::expected<result_t, error> = 0;
const std::vector<std::string>& ignore_list) const noexcept -> std::expected<result, error> = 0;
};

struct parser_t {
parser_t() = default;
virtual ~parser_t() = default;
virtual auto parse(compiler& ctx, const scanner_t::result_t& scanner_result) const noexcept -> std::expected<int, error> = 0; // TODO: Should be an AST output
struct parser {
struct result {
std::vector<parsing::template_t> templates;
std::vector<diagnostic> diagnostics;
};

parser() = default;
virtual ~parser() = default;
virtual auto parse(compiler& ctx, const scanner::result& scanner_result) const noexcept -> std::expected<result, error> = 0;
};

struct semantic_analyzer_t {
semantic_analyzer_t() = default;
virtual ~semantic_analyzer_t() = default;
virtual auto analyze(compiler& ctx, const int& ast) const noexcept -> std::expected<int, error> = 0; // TODO: Should be an ast output
struct semantic_analyzer {
semantic_analyzer() = default;
virtual ~semantic_analyzer() = default;
virtual auto analyze(compiler& ctx, const parser::result& ast) const noexcept -> std::expected<parser::result, error> = 0;
};

struct optimizer_t {
optimizer_t() = default;
virtual ~optimizer_t() = default;
virtual void optimize(compiler& ctx, int& ast) const = 0;
struct optimizer {
optimizer() = default;
virtual ~optimizer() = default;
virtual void optimize(compiler& ctx, parser::result& ast) const = 0;
};

struct generator_t {
generator_t() = default;
virtual ~generator_t() = default;
virtual auto generate(compiler& ctx, const int& ast) const noexcept -> std::expected<ntta_t, error> = 0;
struct generator {
generator() = default;
virtual ~generator() = default;
virtual auto generate(compiler& ctx, const parser::result& ast) const noexcept -> std::expected<ntta_t, error> = 0;
};

class compiler {
public:
compiler(
std::unique_ptr<scanner_t>&& scanner,
std::unique_ptr<parser_t>&& parser,
std::unique_ptr<semantic_analyzer_t>&& analyzer,
std::unique_ptr<optimizer_t>&& optimizer,
std::unique_ptr<generator_t>&& generator);
std::unique_ptr<scanner>&& scanner,
std::unique_ptr<parser>&& parser,
std::unique_ptr<semantic_analyzer>&& analyzer,
std::unique_ptr<optimizer>&& optimizer,
std::unique_ptr<generator>&& generator);
void add_symbols(const expr::symbol_table_t& symbols);
void clear_symbols();
auto get_diagnostic_factory() -> diagnostic_factory&;
auto compile(const std::vector<std::string>& paths, const std::vector<std::string>& ignore_list) -> std::expected<ntta_t, error>;

private:
std::unique_ptr<scanner_t> scanner;
std::unique_ptr<parser_t> parser;
std::unique_ptr<semantic_analyzer_t> analyzer;
std::unique_ptr<optimizer_t> optimizer;
std::unique_ptr<generator_t> generator;
std::unique_ptr<scanner> _scanner;
std::unique_ptr<parser> _parser;
std::unique_ptr<semantic_analyzer> _analyzer;
std::unique_ptr<optimizer> _optimizer;
std::unique_ptr<generator> _generator;
expr::symbol_table_t symbols;
diagnostic_factory diagnostic_factory;
diagnostic_factory _diagnostic_factory;
};
}

Expand Down
75 changes: 0 additions & 75 deletions src/parser/hawk/huppaal/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,81 +76,6 @@ namespace aaltitoad::hawk::huppaal {
}

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> {
// BOOKMARK: What should the scanner actually return?
// Traditionally, a scanner would give a linear token stream. If we were to take the metaphor directly, we would
// return something like a list of "tokens" i.e. different kindas of nodes and edges, i.e. an adjacency list.
// But isn't that just excactly what the AST would be equivalent to (the parser's output)?
// Say that we do that. The scanner outputs a list of unchecked tokens and reports errors if there are
// unrecognized vertex types, missing keys, etc.
// Then what would the parser do? - Checking graph consistency and semantics is the job of the semantic analyzer
// not the parser, so we can't do that...
// Traditionally, the parser would take the token stream and do LALR walking and generate an AST. But our AST
// (no decorations) _is_ the adjacency list. - maybe the parser step should ensure compileability of the expr
// strings? No. That would require a scoped parser, and that is a semantic analyzer thing.
// WHAT DOES THE PARSER DO?
//
// Okay... Maybe the scanner doesnt output the adjacency list then. The question is then: What thing do we need
// to generate an adjacency list? Just a json structure? I mean... The only thing that seems icky about that is
// that we would make the compiler dependent on nlohmann, but is that a problem? It would ensure a valid json
// syntax. Compared to a traditional scanner, would that fit?
//
// Let's see. A C scanner would gladly accept this nonsense: hello int "world" void = 2 = = ==
// The C parser would say that the token stream is fucking stupid, but that's fine. It's valid scanner input.
// Comparatively, if our scanner gets: `{ "hello": 321 }` - that would also be valid scanner input. Again, the
// parser will flip it's shit, because that is clearly not a hawk graph.
// So. The scanner expects valid tokens, and the parser expects that the tokens are sorted in such a manner that
// it makes sense as a hawk graph.
//
// We could also have a custom token stream format instead, that represents an adjacency list, but then again
// why would we do that? To streamline the process, make it more robust and make it easier to extend? - blah!
// i.e. a "DSL" representing an annotated graph - what's it called... a Labelled Transition System!
//
// If we say that the scanner should output valid "tokens" without any context embedded, then an adjacency list
// with "tokens", i.e. nodes, edges and freefloating expressions (symbol declarations) would be the most direct
// approach.
// This approach would make the `{ "hello": 321 }` example not valid scanner input, since it does not describe
// any valid tokens (nodes, edges, declarations).
// A minimal, scanner friendly, but not parser friendly input would then be something like (fluctuations in
// syntaxes can be addressed by other scanners):
// ```json
// {
// "declarations": "...",
// "edges": [
// {...}
// ],
// "vertices": [
// {...}
// ]
// }
// ```
// In any case, the output of the scanner is a struct with nodes (vertices), edges and symbol declarations.
// Without regard of context consistency.
//
// Now the question stands: Who should complain about missing json keys? = THE SCANNER, because a missing key in
// a vertex is an invalid "token". Not an invalid grammar thing. The parser should complain if the graph is not
// a properly defined graph (i.e. the _contents_ of the keys in the vertices are consistent), that could be a
// badly formed (syntactically incorrect) update expression, a non-existent edge source, or even an unrecognized
// vertex type (yes, that is the parser's responsibility to check. Not the scanner. Think; scanner checks that
// the keys exist, parser checks that the values at least make some sense) - then we can do semantic analysis,
// and all that cool optimization magic code!
//
// Now. A HUPPAAL HAWK file's edges will be annotated with guards and updates directly on the edge object, which
// is fine and all, but a Graphedit HAWK file's edges are not structured like that. Whom'stve's responsibility
// is it to unify these two different ways of modelling? The scanner? Perhaps...
// Scanner:
// - The GrapheditScanner should then translate the edge L--g--u-->L' into [L,L'], [<L,g,u,L'>]. The edge would
// be "recreated", so we should keep track of the original edge identifiers for error reporting.
// - The HUPPAALScanner should probably not do much.
//
// Parser:
// This would mean that the scanners won't be outputting the same struct...
//
// Exploratory:
// C: var a = 3; --> <VARKW> <IDENT:a> <EQ> <LIT:3>
// GE: L--g--u--L' --> [L, g, u, L'] [<Lg>,<gu>,<uL'>] << This could be <Lg:g> :thinking:
// HU: LguL' --> [L,L'] [<LL':gu>]
//
// Should <gu> be <gu:gu>, or just <gu:u> ?
for(const auto& filepath : filepaths) {
for(const auto& entry: std::filesystem::directory_iterator(filepath)) {
try {
Expand Down
6 changes: 3 additions & 3 deletions src/parser/hawk/huppaal/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ namespace aaltitoad::hawk::huppaal {
auto load_part(const nlohmann::json& json_file) -> std::string;
};

class json_parser_t : public scanner_t, aaltitoad::hawk::parser_t {
class json_parser_t : public scanner, aaltitoad::hawk::parser {
public:
~json_parser_t() override = default;
auto scan(compiler& ctx,
const std::vector<std::string>& filepaths,
const std::vector<std::string>& ignore_list) const noexcept -> std::expected<std::string, error> override;
auto parse(compiler& ctx, const std::string& stream) const noexcept -> std::expected<int, error> override;
const std::vector<std::string>& ignore_list) const noexcept -> std::expected<scanner::result, error> override;
auto parse(compiler& ctx, const scanner::result& stream) const noexcept -> std::expected<parser::result, error> override;
private:
auto should_ignore(const std::filesystem::directory_entry& entry, const std::vector<std::string>& ignore_list) const -> bool;
auto should_ignore(const std::filesystem::directory_entry& entry, const std::string& ignore_regex) const -> bool;
Expand Down
69 changes: 61 additions & 8 deletions src/parser/hawk/model.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ namespace aaltitoad::hawk {
double y;
};

// ============================================================================================================= //
namespace scanning {
struct vertex {
std::string identifer;
std::string type;
std::string type; // e.g. "LOCATION", "TEMPLATE_INSTANCE"
std::vector<std::string> modifiers; // e.g. "IMMEDIATE", "FINAL"

struct {
Expand Down Expand Up @@ -49,17 +50,69 @@ namespace aaltitoad::hawk {
};
}

// ============================================================================================================= //
namespace parsing {
enum class location_mod {
IMMEDATE,
INITIAL,
FINAL
enum class location_modifier {
IMMEDATE, // Immediate in terms of immediacy
INITIAL, // The location is an initial location in the template
FINAL // The location is a final location in the template
};

enum class template_modifier {
MAIN // The template is the main template - only one per network is allowed
};

enum class vertex_type {
LOCATION,
INTERMEDIATE,
TEMPLATE_INSTANCE
LOCATION, // Semantically signifigant locations
INTERMEDIATE, // Nails, joints, forks, comments, etc.
TEMPLATE_INSTANCE // Instantiations - incoming/outgoing edges determine the composition
};

struct location {
std::string identifier;
std::vector<location_modifier> modifiers;

struct {
std::optional<std::string> name;
std::optional<position> position;
} debug;
};

struct instantiation {
std::string identifier;
std::string template_identifier;
std::string instatiation_expression;

struct {
std::optional<std::string> name;
std::optional<position> position;
} debug;
};

struct edge {
std::string identifier;
std::string source;
std::optional<std::string> guard; // TODO: should be expr compiled tree
std::optional<std::string> update;
std::string target;

struct {
std::optional<std::string> name;
} debug;
};

struct template_t {
std::string identifier;
std::string signature;
std::optional<std::string> declarations; // TODO: should be expr compiled tree
std::vector<location> locations;
std::vector<edge> edges;
std::vector<template_modifier> modifiers;

struct {
std::optional<std::string> name;
std::optional<std::string> filepath;
} debug;
};
}
}
Expand Down

0 comments on commit 8f11c35

Please sign in to comment.