From 14d5eee237b0d900e9862da29688649b90ee3e49 Mon Sep 17 00:00:00 2001 From: Hayden Hargreaves Date: Thu, 16 Oct 2025 12:08:58 -0700 Subject: [PATCH] (FEAT): Working on node implementation. The inline and structure nodes have some basic implementations. The parser needs to begin next. --- flake.nix | 84 +++++++++++++++++------------------ lib/inlindeNode.h | 17 ------- lib/inlineNode.cpp | 23 ++++++++++ lib/inlineNode.h | 97 ++++++++++++++++++++++++++++++++++++++++ lib/node.h | 1 + lib/structureNode.cpp | 64 ++++++++++++++++++++++++++ lib/structureNode.h | 101 +++++++++++++++++++++++++++++++++++++++--- src/main.cpp | 28 ++++++++++++ 8 files changed, 351 insertions(+), 64 deletions(-) delete mode 100644 lib/inlindeNode.h create mode 100644 lib/inlineNode.h diff --git a/flake.nix b/flake.nix index e544aa4..07909a0 100644 --- a/flake.nix +++ b/flake.nix @@ -1,42 +1,42 @@ -{ - description = "Blank development flake. Adjust as needed"; - - inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; - flake-utils.url = "github:numtide/flake-utils"; - }; - - outputs = { self, nixpkgs, flake-utils, ... }: - flake-utils.lib.eachDefaultSystem (system: - let - pkgs = import nixpkgs { inherit system; }; - in - { - # Define the development shell. - # When you run `nix develop` (or direnv activates), you'll enter this shell. - devShells.default = pkgs.mkShell { - # List all the development tools you need available in this shell's PATH. - packages = with pkgs; [ - gcc - gdb - stdenv - ]; - - # Define the shell that will be executed. - # Here, we explicitly use zsh. - # Note: pkgs.zsh needs to be included in `packages` or `nativeBuildInputs` - # for it to be found in the shell's environment. `inherit pkgs.zsh;` is concise. - inherit (pkgs) zsh; - - # Environment variables and commands to run when the shell starts. - shellHook = '' - # Add any exports, hooks, aliases, or anything else here - - # Exec zsh to replace the current shell process with zsh. - # This ensures your prompt and zsh configurations load correctly. - exec zsh - ''; - }; - } - ); -} +{ + description = "Blank development flake. Adjust as needed"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { self, nixpkgs, flake-utils, ... }: + flake-utils.lib.eachDefaultSystem (system: + let + pkgs = import nixpkgs { inherit system; }; + in + { + # Define the development shell. + # When you run `nix develop` (or direnv activates), you'll enter this shell. + devShells.default = pkgs.mkShell { + # List all the development tools you need available in this shell's PATH. + packages = with pkgs; [ + gcc + gdb + stdenv + ]; + + # Define the shell that will be executed. + # Here, we explicitly use zsh. + # Note: pkgs.zsh needs to be included in `packages` or `nativeBuildInputs` + # for it to be found in the shell's environment. `inherit pkgs.zsh;` is concise. + inherit (pkgs) zsh; + + # Environment variables and commands to run when the shell starts. + shellHook = '' + # Add any exports, hooks, aliases, or anything else here + + # Exec zsh to replace the current shell process with zsh. + # This ensures your prompt and zsh configurations load correctly. + exec zsh + ''; + }; + } + ); +} diff --git a/lib/inlindeNode.h b/lib/inlindeNode.h deleted file mode 100644 index 09e5d13..0000000 --- a/lib/inlindeNode.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef INLINENODE_H -#define INLINENODE_H -#include "node.h" - -class InlineNode : public Node{ - public: - InlineNode(std::string content) : content(content); - protected: - std::string content; -}; - -class TextNode : public InlineNode{}; -class BoldNode : public InlineNode{}; -class Italic : public InlineNode{}; -class BoldItalic : public InlineNode{}; - -#endif diff --git a/lib/inlineNode.cpp b/lib/inlineNode.cpp index e69de29..22b4788 100644 --- a/lib/inlineNode.cpp +++ b/lib/inlineNode.cpp @@ -0,0 +1,23 @@ +#include "inlineNode.h" + +#include +#include +#include + +using std::string; + +void InlineNode::AddChild(std::unique_ptr child) { + throw std::runtime_error("Cannot add a child to an InlineNode."); +} + +string TextNode::ToHtml() const { return this->content; } + +string ItalicNode::ToHtml() const { return "" + this->content + ""; } + +string BoldNode::ToHtml() const { + return "" + this->content + ""; +} + +string BoldItalicNode::ToHtml() const { + return "" + this->content + ""; +} diff --git a/lib/inlineNode.h b/lib/inlineNode.h new file mode 100644 index 0000000..7655afd --- /dev/null +++ b/lib/inlineNode.h @@ -0,0 +1,97 @@ +#ifndef INLINENODE_H +#define INLINENODE_H + +#include "node.h" +#include + +/** + * @desc ABC inline node for textual nodes. + * + * An inline node has content, but no children. An attempt to add children to + * this node will result in a runtime exception. + * Inline nodes define text itself, not textual tags, but the actual text inside + * the tags. + * + * @author Hayden Hargreaves (hhargreaves2006@gmail.com) + */ +class InlineNode : public Node { +public: + InlineNode(std::string content) : content(content) {}; + + /** + * @brief Return node as HTML string. + * + * This method is virtual and required to be overridden. + * + * @author Hayden Hargreaves (hhargreaves2006@gmail.com) + */ + virtual std::string ToHtml() const = 0; + + /** + * @brief Cannot add a child to this class. + * + * This method simply returns a runtime error, since there is no reason to add + * a child to a textual node. + * + * @author Hayden Hargreaves (hhargreaves2006@gmail.com) + */ + void AddChild(std::unique_ptr child); + +protected: + std::string content; +}; + +/** + * @desc A raw textual node. + * + * This node is simple, it simple returns it's content with no formatting. + * + * @author Hayden Hargreaves (hhargreaves2006@gmail.com) + */ +class TextNode : public InlineNode { +public: + TextNode(std::string content) : InlineNode(content) {}; + std::string ToHtml() const; +}; + +/** + * @desc A italic textual node. + * + * This node returns it's content wrapped with tags. + * + * @author Hayden Hargreaves (hhargreaves2006@gmail.com) + */ +class ItalicNode : public InlineNode { +public: + ItalicNode(std::string content) : InlineNode(content) {}; + std::string ToHtml() const; +}; + +/** + * @desc A bold textual node. + * + * This node returns it's content wrapped with tags. + * + * @author Hayden Hargreaves (hhargreaves2006@gmail.com) + */ +class BoldNode : public InlineNode { +public: + BoldNode(std::string content) : InlineNode(content) {}; + std::string ToHtml() const; +}; + +/** + * @desc A bold and italic textual node. + * + * This node returns it's content wrapped with AND / + * tags. + * + * @author Hayden Hargreaves (hhargreaves2006@gmail.com) + */ +class BoldItalicNode : public InlineNode { +public: + BoldItalicNode(std::string content) : InlineNode(content) {}; + std::string ToHtml() const; +}; + +#endif diff --git a/lib/node.h b/lib/node.h index 9ee7023..390b004 100644 --- a/lib/node.h +++ b/lib/node.h @@ -16,6 +16,7 @@ /// method is required. When calling a function that accepts a reference, the /// reference operator (*) works perfectly fine. Hence, in this project we will /// 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 { diff --git a/lib/structureNode.cpp b/lib/structureNode.cpp index 6d4d8f4..55ac4d1 100644 --- a/lib/structureNode.cpp +++ b/lib/structureNode.cpp @@ -1 +1,65 @@ #include "structureNode.h" +#include +#include +#include +#include + +using std::string; + +string DocumentNode::ToHtml() const { + std::stringstream ss; + ss << "\n\t\n\t\t\n\t\t\t\n\t\t\t\n\t\t\tDocument\n\t\t\n\t\n"; + + for (const auto &child : this->GetChilren()) { + ss << child->ToHtml(); + } + + ss << "\n\t\n"; + return ss.str(); +} + +HeadingNode::HeadingNode(int size) { + if (1 <= size && size <= 6) { + this->size = size; + return; + } + + throw std::runtime_error("HeadingNode.size must be between 1 and 6."); +} + +string HeadingNode::ToHtml() const { + std::stringstream ss; + ss << ""; + + for (const auto &child : this->GetChilren()) { + ss << child->ToHtml(); + } + + ss << "\n"; + return ss.str(); +} + +string ParagraphNode::ToHtml() const { + std::stringstream ss; + ss << "

"; + + for (const auto &child : this->GetChilren()) { + ss << child->ToHtml(); + } + + ss << "

\n"; + return ss.str(); +} + +// TODO: Implement +string ListNode::ToHtml() const { + std::stringstream ss; + ss << (this->ordered ? "
    NOT YET IMPLEMENTED
" + : "
    NOT YET IMPLEMENTED
"); + + return ss.str(); +} diff --git a/lib/structureNode.h b/lib/structureNode.h index 576de51..c45feea 100644 --- a/lib/structureNode.h +++ b/lib/structureNode.h @@ -2,12 +2,103 @@ #define STRUCTURENODE_H #include "node.h" +#include -class StructureNode : public Node {}; +/** + * @desc ABC inline node for structure nodes. + * + * A structure node has no content, but instead it has children which contain + * content. These children can be other structure nodes, or they can be inline + * nodes. Inline nodes allow this node to display textual content. + * + * @author Hayden Hargreaves (hhargreaves2006@gmail.com) + */ +class StructureNode : public Node { +public: + /** + * @brief Return node as HTML string. + * + * This method is virtual and required to be overridden. + * + * @author Hayden Hargreaves (hhargreaves2006@gmail.com) + */ + virtual std::string ToHtml() const = 0; +}; -class ListNode : public StructureNode {}; -class HeadingNode : public StructureNode {}; -class DocumentNode : public StructureNode {}; -class ParagraphNode : public StructureNode {}; +/** + * @desc A main HTML document node. + * + * This node should be used as the root of the DOM. Calling `ToHtml` will yield + * an HTML document boiler plate with it's children rendered as the body. + * + * @author Hayden Hargreaves (hhargreaves2006@gmail.com) + */ +class DocumentNode : public StructureNode { +public: + std::string ToHtml() const; +}; + +/** + * @desc A heading node. + * + * A heading contains children that are expected to be inline nodes. These + * children represent the textual content of the node. This heading node simply + * stores the children and the size of the heading. A size of 1 means

, etc. + * + * @author Hayden Hargreaves (hhargreaves2006@gmail.com) + */ +class HeadingNode : public StructureNode { +protected: + /** + * @brief Size of the heading. + * + * The constructor will enforce size requirements. + * + * @author Hayden Hargreaves (hhargreaves2006@gmail.com) + */ + int size; + +public: + HeadingNode(int size); + std::string ToHtml() const; +}; + +/** + * @desc A paragraph node. + * + * A paragraph contains children that are expected to be inline nodes. These + * children represent the textual content of the node. This heading node simply + * stores the children. + * + * @author Hayden Hargreaves (hhargreaves2006@gmail.com) + */ +class ParagraphNode : public StructureNode { +public: + std::string ToHtml() const; +}; + +/** + * @desc A list container node. + * + * This node is used to wrap list elements. Not to be confused with the list + * elements themselves. This is the parent (
    or
      ), and must be created + * with a boolean which defines whether the list should be ordered or not. + * i.e., should have numbers (use the
        tags). + * + * @author Hayden Hargreaves (hhargreaves2006@gmail.com) + */ +class ListNode : public StructureNode { +protected: + /** + * @brief Should the list be ordered (numeric). + * + * @author Hayden Hargreaves (hhargreaves2006@gmail.com) + */ + bool ordered; + +public: + ListNode(bool ordered = false) : ordered(ordered) {}; + std::string ToHtml() const; +}; #endif diff --git a/src/main.cpp b/src/main.cpp index 2cfd5eb..f4f54ae 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,8 @@ +#include "../lib/inlineNode.h" #include "../lib/parser.h" +#include "../lib/structureNode.h" + +#include #include int main(int argc, char **argv) { @@ -23,5 +27,29 @@ int main(int argc, char **argv) { std::cout << std::endl; + DocumentNode root; + std::unique_ptr node = std::make_unique("text node"); + std::unique_ptr bold = std::make_unique("bold node"); + std::unique_ptr italic = + std::make_unique("italic node"); + std::unique_ptr bolditalic = + std::make_unique("bold italic node"); + + std::unique_ptr heading = std::make_unique(2); + heading->AddChild(std::move(node)); + heading->AddChild(std::move(bold)); + + std::unique_ptr para = std::make_unique(); + para->AddChild(std::move(italic)); + para->AddChild(std::move(bolditalic)); + + std::unique_ptr list = std::make_unique(); + + root.AddChild(std::move(heading)); + root.AddChild(std::move(para)); + root.AddChild(std::move(list)); + + std::cout << root.ToHtml() << std::endl; + return 0; }