Skip to content

Commit

Permalink
Parent tree built at construction (see #5)
Browse files Browse the repository at this point in the history
+ Oh, and fixing a missing #endif from the prev. commit...
  • Loading branch information
xparq committed Sep 5, 2023
1 parent a9530f0 commit eb147ca
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 5 deletions.
35 changes: 30 additions & 5 deletions parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
#ifdef COPYLESS_GRAMMAR
#warning COPYLESS_GRAMMAR is not properly implemented yet; disabled. (See #19!)
#undef COPYLESS_GRAMMAR
#endif

//=============================================================================
//---------------------------------------------------------------------------
Expand Down Expand Up @@ -238,6 +239,8 @@ struct RULE
//!! Can't define this outside of RULE, sadly. But shipping with a `using RULE::PRODUCTION` can help!
using PRODUCTION = std::vector<RULE>;

const RULE* _parent = nullptr; // top-level rule, if no parent

enum {
OP,
PROD,
Expand Down Expand Up @@ -304,12 +307,18 @@ struct RULE
bool is_opcode() const { return type == OP; }

const PRODUCTION& prod() const { assert(type == PROD);

#ifdef COPYLESS_GRAMMAR
return _prod.get();
#else
#else
return _prod;
#endif
#endif
}
PRODUCTION& prod() { assert(type == PROD);
#ifdef COPYLESS_GRAMMAR
return _prod.get();
#else
return _prod;
#endif
}


Expand Down Expand Up @@ -338,6 +347,8 @@ DBG("RULE::PROD-copy-ctor creating [{}] from [{}] as PROD[0].type: {}...",
if (prod().empty()) {
_destruct(); // Clean up the empty PROD we've just created...
_init_as_nil();
} else {
_relink_parents();
}
//DBG("RULE::PROD-ctor creating [{}] done.", (void*)this);
}
Expand Down Expand Up @@ -396,6 +407,8 @@ DBG("RULE::PROD-move-ctor created [{}] from PROD[0].type: {}...", (void*)this, p
if (prod().empty()) {
_destruct(); // Clean up the empty PROD we've just created...
_init_as_nil();
} else {
_relink_parents();
}
}

Expand Down Expand Up @@ -437,6 +450,14 @@ DBG("- Setting up empty rule...");

void _init_atom(auto&& s);

void _relink_parents() {
if (!is_prod()) return;
for(auto& r : prod()) {
r._parent = this;
r._relink_parents();
}
}

void _destruct() {
//DBG("RULE::destruc (type: {})...", _type_cstr()); //DUMP();
assert (type != _DESTROYED_);
Expand All @@ -463,6 +484,8 @@ DBG("- Setting up empty rule...");
else if (type == PROD) new (const_cast<PRODUCTION*>(&_prod)) PRODUCTION(other.prod()); //! Can't use is_prod() here: it's false if empty()!
#endif
else opcode = other.opcode; // just a number...

_relink_parents();
DBG("RULE::_copy (type == {}) done.", _type_cstr());
}

Expand All @@ -486,6 +509,8 @@ DBG("RULE::_copy (type == {}) done.", _type_cstr());
#endif
else opcode = std::move(tmp.opcode); // just a number...
tmp.type = _MOVED_FROM_;

_relink_parents();
DBG("RULE::_move (type == {}) done.", _type_cstr());
}

Expand Down Expand Up @@ -517,8 +542,8 @@ DBG("RULE::_move (type == {}) done.", _type_cstr());
auto _p [[maybe_unused]] = [&](auto x, auto... args) {cerr << x << endl; };

if (!level) p("/------------------------------------------------------------------\\");
if (d_name.empty()) p_(format("[{}] {} (type #{}):", (void*)this, _type_cstr(), (int)type));
else p_(format("[{}] {} (type #{}) '{}':", (void*)this, _type_cstr(), (int)type, d_name));
if (d_name.empty()) p_(format("[{} :{}] {} (type #{}):", (void*)this, (void*)_parent, _type_cstr(), (int)type));
else p_(format("[{} :{}] {} (type #{}) '{}':", (void*)this, (void*)_parent, _type_cstr(), (int)type, d_name));
if (type == _DESTROYED_) p(" !!! INVALID (DESTROYED) OBJECT !!!");
if (type == _MOVED_FROM_) p(" !!! INVALID (MOVED-FROM) OBJECT !!!");
if (is_atom()) { _p(format(" \"{}\"", atom));
Expand Down
69 changes: 69 additions & 0 deletions test/OP_NAME_AND_CALL.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#include "../parser.hpp"

//---------------------------------------------------------------------------
// TEST CASES
//---------------------------------------------------------------------------
#include "./fw/doctest-setup.hpp"

// Global env. for the test cases...
using namespace Parsing;

CASE("CAPTURE: nested") {
RULE code = _{_MANY, _{_OR, "_ID", "=", "_DIGITS", ";", "_WHITESPACES"} };
RULE block_in = _{"<", _{_SAVE_AS, "inner", code}, ">"};
RULE block_out = _{"<", _{_SAVE_AS, "outer",
_{ _{_OPT, code}, _{_OPT, block_in}, _{_OPT, code} },
}, ">"};

Parser p(block_out); p.syntax.DUMP();

CHECK(p.parse("<outer <inner> block>"));
CHECK(p["inner"] == "inner");
CHECK(p["outer"] == "outer <inner> block");

CHECK(p.parse("<outer < x = 1; y = 22; > block>"));
CHECK(p["inner"] == " x = 1; y = 22; "); //! Mind the spaces...
CHECK(p["inner"] != "x = 1; y = 22;" ); //! Mind the spaces...
CHECK(p["outer"] == "outer < x = 1; y = 22; > block");
}



//===========================================================================
int main(int argc, char** argv)
//===========================================================================
{
doctest::Context TEST;
TEST.applyCommandLine(argc, argv);

try {
Parsing::init();

auto _NAME = OPCODE(':');

OPERATORS[_NAME] = [](Parser& p, size_t pos, const RULE& rule, OUT size_t& len) -> bool {
/* // Shift off the CAPTURE prefix...
//!! ...which, alas, currently means full cloning... :-/
RULE target_rule(PROD(rule.prod().cbegin() + 1, rule.prod().cend()));
if (p.match(pos, target_rule, len)) {
cerr << "\n\n SNAPSHOT: [" << string_view(p.text).substr(pos, len) << "]" << "\n\n";
return true;
}
*/ return false;
};


TEST.run();

} catch(std::runtime_error& x) {
cerr << x.what() << "\n";
exit(-1);
} catch(std::exception& x) {
cerr << "- C++ runtime error: " << x.what() << "\n";
exit(-2);
} catch(...) {
cerr << "- UNKNOWN ERROR(S)!...\n";
exit(-9);
}
}

0 comments on commit eb147ca

Please sign in to comment.