Skip to content

Instantly share code, notes, and snippets.

@zdne
Created April 30, 2014 09:43
Show Gist options
  • Save zdne/55b7a38f52ca642e123b to your computer and use it in GitHub Desktop.
Save zdne/55b7a38f52ca642e123b to your computer and use it in GitHub Desktop.
New API Blueprint parser structure
#include <string>
#include <vector>
#include <regex>
enum MarkdownNodeType {
RootMarkdownNodeType = 0,
HeaderMarkdownNodeType,
ListItemMarkdownNodeType,
ParagraphMarkdownNodeType,
UndefinedMarkdownNodeType = -1
};
struct MarkdownNode {
MarkdownNodeType type;
std::string text;
std::vector<MarkdownNode> children;
};
struct Resource {
std::string name;
std::string description;
};
struct Parameter {
std::string name;
std::string description;
std::vector<Parameter> nested; // Illegal!
};
struct Parameters {
std::string description;
std::vector<Parameter> parametes;
};
struct Blueprint {
std::string name;
std::string description;
std::vector<Resource> resources;
Parameters parameters;
};
enum SectionType {
BlueprintSectionType = 0,
ResoureSectionType,
ParametersSectionType,
ParameterSectionType,
UndefinedSectionType = -1
};
typedef int Result;
typedef std::vector<MarkdownNode> Nodes;
typedef std::vector<MarkdownNode>::const_iterator NodeIterator;
// Forward declarations;
bool recognize_signature(const NodeIterator& node);
template<typename T>
struct Processor;
//----
template<typename T>
struct ProcessorBase {
static NodeIterator process_signature(const NodeIterator& node, T& out) {
return ++NodeIterator(node);
}
static NodeIterator process_description(const NodeIterator& node, T& out) {
out.description += node->text;
return ++NodeIterator(node);
}
static NodeIterator process_content(const NodeIterator& node, T& out) {
return ++NodeIterator(node);
}
static NodeIterator process_nested_section(const NodeIterator& node,
const Nodes& siblings,
SectionType& type,
T& out) {
return node;
}
static NodeIterator process_unexpected_node(const NodeIterator& node,
const Nodes& siblings,
T& out) {
return ++NodeIterator(node);
}
static bool is_description_node(const NodeIterator& node) {
return !Processor<T>::is_content_node(node) &&
Processor<T>::nested_section_node(node) == UndefinedSectionType &&
!recognize_signature(node);
}
static bool is_content_node(const NodeIterator& node) {
return false;
}
static bool is_unexpected_node(const NodeIterator& node) {
return !recognize_signature(node);
}
static SectionType nested_section_node(const NodeIterator& node) {
return UndefinedSectionType;
}
static SectionType defines_section(const NodeIterator& node) {
return UndefinedSectionType;
}
};
template<typename T>
struct Processor : public ProcessorBase<T> {
};
//----
struct HeaderSectionAdapter {
static const NodeIterator working_node(const NodeIterator& seed) {
return seed;
}
static const Nodes& working_node_collection(const NodeIterator& seed, const Nodes& siblings) {
return siblings;
}
static const NodeIterator seed_node(const NodeIterator& seed, const Nodes& siblings, const NodeIterator& cur) {
return cur;
}
};
struct ListSectionAdapter {
static const NodeIterator working_node(const NodeIterator& seed) {
return seed->children.begin();
}
static const Nodes& working_node_collection(const NodeIterator& seed, const Nodes& siblings) {
return seed->children;
}
static const NodeIterator seed_node(const NodeIterator& seed, const Nodes& siblings, const NodeIterator& cur) {
if (seed == siblings.end())
return seed;
return ++NodeIterator(seed);
}
};
template<typename T, typename Adapter>
struct SectionParser {
static NodeIterator parse(const NodeIterator& node, const Nodes& siblings, T& out) {
NodeIterator cur = Adapter::working_node(node);
const Nodes& collection = Adapter::working_node_collection(node, siblings);
NodeIterator lastCur = cur;
cur = Processor<T>::process_signature(cur, out);
if (lastCur == cur)
return Adapter::seed_node(node, siblings, cur);
// Description nodes
while(cur != collection.end() &&
Processor<T>::is_description_node(cur)) {
lastCur = cur;
cur = Processor<T>::process_description(cur, out);
if (lastCur == cur)
return Adapter::seed_node(node, siblings, cur);;
}
// Content nodes
while(cur != collection.end() &&
Processor<T>::is_content_node(cur)) {
lastCur = cur;
cur = Processor<T>::process_content(cur, out);
if (lastCur == cur)
return Adapter::seed_node(node, siblings, cur);;
}
// Nested sections
while(cur != collection.end()) {
lastCur = cur;
SectionType nested_type = Processor<T>::nested_section_node(cur);
if (nested_type != UndefinedSectionType) {
cur = Processor<T>::process_nested_section(cur, collection, nested_type, out);
}
else if (Processor<T>::is_unexpected_node(cur)) {
cur = Processor<T>::process_unexpected_node(cur, collection, out);
}
if (lastCur == cur)
break;
}
return Adapter::seed_node(node, siblings, cur);
}
};
//------------------
template<>
struct Processor<Resource> : public ProcessorBase<Resource> {
static SectionType defines_section(const NodeIterator& node) {
if (node->type == HeaderMarkdownNodeType) {
std::regex pattern("^Resource", std::regex_constants::extended);
if (std::regex_search(node->text, pattern))
return ResoureSectionType;
}
return UndefinedSectionType;
}
};
typedef SectionParser<Resource, HeaderSectionAdapter> ResourceParser;
//------------------
template<>
struct Processor<Parameter> : public ProcessorBase<Parameter> {
static NodeIterator process_nested_section(const NodeIterator& node,
const Nodes& siblings,
SectionType type,
Parameter& out) {
NodeIterator cur = node;
switch (type) {
case ParameterSectionType:
{
Parameter param;
cur = SectionParser<Parameter, ListSectionAdapter>::parse(cur, siblings, param);
out.nested.emplace_back(param);
}
break;
default:
break;
}
return cur;
}
static SectionType nested_section_node(const NodeIterator& node) {
return Processor<Parameter>::defines_section(node);
}
static SectionType defines_section(const NodeIterator& node) {
if (node->type == ListItemMarkdownNodeType
&& !node->children.empty()) {
std::regex pattern("^`.+`$", std::regex_constants::extended);
if (std::regex_search(node->children.front().text, pattern))
return ParameterSectionType;
}
return UndefinedSectionType;
}
};
typedef SectionParser<Parameter, ListSectionAdapter> ParameterParser;
//------------------
template<>
struct Processor<Parameters> : public ProcessorBase <Parameters> {
static NodeIterator process_nested_section(const NodeIterator& node,
const Nodes& siblings,
SectionType type,
Parameters& out) {
NodeIterator cur = node;
switch (type) {
case ParameterSectionType:
{
Parameter param;
cur = ParameterParser::parse(cur, siblings, param);
out.parametes.emplace_back(param);
}
break;
default:
break;
}
return cur;
}
static SectionType nested_section_node(const NodeIterator& node) {
return Processor<Parameter>::defines_section(node);
}
static SectionType defines_section(const NodeIterator& node) {
if (node->type == ListItemMarkdownNodeType
&& !node->children.empty()) {
std::regex pattern("^Parameters$", std::regex_constants::extended);
if (std::regex_search(node->children.front().text, pattern))
return ParametersSectionType;
}
return UndefinedSectionType;
}
};
typedef SectionParser<Parameters, ListSectionAdapter> ParametersParser;
//------------------
template<>
struct Processor<Blueprint> : public ProcessorBase <Blueprint> {
static NodeIterator process_nested_section(const NodeIterator& node,
const Nodes& siblings,
SectionType type,
Blueprint& out) {
NodeIterator cur = node;
switch (type) {
case ResoureSectionType:
{
Resource resource;
cur = ResourceParser::parse(cur, siblings, resource);
out.resources.push_back(resource);
}
break;
case ParametersSectionType:
{
cur = ParametersParser::parse(cur, siblings, out.parameters);
}
break;
default:
break;
}
return cur;
}
static SectionType nested_section_node(const NodeIterator& node) {
SectionType type = Processor<Resource>::defines_section(node);
if (type != UndefinedSectionType)
return type;
type = Processor<Parameters>::defines_section(node);
return type;
}
};
typedef SectionParser<Blueprint, HeaderSectionAdapter > BlueprintParser;
//------------------
bool recognize_signature(const NodeIterator& node)
{
return Processor<Resource>::defines_section(node) != UndefinedSectionType ||
Processor<Parameters>::defines_section(node) != UndefinedSectionType;
}
//------------------
int main()
{
MarkdownNode root = {RootMarkdownNodeType};
root.children.emplace_back(MarkdownNode{HeaderMarkdownNodeType, "My API" });
root.children.emplace_back(MarkdownNode{ParagraphMarkdownNodeType, "Description first paragraph" });
root.children.emplace_back(MarkdownNode{ParagraphMarkdownNodeType, "Description second paragraph" });
root.children.emplace_back(MarkdownNode{HeaderMarkdownNodeType, "Resource A" });
root.children.emplace_back(MarkdownNode{ParagraphMarkdownNodeType, "Resource A description" });
root.children.emplace_back(MarkdownNode{HeaderMarkdownNodeType, "Resource B" });
root.children.emplace_back(MarkdownNode{ParagraphMarkdownNodeType, "Resource B description" });
root.children.emplace_back(MarkdownNode{ListItemMarkdownNodeType});
root.children.back().children.emplace_back(MarkdownNode{ParagraphMarkdownNodeType, "Parameters" });
root.children.back().children.emplace_back(MarkdownNode{ListItemMarkdownNodeType});
root.children.back().children.back().children.emplace_back(MarkdownNode{ParagraphMarkdownNodeType, "`A`"});
root.children.back().children.back().children.emplace_back(MarkdownNode{ParagraphMarkdownNodeType, "Param A description"});
root.children.back().children.emplace_back(MarkdownNode{ParagraphMarkdownNodeType, "BLBOST"});
root.children.back().children.emplace_back(MarkdownNode{ListItemMarkdownNodeType});
root.children.back().children.back().children.emplace_back(MarkdownNode{ParagraphMarkdownNodeType, "`B`"});
root.children.back().children.back().children.emplace_back(MarkdownNode{ParagraphMarkdownNodeType, "Param B description"});
root.children.back().children.back().children.emplace_back(MarkdownNode{ListItemMarkdownNodeType});
root.children.back().children.back().children.back().children.emplace_back(MarkdownNode{ParagraphMarkdownNodeType, "`C`"});
root.children.back().children.back().children.back().children.emplace_back(MarkdownNode{ParagraphMarkdownNodeType, "Param `C` description"});
root.children.emplace_back(MarkdownNode{HeaderMarkdownNodeType, "Resource C" });
root.children.emplace_back(MarkdownNode{ParagraphMarkdownNodeType, "Resource C description" });
Blueprint out;
BlueprintParser::parse(root.children.begin(), root.children, out);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment