diff --git a/input.md b/input.md
index c031c06..72e47cf 100644
--- a/input.md
+++ b/input.md
@@ -1,115 +1,18 @@
-# MarkdownToHtmlCompiler
-
-### Project Overview
-
-The goal is to create a program that reads a file containing text formatted in a simple version of
-Markdown and converts it into a valid HTML file. The program will need to identify and translate
-specific syntax (e.g., ` Heading` to `\
Heading\
`, `*text*` to `\text\`).
+hello `world`
-### Implementation Requirements (Generated by Gemini)
+This `is also a code block`
-Class Hierarchy: Design a class hierarchy to represent the components of your Markdown document. An
-abstract base class, Element, can define common behavior. Derived classes would then represent specific
-types of elements, such as Heading, Paragraph, BoldText, and ListItem. This is a perfect example of
-inheritance and polymorphism.
+hi `mom
+hello`
-Object Composition: A Document class can be composed of multiple Element objects, representing the
-entire file. A Parser class would be composed of helper methods to break down the input string and
-build the Document object. This shows how you can build a complex system from smaller, self-contained
-objects.
+hi `mom
-File I/O and Exceptions: You will need to use ifstream to read the Markdown file and ofstream to write
-the generated HTML file. Your code should use exceptions to gracefully handle potential errors, such
-as a file not being found.
-
-Operator Overloading: Overload the << stream insertion operator for your Element and Document classes.
-This would allow you to easily print the generated HTML to the console or write it to a file, making
-your code cleaner and more readable.
-
-UML Diagram: The complexity of the class relationships makes a UML diagram an essential part of the
-project. It will help you plan your design and will be a key component of your submission.
-
-Recursive Descent Parser: This is the primary algorithm you'll use. It's a top-down parsing technique
-where a set of recursive functions "descend" through the grammar of your simple Markdown language. For
-example, a parse_document() function would call parse_line(), which in turn might call parse_bold_text()
-or parse_italic_text(). This method is intuitive and easy to implement for a simple grammar.
-
-Stack: A stack is essential for handling nested elements. For instance, if you allow bold text inside
-italic text (_This is *bold and italic* text_), you can push the _ token onto the stack and then push
-the * token. When you encounter the closing *, you check if the top of the stack matches. This ensures
-that all tags are correctly opened and closed. Your presentation can visually demonstrate this process
-with a stack diagram.
-
-Hash Map or Map: A hash map (std::unordered_map) or a map (std::map) can be used to efficiently store
-and retrieve the HTML equivalent for each Markdown tag. For example, you could map `#` to `\`or `*`
-to `\`. This provides O(1) average-case lookup time.
+this is too far`
-### Contribution Policy
+*this is **words***
-###### Branching
-When working on this project, please use a feature branch (i.e. `feature/parser`) with a descriptive name.
-`feature/a` is not a descriptive name. These branches should be branched off the most recent `main` branch,
-we will not make use of a `dev` or `staging` branch since the project is small in scale as well as time.
-**However, if the project becomes larger or out-of-control, a dev/staging branch will be implemented.**
+## **Hello world**
-###### Commits
-
-When working, it is best practice to commit code as much as possible, without being over zealous. For
-example, when a feature or bug is complete, its time to commit. But when you have to make a new function,
-that does not mean its time. Each team member should use their best judgment.
-
-Commit messages a little bit more important, when working in a team, it is important to provide strong,
-clear and concise commit messages. In this project, the team will use a simple formula:
-
-**(SUBJECT) Title: textual description**
-
-i.e. (FIX) Rendering completed: explain what changed in short.
-
-###### Pushing
-
-When working in a feature branch, pushing and pulling has no restrictions. Feel free to do as much
-(or as little) as possible. However, you **CANNOT** push directly to `main`, the VCS will not allow you
-to do so, but do not make that mistake. When you are ready to merge a feature, you will create a PR
-and once it has been reviewed and approved it will be automatically merged in.
-
-###### Pull Requests (PR)
-
-Once a feature is complete, you will create a pull request. Before a request can be merged into `main`,
-one approval is required (which cannot be the author). This practice is to promote team work and encourage
-code reviews. Each team member is expected to check in frequently and review as often as they are able to,
-however, there is no defined time requirement. Personal communication is totally acceptable as a means to
-request approval, since I am unsure if this platform will notify members.
-
-###### Issues
-
-If a bug, issue, or otherwise concern is noticed the first thing the team member should do is create an
-issue. An issue should be descriptive and contain everything another team member needs to understand the
-issue and its context. This way, a new team member can tackle the issue without contextual gaps.
-
-If a member would like to work on the issue themself, the `assignee` field is where this should be defined.
-If a member would like help from another member, they should assign the other team member to the issue, and
-leave a comment in the issue itself describing what help is needed.
-
-**Labels** are important for understanding what type of issues/bugs exist in the application. When a bug is
-created, make sure the proper labels are applied. These labels will be abstract, such as: `bug`, `fix` or `feature`
-and they will also be specific, such as: `parser`, `i/o` or `processer`. A combination of both styles of labels
-allows other team members to understand what is going on. If a member feels an issue is missing, they are free
-to create new ones, but there is a such thing as **too many labels** a few per issue is totally fine. They are
-not meant to replace the description.
-
-**Priority** is the final important factor to consider. In this project, priority will be defined using labels
-as well. The policy defined above will apply here to priority labels as well. However, these labels are
-**mutually exclusive**.
-
-###### Projects (Sprints)
-
-The use of the `projects` tab in the VCS will allow the team to remain organized as create notes and action
-items that should be completed before one another. These resemble `sprints` from the `AGILE` development life cycle.
-A new "project" should be created when a large piece of functionality needs to be created. Issues can **and should**
-be attached to the projects they are related too. This will continue to encourage teamwork and organization.
-
-Projects should have defined criteria, such as input and outputs, expectations and a semi-defined timeline.
-Once a description and is defined, tasks can be added and moved around as needed. The team will use **Kanban**
-project types, as they are simple and easy to understand for new team members.
+### hello world
diff --git a/lib/inlineNode.cpp b/lib/inlineNode.cpp
index 22b4788..625de65 100644
--- a/lib/inlineNode.cpp
+++ b/lib/inlineNode.cpp
@@ -21,3 +21,5 @@ string BoldNode::ToHtml() const {
string BoldItalicNode::ToHtml() const {
return "" + this->content + "";
}
+
+string CodeNode::ToHtml() const { return "" + this->content + ""; }
diff --git a/lib/inlineNode.h b/lib/inlineNode.h
index 7655afd..af825a7 100644
--- a/lib/inlineNode.h
+++ b/lib/inlineNode.h
@@ -2,6 +2,7 @@
#define INLINENODE_H
#include "node.h"
+#include
#include
/**
@@ -37,6 +38,15 @@ public:
*/
void AddChild(std::unique_ptr child);
+ /**
+ * @brief Is the node empty.
+ *
+ * This is the same as checking if the nodes content is empty.
+ *
+ * @author Hayden Hargreaves (hhargreaves2006@gmail.com)
+ */
+ bool IsEmpty() const { return this->content.empty(); };
+
protected:
std::string content;
};
@@ -94,4 +104,17 @@ public:
std::string ToHtml() const;
};
+/**
+ * @desc An inline code block node.
+ *
+ * This node returns it's content wrapped with tags.
+ *
+ * @author Hayden Hargreaves (hhargreaves2006@gmail.com)
+ */
+class CodeNode : public InlineNode {
+public:
+ CodeNode(std::string content) : InlineNode(content) {};
+ std::string ToHtml() const;
+};
+
#endif
diff --git a/lib/node.h b/lib/node.h
index 390b004..6009d1c 100644
--- a/lib/node.h
+++ b/lib/node.h
@@ -18,7 +18,6 @@
/// try to avoid using raw pointers, and only use references when needed.
/// Reference: https://www.youtube.com/watch?v=AmjoK55h68Y&t=166s
-// NOTE ABC
class Node {
protected:
/**
@@ -67,6 +66,15 @@ public:
virtual const std::vector> &GetChilren() const {
return this->children;
}
+
+ /**
+ * @brief Is the node empty.
+ *
+ * This is done differently for inline nodes and structure nodes.
+ *
+ * @author Hayden Hargreaves (hhargreaves2006@gmail.com)
+ */
+ virtual bool IsEmpty() const = 0;
};
#endif
diff --git a/lib/parser.cpp b/lib/parser.cpp
index 86ab32d..54372e5 100644
--- a/lib/parser.cpp
+++ b/lib/parser.cpp
@@ -89,7 +89,7 @@ std::unique_ptr Parser::ParseParagraph() {
node->AddChild(std::move(text_node));
}
- if (node->GetChilren().size() < 1)
+ if (node->IsEmpty())
return nullptr;
return node;
@@ -143,15 +143,29 @@ vector> Parser::ParseInline() {
if (c == '*' && Peek(1) == '*' && Peek(2) == '*') {
PushTextNode(nodes, str);
- nodes.push_back(std::move(ParseBoldItalic()));
+ auto node = ParseBoldItalic();
+ if (!node->IsEmpty())
+ nodes.push_back(std::move(node));
continue;
} else if (c == '*' && Peek(1) == '*') {
PushTextNode(nodes, str);
- nodes.push_back(std::move(ParseBold()));
+ auto node = ParseBold();
+ if (!node->IsEmpty())
+ nodes.push_back(std::move(node));
continue;
} else if (c == '*') {
PushTextNode(nodes, str);
- nodes.push_back(std::move(ParseItalic()));
+ auto node = ParseItalic();
+ if (!node->IsEmpty())
+ nodes.push_back(std::move(node));
+ continue;
+ }
+
+ if (c == '`') {
+ PushTextNode(nodes, str);
+ auto node = ParseCode();
+ if (!node->IsEmpty())
+ nodes.push_back(std::move(node));
continue;
}
@@ -231,6 +245,28 @@ std::unique_ptr Parser::ParseBoldItalic() {
return std::make_unique(str);
}
+std::unique_ptr Parser::ParseCode() {
+ string str;
+ Consume(1);
+
+ while (!IsEOF()) {
+ char c = Peek();
+
+ if (c == '\n' && Peek(1) == '\n')
+ break;
+
+ if (c == '`') {
+ Consume(1);
+ break;
+ }
+
+ str += c;
+ Consume();
+ }
+
+ return std::make_unique(str);
+}
+
void Parser::PushTextNode(vector> &nodes, string &str) {
if (!str.empty())
nodes.push_back(std::move(std::make_unique(str)));
@@ -252,7 +288,6 @@ void Parser::Consume(size_t count) { this->position += count; };
bool Parser::IsEOF() { return this->position >= this->content.length(); };
void Parser::ConsumeWhiteSpace() {
- // TODO: This can be optimized using an accumulator and then consuming
char c = Peek();
while (c == ' ' || c == '\t' || c == '\n') {
Consume();
diff --git a/lib/parser.h b/lib/parser.h
index cd24c74..63766af 100644
--- a/lib/parser.h
+++ b/lib/parser.h
@@ -126,6 +126,7 @@ private:
std::unique_ptr ParseItalic();
std::unique_ptr ParseBold();
std::unique_ptr ParseBoldItalic();
+ std::unique_ptr ParseCode();
char Peek(size_t offset = 0);
void Consume(size_t count = 1);
diff --git a/lib/structureNode.h b/lib/structureNode.h
index c45feea..7e07bf8 100644
--- a/lib/structureNode.h
+++ b/lib/structureNode.h
@@ -2,6 +2,7 @@
#define STRUCTURENODE_H
#include "node.h"
+#include
#include
/**
@@ -23,6 +24,15 @@ public:
* @author Hayden Hargreaves (hhargreaves2006@gmail.com)
*/
virtual std::string ToHtml() const = 0;
+
+ /**
+ * @brief Is the node empty.
+ *
+ * This is the same as checking if the node has no children.
+ *
+ * @author Hayden Hargreaves (hhargreaves2006@gmail.com)
+ */
+ bool IsEmpty() const { return this->children.size() == 0; };
};
/**
diff --git a/src/main.cpp b/src/main.cpp
index cf4be4c..13be374 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -79,7 +79,7 @@ void test_input(int argc, char **argv) {
}
int main(int argc, char **argv) {
- Parser p("syntax.md");
+ Parser p("input.md");
p.ParseDocument();
p.WriteOutput();