(FEAT) Abstracted file system into its own class.
This class is then composed into the parser class and called to write the expected outputs. This is a huge step towards the final product. Furthermore, the output it being written to the file generated. Until the CLI is implemented, this is the best it will do.
This commit is contained in:
parent
cf3b57c8e4
commit
7587e493d7
8
Makefile
8
Makefile
@ -1,6 +1,6 @@
|
|||||||
# Define the C++ compiler and flags
|
# Define the C++ compiler and flags
|
||||||
CXX = g++
|
CXX = g++
|
||||||
CXXFLAGS = -Wall -g
|
CXXFLAGS = -Wall -g -fPIE
|
||||||
|
|
||||||
# Directories
|
# Directories
|
||||||
BUILD_DIR = build
|
BUILD_DIR = build
|
||||||
@ -29,15 +29,15 @@ $(BUILD_DIR):
|
|||||||
mkdir -p $(BUILD_DIR)
|
mkdir -p $(BUILD_DIR)
|
||||||
|
|
||||||
$(TARGET): $(OBJECTS)
|
$(TARGET): $(OBJECTS)
|
||||||
$(CXX) $(CXXFLAGS) $(INCLUDES) $^ -o $@
|
$(CXX) $(CXXFLAGS) $(INCLUDES) $^ -o $@ -pie
|
||||||
|
|
||||||
# Generic rule for all .cpp files in the src/ directory
|
# Generic rule for all .cpp files in the src/ directory
|
||||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.cpp
|
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.cpp
|
||||||
$(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@
|
$(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@ -pie
|
||||||
|
|
||||||
# Generic rule for all .cpp files in the lib/ directory
|
# Generic rule for all .cpp files in the lib/ directory
|
||||||
$(BUILD_DIR)/%.o: $(LIB_DIR)/%.cpp
|
$(BUILD_DIR)/%.o: $(LIB_DIR)/%.cpp
|
||||||
$(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@
|
$(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@ -pie
|
||||||
|
|
||||||
test: all
|
test: all
|
||||||
./$(TARGET)
|
./$(TARGET)
|
||||||
|
|||||||
62
lib/fileSystem.cpp
Normal file
62
lib/fileSystem.cpp
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
#include "fileSystem.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
FileSystem::FileSystem(string input_file_path, string output_file_path) {
|
||||||
|
removeWhitespace(input_file_path);
|
||||||
|
removeWhitespace(output_file_path);
|
||||||
|
|
||||||
|
if (input_file_path.empty())
|
||||||
|
throw std::runtime_error("input_file_path cannot be empty");
|
||||||
|
|
||||||
|
this->input_file_path = input_file_path;
|
||||||
|
|
||||||
|
this->output_file_path = output_file_path;
|
||||||
|
if (this->output_file_path.empty())
|
||||||
|
GenerateOutputFilePath();
|
||||||
|
};
|
||||||
|
|
||||||
|
void FileSystem::GenerateOutputFilePath() {
|
||||||
|
if (this->input_file_path.empty())
|
||||||
|
throw std::runtime_error("Cannot generate output path from empty input.");
|
||||||
|
|
||||||
|
int ext_idx = this->input_file_path.find_last_of('.');
|
||||||
|
string output_cleaned = this->input_file_path.substr(0, ext_idx) + ".html";
|
||||||
|
this->output_file_path = output_cleaned;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string FileSystem::ReadInputFile() {
|
||||||
|
// Cannot read file if the path does not exist
|
||||||
|
if (this->input_file_path.empty())
|
||||||
|
throw std::runtime_error("Cannot open file: path was not provided.");
|
||||||
|
|
||||||
|
std::ifstream input_file(this->input_file_path);
|
||||||
|
|
||||||
|
if (!input_file.is_open())
|
||||||
|
throw std::runtime_error("Failed to open input file.");
|
||||||
|
|
||||||
|
// Read the file into a single string using a string stream
|
||||||
|
std::stringstream buffer;
|
||||||
|
buffer << input_file.rdbuf();
|
||||||
|
input_file.close();
|
||||||
|
|
||||||
|
return buffer.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSystem::WriteOutputFile(std::string content) {
|
||||||
|
// Cannot write to file if the path does not exist
|
||||||
|
if (this->output_file_path.empty())
|
||||||
|
throw std::runtime_error("Cannot open file: path was not provided.");
|
||||||
|
|
||||||
|
std::ofstream output_file(this->output_file_path);
|
||||||
|
|
||||||
|
if (!output_file.is_open())
|
||||||
|
throw std::runtime_error("Failed to open output file.");
|
||||||
|
|
||||||
|
output_file << content;
|
||||||
|
output_file.close();
|
||||||
|
}
|
||||||
71
lib/fileSystem.h
Normal file
71
lib/fileSystem.h
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#ifndef FILESYSTEM_H
|
||||||
|
#define FILESYSTEM_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
class FileSystem {
|
||||||
|
public:
|
||||||
|
FileSystem(string input_file_path, string output_file_path = "");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read the input file and return its content.
|
||||||
|
*
|
||||||
|
* This method will read the file at the input_file_path and create a single
|
||||||
|
* output string. Each line will be delimited by either `\n` (Unix) or `\r\n`
|
||||||
|
* (Windows). If the file path does not exist OR the file fails to open, this
|
||||||
|
* method will throw a run time error.
|
||||||
|
*
|
||||||
|
* @return File contents as a single string.
|
||||||
|
*
|
||||||
|
* @author Hayden Hargreaves (hhargreaves2006@gmail.com)
|
||||||
|
*/
|
||||||
|
string ReadInputFile();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write the provided string to the output file.
|
||||||
|
*
|
||||||
|
* This method will attempt to open the output file and write the content
|
||||||
|
* provided to the method in the file. If the file does not exist, it will be
|
||||||
|
* created. If the file path does not exist OR the file fails to open, this
|
||||||
|
* method will throw a run time error.
|
||||||
|
*
|
||||||
|
* @author Hayden Hargreaves (hhargreaves2006@gmail.com)
|
||||||
|
*/
|
||||||
|
void WriteOutputFile(string content);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* @brief Input file path.
|
||||||
|
*
|
||||||
|
* Must be provided by the user.
|
||||||
|
*
|
||||||
|
* @author Hayden Hargreaves (hhargreaves2006@gmail.com)
|
||||||
|
*/
|
||||||
|
string input_file_path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Output file path.
|
||||||
|
*
|
||||||
|
* If not provided, will be generated using the `input_file_path` by removing
|
||||||
|
* the extension and appending `.html`.
|
||||||
|
*
|
||||||
|
* @author Hayden Hargreaves (hhargreaves2006@gmail.com)
|
||||||
|
*/
|
||||||
|
string output_file_path;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* @brief Generate an output file path.
|
||||||
|
*
|
||||||
|
* If the user does not provide an output file path, this method can be
|
||||||
|
* used to generate the path. This is done by simply swapping the `.md`
|
||||||
|
* with `.html`.
|
||||||
|
*
|
||||||
|
* @author Hayden Hargreaves (hhargreaves2006@gmail.com)
|
||||||
|
*/
|
||||||
|
void GenerateOutputFilePath();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -1,49 +1,19 @@
|
|||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
#include "fileSystem.h"
|
||||||
#include "inlineNode.h"
|
#include "inlineNode.h"
|
||||||
#include "structureNode.h"
|
#include "structureNode.h"
|
||||||
#include "util.h"
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <fstream>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <sstream>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
|
|
||||||
Parser::Parser(string input_file_path, string output_file_path) {
|
|
||||||
// NOTE: Remove any white space AROUND the inputs
|
|
||||||
removeWhitespace(input_file_path);
|
|
||||||
removeWhitespace(output_file_path);
|
|
||||||
|
|
||||||
if (input_file_path == "") {
|
|
||||||
throw std::runtime_error("input_file_path cannot be empty");
|
|
||||||
}
|
|
||||||
|
|
||||||
this->input_file_path = input_file_path;
|
|
||||||
|
|
||||||
// NOTE: If the user does not provide an output file, then we should construct
|
|
||||||
// one using the input file with .md swapped with the extension.
|
|
||||||
if (output_file_path == "") {
|
|
||||||
int ext_idx = input_file_path.find_last_of('.');
|
|
||||||
string output_cleaned = input_file_path.substr(0, ext_idx) + ".html";
|
|
||||||
this->output_file_path = output_cleaned;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->output_file_path = output_file_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Parser::Inspect() {
|
void Parser::Inspect() {
|
||||||
std::cout << "std::string input_file_path: " << this->input_file_path
|
std::cerr << "Parser::Inspect() is not yet implemented." << std::endl;
|
||||||
<< std::endl;
|
|
||||||
std::cout << "std::string output_file_path: " << this->output_file_path
|
|
||||||
<< std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// replace '\r\n' with '\n'
|
|
||||||
void Parser::NormalizeInputStream() {
|
void Parser::NormalizeInputStream() {
|
||||||
if (this->content.empty())
|
if (this->content.empty())
|
||||||
return;
|
return;
|
||||||
@ -60,22 +30,23 @@ void Parser::NormalizeInputStream() {
|
|||||||
this->content.end());
|
this->content.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Parser::ParseDocument() {
|
void Parser::WriteOutput() {
|
||||||
// Open the input file
|
if (this->DOM == nullptr)
|
||||||
std::ifstream input_file(this->input_file_path);
|
throw std::runtime_error(
|
||||||
|
"Cannot write output, output DOM tree does not exist. Please run the "
|
||||||
|
"Parser::ParserDocument method first.");
|
||||||
|
|
||||||
if (!input_file.is_open()) {
|
this->filesystem.WriteOutputFile(this->DOM->ToHtml());
|
||||||
throw std::runtime_error("Failed to open input file.");
|
}
|
||||||
|
|
||||||
|
void Parser::ParseDocument() {
|
||||||
|
try {
|
||||||
|
this->content = this->filesystem.ReadInputFile();
|
||||||
|
} catch (const std::runtime_error &e) {
|
||||||
|
std::cerr << "Caught an error: " << e.what() << std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the file into a single string
|
|
||||||
std::stringstream buffer;
|
|
||||||
buffer << input_file.rdbuf();
|
|
||||||
this->content = buffer.str();
|
|
||||||
|
|
||||||
input_file.close();
|
|
||||||
|
|
||||||
// Remove the windows BS
|
// Remove the windows BS
|
||||||
NormalizeInputStream();
|
NormalizeInputStream();
|
||||||
|
|
||||||
@ -88,8 +59,6 @@ void Parser::ParseDocument() {
|
|||||||
if (block != nullptr)
|
if (block != nullptr)
|
||||||
this->DOM->AddChild(std::move(block));
|
this->DOM->AddChild(std::move(block));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << this->DOM->ToHtml();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// All this does is pick which subparser to call
|
// All this does is pick which subparser to call
|
||||||
|
|||||||
45
lib/parser.h
45
lib/parser.h
@ -1,6 +1,7 @@
|
|||||||
#ifndef PARSER_H
|
#ifndef PARSER_H
|
||||||
#define PARSER_H
|
#define PARSER_H
|
||||||
|
|
||||||
|
#include "fileSystem.h"
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -25,7 +26,8 @@ using std::vector;
|
|||||||
*/
|
*/
|
||||||
class Parser {
|
class Parser {
|
||||||
public:
|
public:
|
||||||
Parser(string input_file_path, string output_file_path = "");
|
Parser(string input_file_path, string output_file_path = "")
|
||||||
|
: filesystem(input_file_path, output_file_path) {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Inspect (view) contents of the class.
|
* @brief Inspect (view) contents of the class.
|
||||||
@ -37,7 +39,6 @@ public:
|
|||||||
void Inspect();
|
void Inspect();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @brief Parse an entire document.
|
* @brief Parse an entire document.
|
||||||
*
|
*
|
||||||
* This function will be called to yield the result. This is the entry point
|
* This function will be called to yield the result. This is the entry point
|
||||||
@ -53,25 +54,27 @@ public:
|
|||||||
*/
|
*/
|
||||||
void ParseDocument();
|
void ParseDocument();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write the output to the file.
|
||||||
|
*
|
||||||
|
* Once the tree is generated, this method should be called to actually
|
||||||
|
* write the output. Having this functionality separate allows for more
|
||||||
|
* portability.
|
||||||
|
*
|
||||||
|
* @author Hayden Hargreaves (hhargreaves2006@gmail.com)
|
||||||
|
*/
|
||||||
|
void WriteOutput();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* @brief Input file path.
|
* @brief File system module to handle file I/O.
|
||||||
|
*
|
||||||
|
* Anything requiring file I/O operations will be handled by this module.
|
||||||
*
|
*
|
||||||
* Must be provided by the user.
|
|
||||||
*
|
*
|
||||||
* @author Hayden Hargreaves (hhargreaves2006@gmail.com)
|
* @author Hayden Hargreaves (hhargreaves2006@gmail.com)
|
||||||
*/
|
*/
|
||||||
string input_file_path;
|
FileSystem filesystem;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Output file path.
|
|
||||||
*
|
|
||||||
* If not provided, will be generated using the `input_file_path` by removing
|
|
||||||
* the extension and appending `.html`.
|
|
||||||
*
|
|
||||||
* @author Hayden Hargreaves (hhargreaves2006@gmail.com)
|
|
||||||
*/
|
|
||||||
string output_file_path;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Parser generated tree.
|
* @brief Parser generated tree.
|
||||||
@ -88,7 +91,15 @@ protected:
|
|||||||
// std::stack<any> stack;
|
// std::stack<any> stack;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// windows... >:(
|
/**
|
||||||
|
* @brief Normalize the input stream.
|
||||||
|
*
|
||||||
|
* Replaces all `\r\n` with just `\n` since that is what the parser expects.
|
||||||
|
* Then removes any left over `\r` elements in the stream. If the stream is
|
||||||
|
* empty this method does nothing.
|
||||||
|
*
|
||||||
|
* @author Hayden Hargreaves (hhargreaves2006@gmail.com)
|
||||||
|
*/
|
||||||
void NormalizeInputStream();
|
void NormalizeInputStream();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -97,7 +108,7 @@ private:
|
|||||||
* How does this function work...
|
* How does this function work...
|
||||||
* This is where the magic happens.
|
* This is where the magic happens.
|
||||||
*
|
*
|
||||||
* @return DOMNode, once exists
|
* @return Node, to be appended to the callers children.
|
||||||
*
|
*
|
||||||
* @author Hayden Hargreaves (hhargreaves2006@gmail.com)
|
* @author Hayden Hargreaves (hhargreaves2006@gmail.com)
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -79,9 +79,10 @@ void test_input(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
Parser p("input.md");
|
Parser p("syntax.md");
|
||||||
p.ParseDocument();
|
p.ParseDocument();
|
||||||
|
p.WriteOutput();
|
||||||
|
|
||||||
Parser p2("README.md");
|
// Parser p2("README.md");
|
||||||
p2.ParseDocument();
|
// p2.ParseDocument();
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user