diff --git a/src/cpp/include/parser.h b/src/cpp/include/parser.h index d903182..2f2c224 100644 --- a/src/cpp/include/parser.h +++ b/src/cpp/include/parser.h @@ -8,6 +8,10 @@ struct Question { + std::string ID; + std::string QuestionText; + std::string Section; + virtual std::string ToString() const = 0; virtual ~Question() = default; }; @@ -24,23 +28,18 @@ enum MultiElementType { }; struct MultiElementQuestion : public Question { - std::string ID; - std::string QuestionText; std::vector Choices; - std::string Section; MultiElementType type; std::string ToString() const override; }; struct Group { - std::string name; - std::string elements; + std::string name; + std::vector elements; }; struct GroupQuestion : public Question { - std::string ID; - std::string QuestionText; std::vector Groups; std::string ToString() const override; diff --git a/src/cpp/qtapp/.cache/clangd/index/main.cpp.6DE93E662B25E657.idx b/src/cpp/qtapp/.cache/clangd/index/main.cpp.6DE93E662B25E657.idx deleted file mode 100644 index e73b53f..0000000 Binary files a/src/cpp/qtapp/.cache/clangd/index/main.cpp.6DE93E662B25E657.idx and /dev/null differ diff --git a/src/cpp/qtapp/.cache/clangd/index/mocs_compilation.cpp.24E22B09DF7BB0D0.idx b/src/cpp/qtapp/.cache/clangd/index/mocs_compilation.cpp.24E22B09DF7BB0D0.idx deleted file mode 100644 index 2d86651..0000000 Binary files a/src/cpp/qtapp/.cache/clangd/index/mocs_compilation.cpp.24E22B09DF7BB0D0.idx and /dev/null differ diff --git a/src/cpp/qtapp/.gitignore b/src/cpp/qtapp/.gitignore index 0f3a6b1..481ed1e 100644 --- a/src/cpp/qtapp/.gitignore +++ b/src/cpp/qtapp/.gitignore @@ -1,2 +1,3 @@ Debug Release +.cache diff --git a/src/cpp/qtapp/main.cpp b/src/cpp/qtapp/main.cpp index c727fc2..1416c0a 100644 --- a/src/cpp/qtapp/main.cpp +++ b/src/cpp/qtapp/main.cpp @@ -199,7 +199,7 @@ void CreateMdems(std::vector& questions) { }; for (size_t i = 0; i < questions.size(); ++i) { - if (AnswerQuestion* mw = dynamic_cast(questions[i])) { + if (MultiElementQuestion* mw = dynamic_cast(questions[i])) { mdems[i]->wFrontText->setText( QString::fromStdString(mw->QuestionText) ); diff --git a/src/cpp/transpiler/.cache/clangd/index/api.cpp.00DF3E88855FBE2C.idx b/src/cpp/transpiler/.cache/clangd/index/api.cpp.00DF3E88855FBE2C.idx deleted file mode 100644 index 0234583..0000000 Binary files a/src/cpp/transpiler/.cache/clangd/index/api.cpp.00DF3E88855FBE2C.idx and /dev/null differ diff --git a/src/cpp/transpiler/.cache/clangd/index/api.h.09188030E1E1AD2B.idx b/src/cpp/transpiler/.cache/clangd/index/api.h.09188030E1E1AD2B.idx deleted file mode 100644 index 3babb38..0000000 Binary files a/src/cpp/transpiler/.cache/clangd/index/api.h.09188030E1E1AD2B.idx and /dev/null differ diff --git a/src/cpp/transpiler/.cache/clangd/index/config.h.37161B9BC74F84AB.idx b/src/cpp/transpiler/.cache/clangd/index/config.h.37161B9BC74F84AB.idx deleted file mode 100644 index cbe0f87..0000000 Binary files a/src/cpp/transpiler/.cache/clangd/index/config.h.37161B9BC74F84AB.idx and /dev/null differ diff --git a/src/cpp/transpiler/.cache/clangd/index/lexer.cpp.83041CDDE7BB82EA.idx b/src/cpp/transpiler/.cache/clangd/index/lexer.cpp.83041CDDE7BB82EA.idx deleted file mode 100644 index a4c1a2a..0000000 Binary files a/src/cpp/transpiler/.cache/clangd/index/lexer.cpp.83041CDDE7BB82EA.idx and /dev/null differ diff --git a/src/cpp/transpiler/.cache/clangd/index/lexer.h.56AED8998E88A18A.idx b/src/cpp/transpiler/.cache/clangd/index/lexer.h.56AED8998E88A18A.idx deleted file mode 100644 index 75fe5a4..0000000 Binary files a/src/cpp/transpiler/.cache/clangd/index/lexer.h.56AED8998E88A18A.idx and /dev/null differ diff --git a/src/cpp/transpiler/.cache/clangd/index/main.cpp.3110054129CACA6D.idx b/src/cpp/transpiler/.cache/clangd/index/main.cpp.3110054129CACA6D.idx deleted file mode 100644 index edfaa5d..0000000 Binary files a/src/cpp/transpiler/.cache/clangd/index/main.cpp.3110054129CACA6D.idx and /dev/null differ diff --git a/src/cpp/transpiler/.cache/clangd/index/parser.cpp.1DA6C31FD012A889.idx b/src/cpp/transpiler/.cache/clangd/index/parser.cpp.1DA6C31FD012A889.idx deleted file mode 100644 index f1ff536..0000000 Binary files a/src/cpp/transpiler/.cache/clangd/index/parser.cpp.1DA6C31FD012A889.idx and /dev/null differ diff --git a/src/cpp/transpiler/.cache/clangd/index/parser.h.A6B071E84CF21EB1.idx b/src/cpp/transpiler/.cache/clangd/index/parser.h.A6B071E84CF21EB1.idx deleted file mode 100644 index 903df12..0000000 Binary files a/src/cpp/transpiler/.cache/clangd/index/parser.h.A6B071E84CF21EB1.idx and /dev/null differ diff --git a/src/cpp/transpiler/.cache/clangd/index/result.h.9FDF8FE2A27152FF.idx b/src/cpp/transpiler/.cache/clangd/index/result.h.9FDF8FE2A27152FF.idx deleted file mode 100644 index ff249d2..0000000 Binary files a/src/cpp/transpiler/.cache/clangd/index/result.h.9FDF8FE2A27152FF.idx and /dev/null differ diff --git a/src/cpp/transpiler/.cache/clangd/index/time.cpp.D8F4534350FEB86F.idx b/src/cpp/transpiler/.cache/clangd/index/time.cpp.D8F4534350FEB86F.idx deleted file mode 100644 index f9c058b..0000000 Binary files a/src/cpp/transpiler/.cache/clangd/index/time.cpp.D8F4534350FEB86F.idx and /dev/null differ diff --git a/src/cpp/transpiler/.cache/clangd/index/time.h.A5DECF25CDA82FFC.idx b/src/cpp/transpiler/.cache/clangd/index/time.h.A5DECF25CDA82FFC.idx deleted file mode 100644 index 5304205..0000000 Binary files a/src/cpp/transpiler/.cache/clangd/index/time.h.A5DECF25CDA82FFC.idx and /dev/null differ diff --git a/src/cpp/transpiler/.gitignore b/src/cpp/transpiler/.gitignore index 0f3a6b1..481ed1e 100644 --- a/src/cpp/transpiler/.gitignore +++ b/src/cpp/transpiler/.gitignore @@ -1,2 +1,3 @@ Debug Release +.cache diff --git a/src/cpp/transpiler/lexer.cpp b/src/cpp/transpiler/lexer.cpp index 32049ff..b210bf6 100644 --- a/src/cpp/transpiler/lexer.cpp +++ b/src/cpp/transpiler/lexer.cpp @@ -111,7 +111,16 @@ Result> TokenizeMdem(const std::string& fileRunes) { row += 1; column = 0; } - buffer.push_back(c); + + if (c == '\\') { + i += 1; + if (i < fileRunes.size()) { + buffer.push_back(fileRunes[i]); + } + continue; + } else { + buffer.push_back(c); + } // SkipWhitetext if (!textStarted) { diff --git a/src/cpp/transpiler/parser.cpp b/src/cpp/transpiler/parser.cpp index fdbbf91..959beaf 100644 --- a/src/cpp/transpiler/parser.cpp +++ b/src/cpp/transpiler/parser.cpp @@ -19,25 +19,45 @@ struct QuestionElement { }; std::string MultiElementQuestion::ToString() const { - std::stringstream choiceOut; + std::stringstream ss; for (const auto& choice : Choices) { char opener; - if (choice.IsCorrect) { + if (type == MultiElementType::Order) { + opener = '^'; + } else if (choice.IsCorrect) { opener = '+'; } else { opener = '-'; } - choiceOut << opener << " " << choice.Answer << "; "; + ss << opener << " " << choice.Answer << "; "; } return std::format( - ":{} section: {} id: {}\n{}", - QuestionText, - Section, - ID, - choiceOut.str() + "\nsection:{}\nid:{}\n{}\n{}", + Section, + ID, + QuestionText, + ss.str() ); } +std::string GroupQuestion::ToString() const { + std::stringstream ss; + for (auto group: Groups) { + ss << group.name << ": "; + for (auto el: group.elements) { + ss << el << ", "; + } + ss << "; "; + } + return std::format( + "\nsection:{}\nid:{}\n{}\n{}", + Section, + ID, + QuestionText, + ss.str() + ); +} + // Automaton for validating token transitions std::map> automata; @@ -166,9 +186,22 @@ Result> ParseQuestions(const std::vector& tokens) std::vector questionElements; bool isOrderQuestion = false; bool isGroupQuestion = false; + bool isPlusQuestion = false; + + auto isInBounds = [tokens](size_t i) { + return i < tokens.size() && tokens[i].tokenType != TokenType::EndOfFile; + }; // Start element parsing & add to the offset. - if (tokens[i + 1].tokenType == TokenType::IdentifierStart) { + if (isInBounds(i + 1) && tokens[i + 1].tokenType == TokenType::ElementOrderModifier) { + return { + questions, + "cannot have order modifier ('^') in the question definition", + tokens[i + 1].row, + tokens[i + 1].column + }; + } + if (isInBounds(i + 1) && tokens[i + 1].tokenType == TokenType::IdentifierStart) { id = tokens[i + 2].content; questionText = tokens[i + 4].content; i += 6; @@ -178,10 +211,6 @@ Result> ParseQuestions(const std::vector& tokens) i += 3; } - auto isInBounds = [tokens](size_t i) { - return i < tokens.size() && tokens[i].tokenType != TokenType::EndOfFile; - }; - // Parse elements of a question. while (isInBounds(i)) { @@ -194,12 +223,17 @@ Result> ParseQuestions(const std::vector& tokens) } // Check question end. - if (tokens[i].tokenType == TokenType::ElementDashStart && isInBounds(i + 3)) { + if (isInBounds(i + 3) && tokens[i].tokenType == TokenType::ElementDashStart) { // Distance to the possible question end. - size_t offset = tokens[i + 1].tokenType == TokenType::IdentifierStart ? 5 : 2; + size_t offset; + if (tokens[i + 1].tokenType == TokenType::ElementOrderModifier) { + offset = tokens[i + 2].tokenType == TokenType::IdentifierStart ? 6 : 3; + } else { + offset = tokens[i + 1].tokenType == TokenType::IdentifierStart ? 5 : 2; + } if (isInBounds(i + offset) && tokens[i + offset].tokenType == TokenType::QuestionEnd) { - break; - } + break; + } if (offset == 5 && tokens[i + 5].tokenType != TokenType::QuestionEnd) { // Cannot place the identifier on the ordinary element. return { @@ -214,39 +248,61 @@ Result> ParseQuestions(const std::vector& tokens) // Determine element type. bool isDash; bool isGroup = false; - if (isInBounds(i+1) && tokens[i].tokenType == TokenType::ElementOrderModifier) { - isOrderQuestion = true; - if (!isDash) { - // TODO: err - } - } + bool isOrder = false; if (tokens[i].tokenType == TokenType::ElementDashStart) { isDash = true; - if (isOrderQuestion) { - // TODO: err - } } else { isDash = false; + isPlusQuestion = true; } - if (isInBounds(i+2) && tokens[i].tokenType == TokenType::MatchGroupEnd) { + if (isInBounds(i+1) && tokens[i + 1].tokenType == TokenType::ElementOrderModifier) { + isOrder = true; + isOrderQuestion = true; + if (!isDash) { + return { + questions, + "order questions can only be used with dashes ('-')", + tokens[i].row, + tokens[i].column + }; + } + if (isGroupQuestion) { + return { + questions, + "question with groups cannot be ordered ('-^' and ':')", + tokens[i].row, + tokens[i].column + }; + } + if (isInBounds(i + 3) && tokens[i + 3].tokenType == TokenType::MatchGroupEnd) { + return { + questions, + "cannot have groups in order question('-^' and ':')", + tokens[i].row, + tokens[i].column + }; + } + } + if (isInBounds(i + 2) && tokens[i + 2].tokenType == TokenType::MatchGroupEnd) { isGroup = true; isGroupQuestion = true; if (!isDash) { - // TODO: err - } - if (isOrderQuestion) { - // TODO: err + return {questions, "group questions can only be used with dashes ('-')"}; } } QuestionElement questionElement; questionElement.isDash = isDash; questionElement.isGroup = isGroup; - questionElement.content = tokens[i + 1].content; + if (isOrder) { + questionElement.content = tokens[i + 2].content; + } else { + questionElement.content = tokens[i + 1].content; + } questionElements.push_back(questionElement); size_t offset = 2; - if (isOrderQuestion) { + if (isOrder) { offset += 1; } if (isGroup) { @@ -256,25 +312,53 @@ Result> ParseQuestions(const std::vector& tokens) i += offset; } - if (questionElements.size() > 1) { + if (questionElements.size() > 0) { if (isGroupQuestion) { - GroupQuestion *question = new GroupQuestion(); - // TODO - - } if (isOrderQuestion) { + auto *question = new GroupQuestion(); + question->ID = id; + question->QuestionText = questionText; + question->Section = section; + int32_t k = -1; + for (size_t i = 0; i < questionElements.size(); ++i) { + auto questionElement = questionElements[i]; + if (questionElement.isGroup) { + ++k; + auto group = Group(); + group.name = questionElement.content; + question->Groups.push_back(group); + } else { + if (k >= 0) { + question->Groups[k].elements.push_back( + questionElement.content + ); + } + } + } + questions.push_back(question); + if (debug) { + std::cout << question->ToString() << "\n"; + } + } else { auto *question = new MultiElementQuestion(); question->ID = id; question->QuestionText = questionText; + question->Section = section; for (const auto& elem : questionElements) { Choice choice; choice.Answer = elem.content; choice.IsCorrect = !elem.isDash; question->Choices.push_back(choice); } - question->Section = section; questions.push_back(question); + if (isPlusQuestion) { + question->type = MultiElementType::MultiChoice; + } else if (isOrderQuestion) { + question->type = MultiElementType::Order; + } else { + question->type = MultiElementType::Regular; + } if (debug) { - std::cout << question->ToString() << "\n"; + std::cout << question->ToString() << "\n"; } } }