diff --git a/NouVeL/Environment.cpp b/NouVeL/Environment.cpp index 1739526..ae6a963 100644 --- a/NouVeL/Environment.cpp +++ b/NouVeL/Environment.cpp @@ -52,4 +52,4 @@ namespace NVL { return env.find(name) != env.end(); } -} \ No newline at end of file +} diff --git a/NouVeL/Environment.h b/NouVeL/Environment.h index f455d77..029a7d7 100644 --- a/NouVeL/Environment.h +++ b/NouVeL/Environment.h @@ -31,4 +31,4 @@ namespace NVL { bool exists(const std::string& name); }; extern Environment ENVIRONMENT; -} \ No newline at end of file +} diff --git a/NouVeL/NouVeL.cpp b/NouVeL/NouVeL.cpp index 763140e..79012f0 100644 --- a/NouVeL/NouVeL.cpp +++ b/NouVeL/NouVeL.cpp @@ -1,13 +1,10 @@ #include "Parser.h" #include "Environment.h" -#include -#include #include #include int main() { - auto f = [](NVL::Variable) { return NVL::Variable(NVL::Type::Nil); }; - NVL::Variable v(f, 1); + NVL::Variable v([](NVL::Variable) { return NVL::Variable(NVL::Type::Nil); }, 1); NVL::ENVIRONMENT.enter("hello", v); diff --git a/NouVeL/Parser.cpp b/NouVeL/Parser.cpp index 57bb5c5..a178af6 100644 --- a/NouVeL/Parser.cpp +++ b/NouVeL/Parser.cpp @@ -26,7 +26,7 @@ namespace { struct Match { std::string accept; - constexpr operator char() const { + operator char() const { return accept[0]; } bool operator== (const std::string& other) const { @@ -36,7 +36,7 @@ namespace { const ParseGroup NUMERIC = { "1234567890" }; const Match DECIMAL_DOT = { "." }; - const ParseGroup ALPHA = { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrst" }; + const ParseGroup ALPHA = { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" }; const Match ARRAY_OPEN = { "[" }; const Match ARRAY_CLOSE = { "]" }; const Match ARRAY_DELIM = { "," }; @@ -60,24 +60,46 @@ namespace { char(COMMENT_BEGIN) }; const Match NEWLINE = { "\n" }; - const Match ESCAPE = { "\\" }; const ParseGroup ESCAPED = { "\\\"" }; + const Match ESCAPE = { "\\" }; + + // Dialogue mode matches + const Match MARKUP_OPEN = { "[" }; + const Match MARKUP_CLOSE = { "]" }; + const Match SPEAKER_OPEN = { "[" }; + const Match SPEAKER_CLOSE = { "]" }; + const Match MARKUP_TEXT_OPEN = { "{" }; + const Match MARKUP_TEXT_CLOSE = { "}" }; + const Match TEMPLATE_IND = { "$" }; + const Match TEMPLATE_OPEN = { "{" }; + const Match TEMPLATE_CLOSE = { "}" }; + + const Match COMMAND_ESCAPE = { "*!" }; + const ParseGroup DIALOGUE_ESCAPED_SINGLE = { + ESCAPE.accept + + char(MARKUP_OPEN) + + char(MARKUP_CLOSE) + + char(MARKUP_TEXT_OPEN) + + char(MARKUP_TEXT_CLOSE) + + // char(SPEAKER_OPEN) + + // char(SPEAKER_CLOSE) + + char(TEMPLATE_IND) + // char(TEMPLATE_OPEN) + + // char(TEMPLATE_CLOSE) + }; + enum class ParseType { Symbol, Number, String, Array, Subexpression }; std::string read_file_to_string(const std::string& path) { std::ifstream f(path); { // Some apps on Windows adds this signature in front of UTF-8 files when saving char a, b, c; - a = f.get(); - b = f.get(); - c = f.get(); - if (a != (char)0xEF || b != (char)0xBB || c != (char)0xBF) { + a = f.get(); b = f.get(); c = f.get(); + if (a != (char)0xEF || b != (char)0xBB || c != (char)0xBF) f.seekg(0); - } - else { + else std::cerr << "Warning: Windows UTF-8 BOM skipped" << std::endl; - } } std::stringstream buffer; buffer << f.rdbuf(); @@ -125,7 +147,6 @@ namespace { }; using Command = std::vector; - class Scene { std::string name; std::vector commands{}; @@ -136,6 +157,15 @@ namespace { } }; + struct Markup { + //... TODO + }; + + struct MarkupInstance { + std::pair range; + std::string effect; //TEMP + }; + void SkipWS(const std::string& f, size_t& pos) { while (WS.accept.find(f[pos]) != std::string::npos) pos++; @@ -292,7 +322,46 @@ namespace { } Command ParseDialogue(const std::string& s) { - return { { ParseType::Symbol, "Say" }, { ParseType::String, s } }; + if (s.substr(0, 2) == COMMAND_ESCAPE.accept) { + size_t dummy = 0; + return ParseCommand(s.substr(2), dummy); // TODO string[] will throw on this 100%, maybe do ParseDialogueCommand + } + + if (s.back() == SPEAKER_CLOSE) { + if (s.front() == SPEAKER_OPEN) { + auto name = s.substr(1, s.length() - 2); + if (IsLegalSymbolName(name)) + return { { ParseType::Symbol, "SwitchSpeaker" }, { ParseType::String, name } }; + } + else + throw std::runtime_error("Malformed speaker command"); + } + + std::vector discards; + for (int i = 0; i < s.length(); i++) { + if (s[i] == ESCAPE) { + if (DIALOGUE_ESCAPED_SINGLE.accept.find(s[i]) != std::string::npos) { + discards.push_back(i++); + } + else + throw std::runtime_error("Unrecognized escape sequence"); + } + } + std::string new_s{s}; + for (int i = 0; i < discards.size(); i++) { + new_s.erase(discards[i] - i, 1); + discards[i] -= i; // New indices become the positions of the escaped characters + } + // TODO + for (int i = 0; i < s.length(); i++) { + if (!discards.empty() && discards[0] < i) { + discards.erase(discards.begin()); + } + + } + + std::cout << new_s << std::endl; + return { { ParseType::Symbol, "Say" }, { ParseType::String, new_s } }; } Scene ParseScene(const std::string& f, size_t& pos) { diff --git a/NouVeL/Parser.h b/NouVeL/Parser.h index c322f0d..b217980 100644 --- a/NouVeL/Parser.h +++ b/NouVeL/Parser.h @@ -3,4 +3,4 @@ namespace NVL { void ParseFile(const std::string& path); -} \ No newline at end of file +} diff --git a/NouVeL/spec.nvl b/NouVeL/spec.nvl index a2bdf88..a10c2d2 100644 --- a/NouVeL/spec.nvl +++ b/NouVeL/spec.nvl @@ -26,7 +26,7 @@ Every new line is a new "click". I discarded the "pause" idea. [Bailey] Je ne suis plus Alex. -Ça ne me arrête pas de vous démontrer notre support multilingue noblement distingué. +Ça ne m'arrête pas de vous démontrer notre support multilingue noblement distingué. [Catherine] CJKテスト! @@ -44,7 +44,7 @@ To grab a value from the environment, do it like this: ${var}. This is also the syntax to evaluate a command from dialogue mode. If the return is void it will say "undefined" or something like that. -*! This "is a command in dialogue mode." +*! This "is a command in dialogue mode." // Dialogue mode commands have to be one liners *! Set var (+ var 1) [NARRATION] @@ -61,6 +61,6 @@ Choice var4 ["Apple", "Orange"] // to have ways to terminate a scene other than END, for instance JUMP can be an alternative like this: // JUMP Scene2 // we can equally do something like this -// JUMP (switch var4 [["Apple", RouteA], ["Orange", RouteB], [default, RouteC]]) +// JUMP (switch var4 [[0, RouteA], [1, RouteB], [default, RouteC]]) END diff --git a/NouVeL/test.nvl b/NouVeL/test.nvl index 8bca0cb..05af1a1 100644 --- a/NouVeL/test.nvl +++ b/NouVeL/test.nvl @@ -1,7 +1,12 @@ BEGIN Scene1 <<- +[Alex] +Hello. Welcome to dialogue mode. +Every new line is a new "click". I discarded the "pause" idea. +[Bailey] Je ne suis plus Alex. -Ça ne me arrête pas de vous démontrer notre support multilingue noblement distingué. +Ça ne m'arrête pas de vous démontrer notre support multilingue noblement distingué. +[Catherine] CJKテスト! 夏はマシンガン。 ->>