(FEAT): Working on node implementation.

The inline and structure nodes have some basic implementations. The
parser needs to begin next.
This commit is contained in:
Hayden Hargreaves 2025-10-16 12:08:58 -07:00
parent 4b973abf6c
commit 14d5eee237
8 changed files with 351 additions and 64 deletions

View File

@ -1,42 +1,42 @@
{ {
description = "Blank development flake. Adjust as needed"; description = "Blank development flake. Adjust as needed";
inputs = { inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils"; flake-utils.url = "github:numtide/flake-utils";
}; };
outputs = { self, nixpkgs, flake-utils, ... }: outputs = { self, nixpkgs, flake-utils, ... }:
flake-utils.lib.eachDefaultSystem (system: flake-utils.lib.eachDefaultSystem (system:
let let
pkgs = import nixpkgs { inherit system; }; pkgs = import nixpkgs { inherit system; };
in in
{ {
# Define the development shell. # Define the development shell.
# When you run `nix develop` (or direnv activates), you'll enter this shell. # When you run `nix develop` (or direnv activates), you'll enter this shell.
devShells.default = pkgs.mkShell { devShells.default = pkgs.mkShell {
# List all the development tools you need available in this shell's PATH. # List all the development tools you need available in this shell's PATH.
packages = with pkgs; [ packages = with pkgs; [
gcc gcc
gdb gdb
stdenv stdenv
]; ];
# Define the shell that will be executed. # Define the shell that will be executed.
# Here, we explicitly use zsh. # Here, we explicitly use zsh.
# Note: pkgs.zsh needs to be included in `packages` or `nativeBuildInputs` # 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. # for it to be found in the shell's environment. `inherit pkgs.zsh;` is concise.
inherit (pkgs) zsh; inherit (pkgs) zsh;
# Environment variables and commands to run when the shell starts. # Environment variables and commands to run when the shell starts.
shellHook = '' shellHook = ''
# Add any exports, hooks, aliases, or anything else here # Add any exports, hooks, aliases, or anything else here
# Exec zsh to replace the current shell process with zsh. # Exec zsh to replace the current shell process with zsh.
# This ensures your prompt and zsh configurations load correctly. # This ensures your prompt and zsh configurations load correctly.
exec zsh exec zsh
''; '';
}; };
} }
); );
} }

View File

@ -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

View File

@ -0,0 +1,23 @@
#include "inlineNode.h"
#include <memory>
#include <stdexcept>
#include <string>
using std::string;
void InlineNode::AddChild(std::unique_ptr<Node> child) {
throw std::runtime_error("Cannot add a child to an InlineNode.");
}
string TextNode::ToHtml() const { return this->content; }
string ItalicNode::ToHtml() const { return "<em>" + this->content + "</em>"; }
string BoldNode::ToHtml() const {
return "<strong>" + this->content + "</strong>";
}
string BoldItalicNode::ToHtml() const {
return "<strong><em>" + this->content + "</em></strong>";
}

97
lib/inlineNode.h Normal file
View File

@ -0,0 +1,97 @@
#ifndef INLINENODE_H
#define INLINENODE_H
#include "node.h"
#include <vector>
/**
* @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<Node> 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 <em></em> 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 <strong></strong> 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 <strong></strong> AND <em>/<em>
* tags.
*
* @author Hayden Hargreaves (hhargreaves2006@gmail.com)
*/
class BoldItalicNode : public InlineNode {
public:
BoldItalicNode(std::string content) : InlineNode(content) {};
std::string ToHtml() const;
};
#endif

View File

@ -16,6 +16,7 @@
/// method is required. When calling a function that accepts a reference, the /// method is required. When calling a function that accepts a reference, the
/// reference operator (*) works perfectly fine. Hence, in this project we will /// reference operator (*) works perfectly fine. Hence, in this project we will
/// try to avoid using raw pointers, and only use references when needed. /// try to avoid using raw pointers, and only use references when needed.
/// Reference: https://www.youtube.com/watch?v=AmjoK55h68Y&t=166s
// NOTE ABC // NOTE ABC
class Node { class Node {

View File

@ -1 +1,65 @@
#include "structureNode.h" #include "structureNode.h"
#include <cstdio>
#include <sstream>
#include <stdexcept>
#include <string>
using std::string;
string DocumentNode::ToHtml() const {
std::stringstream ss;
ss << "<!DOCTYPE html>\n\t<html lang=\"en\">\n\t\t<head>\n\t\t\t<meta "
"charset=\"UTF-8\">\n\t\t\t<meta "
"name=\"viewport\" content=\"width=device-width, "
"initial-scale=1.0\">\n\t\t\t<title>Document</title>\n\t\t</"
"head>\n\t<body>\n";
for (const auto &child : this->GetChilren()) {
ss << child->ToHtml();
}
ss << "\n\t</body>\n</html>";
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 << "<h" << size << ">";
for (const auto &child : this->GetChilren()) {
ss << child->ToHtml();
}
ss << "</h" << size << ">\n";
return ss.str();
}
string ParagraphNode::ToHtml() const {
std::stringstream ss;
ss << "<p>";
for (const auto &child : this->GetChilren()) {
ss << child->ToHtml();
}
ss << "</p>\n";
return ss.str();
}
// TODO: Implement
string ListNode::ToHtml() const {
std::stringstream ss;
ss << (this->ordered ? "<ol>NOT YET IMPLEMENTED</ol>"
: "<ul>NOT YET IMPLEMENTED</ul>");
return ss.str();
}

View File

@ -2,12 +2,103 @@
#define STRUCTURENODE_H #define STRUCTURENODE_H
#include "node.h" #include "node.h"
#include <string>
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 {}; * @desc A main HTML document node.
class DocumentNode : public StructureNode {}; *
class ParagraphNode : public StructureNode {}; * 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 <h1>, 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 (<ul> or <ol>), and must be created
* with a boolean which defines whether the list should be ordered or not.
* i.e., should have numbers (use the <ol> 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 #endif

View File

@ -1,4 +1,8 @@
#include "../lib/inlineNode.h"
#include "../lib/parser.h" #include "../lib/parser.h"
#include "../lib/structureNode.h"
#include <memory>
#include <stdexcept> #include <stdexcept>
int main(int argc, char **argv) { int main(int argc, char **argv) {
@ -23,5 +27,29 @@ int main(int argc, char **argv) {
std::cout << std::endl; std::cout << std::endl;
DocumentNode root;
std::unique_ptr<TextNode> node = std::make_unique<TextNode>("text node");
std::unique_ptr<BoldNode> bold = std::make_unique<BoldNode>("bold node");
std::unique_ptr<ItalicNode> italic =
std::make_unique<ItalicNode>("italic node");
std::unique_ptr<BoldItalicNode> bolditalic =
std::make_unique<BoldItalicNode>("bold italic node");
std::unique_ptr<HeadingNode> heading = std::make_unique<HeadingNode>(2);
heading->AddChild(std::move(node));
heading->AddChild(std::move(bold));
std::unique_ptr<ParagraphNode> para = std::make_unique<ParagraphNode>();
para->AddChild(std::move(italic));
para->AddChild(std::move(bolditalic));
std::unique_ptr<ListNode> list = std::make_unique<ListNode>();
root.AddChild(std::move(heading));
root.AddChild(std::move(para));
root.AddChild(std::move(list));
std::cout << root.ToHtml() << std::endl;
return 0; return 0;
} }