From 81ebf1d8eb9179e95d2dd1d5f2e159a96d6cb076 Mon Sep 17 00:00:00 2001 From: lachrymaL Date: Sat, 15 May 2021 17:48:37 -0400 Subject: [PATCH] comments and refactor --- NouVeL/NVL.cpp | 165 ++++++++++++++++++++++++++++--------------------- NouVeL/NVL.h | 9 +-- 2 files changed, 95 insertions(+), 79 deletions(-) diff --git a/NouVeL/NVL.cpp b/NouVeL/NVL.cpp index 408d863..2222950 100644 --- a/NouVeL/NVL.cpp +++ b/NouVeL/NVL.cpp @@ -2,6 +2,11 @@ #include "NVL.h" namespace { + void skip_ws(std::ifstream& stream) + { + stream >> std::ws; + } + const std::map SCOPER_MAP = { {'{', '}' }, // CURLY {'<', '>'}, // ANGLED @@ -14,6 +19,7 @@ namespace { bool need_escape(char c) { + // todo: refactor, too cryptic return (c == '\'' || c == '\"'); } @@ -21,8 +27,12 @@ namespace { std::vector Scope; }; - std::streampos scope_cope(char scope_char, std::ifstream& stream) + std::streampos scope_cope(char scope_char, std::ifstream& stream) { + // important + // scope_cope() expects the scope opener to already have been fetched and stored in scope_char + // i.o.w. it wont be able to cope properly because there will be one extra level of scope that it cannot match + std::streampos initial = stream.tellg(); std::streampos final; @@ -34,15 +44,10 @@ namespace { while (!current_scope.Scope.empty()) { stream.get(c); - bool no_more_nesting_quotes = false; - for (auto& x : current_scope.Scope) - { - if (x == '\'' || x == '\"') - { - no_more_nesting_quotes = true; - } - } + // there cannot be any more scope inside of quoted strings + bool no_more_nesting_quotes = (current_scope.Scope.back() == '\'' || current_scope.Scope.back() == '\"'); + // push scope if opening scoper is found bool set_scope_on_this_iter = false; if (!no_more_nesting_quotes) { for (auto const& x : SCOPER_MAP) @@ -55,6 +60,8 @@ namespace { } } + // pop last scope if ending scoper is found + // set_scope_on_this_iter to prevent immediately popping scopers that have the same closers and openers if (!set_scope_on_this_iter && c == SCOPER_MAP.at(current_scope.Scope.back())) current_scope.Scope.pop_back(); @@ -67,6 +74,7 @@ namespace { } } + // cannot match all the copes and has read to the end of the file if (stream.eof()) { std::cerr << "Can't cope with scope!" << std::endl; @@ -83,37 +91,46 @@ namespace { std::string read_sequence_name(std::ifstream& nvl) { - nvl >> std::ws; + // this function will move the reading head of nvl, this is hard to keep track of but simplifies the program + skip_ws(nvl); std::string token; - char c; - while (nvl.get(c)) + char c{}; + + nvl.get(c); + while (c != ' ' && c != '{' && c != '\n') { - if (c == ' ' || c == '{' || c == '\n') - { - nvl.putback(c); - break; - } - else - token += c; + token += c; + nvl.get(c); } + nvl.putback(c); return token; } void skip_comment_ouside_sequence(std::ifstream& nvl, char& c) { - // assumes c is ';' - while (c != '\n') - { - nvl.get(c); - } - nvl >> std::ws; if (nvl.peek() == ';') { nvl.get(c); + while (c != '\n') + { + nvl.get(c); + } + + skip_ws(nvl); + skip_comment_ouside_sequence(nvl, c); + + skip_ws(nvl); + } + } + + void indent_loop(int indent) + { + for (int i = 0; i < indent; i++) + { + std::cout << "\t"; } - nvl >> std::ws; } } @@ -126,30 +143,32 @@ namespace NVL Context this_context = parent_context; this_context.Scope_Hierarchy.push_back(this_object); - nvl >> std::ws; + skip_ws(nvl); std::streampos end; // unused if object is not scoped - bool is_comment = false; - std::variant> content = ""; + std::variant> content = ""; // init to empty str char c{}; + + // early exit for comments if (nvl.peek() == ';' && is_parent_call) { while (nvl.peek() != '\n') nvl.get(c); return; } + switch (nvl.peek()) { case '[': // List - nvl.get(c); // do not exchange this line with the next one + nvl.get(c); end = scope_cope('[', nvl); while (nvl.tellg() < end - static_cast(1)) { parse_Object(this_context, nvl); - nvl >> std::ws; + skip_ws(nvl); } - nvl.get(c); + nvl.get(c); // skip ending scoper (']') break; case '<': // Dialogue, not yet implemented end = scope_cope('<', nvl); @@ -160,21 +179,28 @@ namespace NVL while (nvl.tellg() < end - static_cast(1)) { nvl.get(c); - if (c == '\\' && (nvl.peek() == '\'' || nvl.peek() == '\"')) + + // do not concat escaping '\' to content + if (c == '\\' && (nvl.peek() == '\'' || nvl.peek() == '\"')) continue; + content = std::get(content) + c; } - nvl.get(c); // rid of final scoper + nvl.get(c); // skip ending scoper this_object.Value = std::get(content); break; default: - for (nvl.get(c); !(c == ' ' || c == '\n' || c == '}' || c == ']' || c == ','); nvl.get(c)) + nvl.get(c); + while (c != ' ' && c != '\n' && c != '}' && c != ']' && c != ',') { - content = std::get(content) + c; + content = std::get(content) + c; + nvl.get(c); } - if (c == ']' || c == '}' || c == '\n') + + // ']' handled in next object parse, '}' handled in sequence parse, '\n' will be skipped somewhere with skip_ws(), where? idk + if (c == ']' || c == '}' || c == '\n') { nvl.putback(c); } @@ -182,6 +208,7 @@ namespace NVL try { + // try number this_object.Value = std::stof(std::get(content)); } catch (std::exception) @@ -195,6 +222,10 @@ namespace NVL } else { + // early return if string is empty, this should only happen if calling from an object (not a call) + if (std::all_of(std::get(content).begin(), std::get(content).end(), isspace)) + return; + // default case if content does not match keywords this_object.Value = std::get(content); } } @@ -206,14 +237,10 @@ namespace NVL if (is_parent_call) (std::get>(parent_context.Scope_Hierarchy.back())).get().Objects.push_back(this_object); - else if ((std::get>(parent_context.Scope_Hierarchy.back())).get().Value.index() == 4) // 4 for list - { + else if ((std::get>(parent_context.Scope_Hierarchy.back())).get().Value.index() == 4) // 4 for list, indicates that parent is an object that is already a vector of objects std::get>((std::get>(parent_context.Scope_Hierarchy.back())).get().Value).push_back(this_object); - } - else - { + else // parent is not yet vector, initialize as (change from nil to) vector (std::get>(parent_context.Scope_Hierarchy.back())).get().Value = std::vector { this_object }; - } } void parse_Call(Context parent_context, std::ifstream& nvl) @@ -223,8 +250,10 @@ namespace NVL Context this_context = parent_context; this_context.Scope_Hierarchy.push_back(this_call); + // parse the symbol (first obj in call) parse_Object(this_context, nvl); + // parse the rest while (!(nvl.peek() == '\n' || nvl.peek() == '}')) { parse_Object(this_context, nvl); @@ -239,19 +268,15 @@ namespace NVL Context this_context = parent_context; this_context.Scope_Hierarchy.push_back(this_sequence); - nvl >> std::ws; + skip_ws(nvl); char c{}; - - if (nvl.peek() == ';') - { - nvl.get(c); - skip_comment_ouside_sequence(nvl, c); - } + skip_comment_ouside_sequence(nvl, c); this_sequence = Sequence(read_sequence_name(nvl)); - nvl >> std::ws; + skip_ws(nvl); + nvl.get(c); // get { if (c != '{') @@ -265,7 +290,7 @@ namespace NVL while (nvl.tellg() < end_pos - static_cast(1)) { parse_Call(this_context, nvl); - nvl >> std::ws; + skip_ws(nvl); } nvl.get(c); // get } @@ -279,22 +304,18 @@ namespace NVL nvl.open(path); if (nvl.is_open()) { - Context current_context; - current_context.Scope_Hierarchy.push_back(root); while (!nvl.eof()) { + // parse_Sequence() already takes care of comments before a sequence parse_Sequence(current_context, nvl); - nvl >> std::ws; - { - if (nvl.peek() == ';') { - char c{}; - nvl.get(c); - skip_comment_ouside_sequence(nvl, c); - } - } - nvl >> std::ws; + skip_ws(nvl); + + char c{}; + skip_comment_ouside_sequence(nvl, c); + + skip_ws(nvl); } nvl.close(); @@ -306,18 +327,12 @@ namespace NVL } - void indent_loop(int indent) - { - for (int i = 0; i < indent; i++) - { - std::cout << "\t"; - } - } void Object::Print(int indent) { indent_loop(indent); std::cout << "Object: "; + switch (Value.index()) { case 0: @@ -337,6 +352,7 @@ namespace NVL break; case 4: std::cout << "List:" << std::endl; + for (auto& x : std::get>(Value)) { x.Print(indent + 1); @@ -344,30 +360,37 @@ namespace NVL break; } } + void Call::Print(int indent) { indent_loop(indent); std::cout << "Call:" << std::endl; + for (auto& x : Objects) { x.Print(indent + 1); } } + void Sequence::Print(int indent) { indent_loop(indent); std::cout << "Sequence " << Name << ":" << std::endl; + for (auto& x : Calls) { x.Print(indent + 1); } + indent_loop(indent); - std::cout << "------------------------" << std::endl; + std::cout << "-----------------------------------------------" << std::endl; } + void Tree::Print(int indent) { indent_loop(indent); std::cout << "Tree:" << std::endl; + for (auto& x : Sequences) { x.Print(indent + 1); diff --git a/NouVeL/NVL.h b/NouVeL/NVL.h index 516f771..a940ea4 100644 --- a/NouVeL/NVL.h +++ b/NouVeL/NVL.h @@ -4,8 +4,8 @@ #include #include #include -#include #include +#include namespace NVL @@ -65,11 +65,4 @@ namespace NVL }; void parse_NVL(Tree& root, std::string path); - - void parse_Sequence(Context parent_context, std::ifstream& nvl); - - void parse_Call(Context parent_context, std::ifstream& nvl); - - template - void parse_Object(Context parent_context, std::ifstream& nvl); }