comments and refactor
This commit is contained in:
parent
34c0fbf38a
commit
81ebf1d8eb
2 changed files with 95 additions and 79 deletions
165
NouVeL/NVL.cpp
165
NouVeL/NVL.cpp
|
@ -2,6 +2,11 @@
|
|||
#include "NVL.h"
|
||||
|
||||
namespace {
|
||||
void skip_ws(std::ifstream& stream)
|
||||
{
|
||||
stream >> std::ws;
|
||||
}
|
||||
|
||||
const std::map<char, char> 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<char> 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<std::string, std::vector<Object>> content = "";
|
||||
std::variant<std::string, std::vector<Object>> 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<std::streampos>(1))
|
||||
{
|
||||
parse_Object<false, false>(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<std::streampos>(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<std::string>(content) + c;
|
||||
}
|
||||
nvl.get(c); // rid of final scoper
|
||||
nvl.get(c); // skip ending scoper
|
||||
|
||||
this_object.Value = std::get<std::string>(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<std::string>(content) + c;
|
||||
content = std::get<std::string>(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<std::string>(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<std::string>(content).begin(), std::get<std::string>(content).end(), isspace))
|
||||
return;
|
||||
// default case if content does not match keywords
|
||||
this_object.Value = std::get<std::string>(content);
|
||||
}
|
||||
}
|
||||
|
@ -206,14 +237,10 @@ namespace NVL
|
|||
|
||||
if (is_parent_call)
|
||||
(std::get<std::reference_wrapper<Call>>(parent_context.Scope_Hierarchy.back())).get().Objects.push_back(this_object);
|
||||
else if ((std::get<std::reference_wrapper<Object>>(parent_context.Scope_Hierarchy.back())).get().Value.index() == 4) // 4 for list
|
||||
{
|
||||
else if ((std::get<std::reference_wrapper<Object>>(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::vector<Object>>((std::get<std::reference_wrapper<Object>>(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<std::reference_wrapper<Object>>(parent_context.Scope_Hierarchy.back())).get().Value = std::vector<Object> { 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<true, true>(this_context, nvl);
|
||||
|
||||
// parse the rest
|
||||
while (!(nvl.peek() == '\n' || nvl.peek() == '}'))
|
||||
{
|
||||
parse_Object<true, false>(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<std::streampos>(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<std::vector<Object>>(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);
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
#include <fstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <regex>
|
||||
#include <variant>
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
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 <bool is_parent_call, bool is_symbol>
|
||||
void parse_Object(Context parent_context, std::ifstream& nvl);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue