Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 18 additions & 11 deletions src/ast.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,22 @@

namespace almo {

namespace detail {

inline void collect_nodes_byclass(
const ASTNode& node, const std::string& classname,
std::vector<std::shared_ptr<ASTNode>>& out) {
if (node.get_classname() == classname) {
out.push_back(const_cast<ASTNode&>(node).shared_from_this());
}

for (const auto& child : node.childs) {
collect_nodes_byclass(*child, classname, out);
}
}

} // namespace detail

struct uuid_gen_ {
int operator()() {
static int uuid = 0;
Expand Down Expand Up @@ -120,16 +136,7 @@ std::vector<std::shared_ptr<ASTNode>> ASTNode::get_childs() const {
std::vector<std::shared_ptr<ASTNode>> ASTNode::nodes_byclass(
const std::string &classname) const {
std::vector<std::shared_ptr<ASTNode>> ret;
if (get_classname() == classname) {
ret.push_back(const_cast<ASTNode *>(this)->shared_from_this());
}
for (auto child : childs) {
std::vector<std::shared_ptr<ASTNode>> childs_ret =
child->nodes_byclass(classname);
for (auto child_ret : childs_ret) {
ret.push_back(child_ret);
}
}
detail::collect_nodes_byclass(*this, classname, ret);
return ret;
}

Expand All @@ -139,4 +146,4 @@ void ASTNode::move_node(std::shared_ptr<ASTNode> node,
new_parent->pushback_child(node);
}

} // namespace almo
} // namespace almo
9 changes: 5 additions & 4 deletions src/interfaces/parse.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <string>
#include <string_view>
#include "../reader.hpp"
#include "ast.hpp"

Expand All @@ -9,12 +10,12 @@ namespace almo {
// parse a line contain only inline syntax
struct InlineParser {
template<class Syntax>
static void process_inline(const std::string &str, ASTNode &ast, Syntax&& syn, int pos);
static void process_inline(std::string_view str, ASTNode &ast, Syntax&& syn, int pos);

template<class Syntax, class HeadSyntax, class... TailSyntax>
static void process_inline(const std::string &str, ASTNode &ast, Syntax&& syn, int pos, HeadSyntax&& hsyn, TailSyntax&&... tsyn);
static void process_inline(std::string_view str, ASTNode &ast, Syntax&& syn, int pos, HeadSyntax&& hsyn, TailSyntax&&... tsyn);

static void process(const std::string &str, ASTNode &ast);
static void process(std::string_view str, ASTNode &ast);
};

// parse an entire markdown and detect block syntax
Expand All @@ -30,4 +31,4 @@ struct MarkdownParser {
void process(ASTNode &ast);
};

} // namespace almo
} // namespace almo
10 changes: 5 additions & 5 deletions src/interfaces/syntax.hpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#pragma once

#include <limits>
#include "../reader.hpp"
#include "ast.hpp"
#include <regex>
#include <limits>
#include <string_view>

namespace almo {

Expand All @@ -25,11 +25,11 @@ struct InlineSyntax {
// ---> substring located at [2,7) detected : '$c+d$'
// ---> return 2
// ( ---> captured substring is located at [3,6) : 'c+d' )
virtual int operator()(const std::string &str) const = 0;
virtual int operator()(std::string_view str) const = 0;

// update read and ast
// assume that the string matches as the syntax
virtual void operator()(const std::string &str, ASTNode &ast) const = 0;
virtual void operator()(std::string_view str, ASTNode &ast) const = 0;
};

} // namespace almo
} // namespace almo
10 changes: 5 additions & 5 deletions src/parse.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
namespace almo {

template<class Syntax>
void InlineParser::process_inline(const std::string &str, ASTNode &ast, Syntax&& syn, int pos){
void InlineParser::process_inline(std::string_view str, ASTNode &ast, Syntax&& syn, int pos){
std::invoke(syn, str, ast);
}

// syn has matched at position pos
template<class Syntax, class HeadSyntax, class... TailSyntax>
void InlineParser::process_inline(const std::string &str, ASTNode &ast, Syntax&& syn, int pos, HeadSyntax&& hsyn, TailSyntax&&... tsyn){
void InlineParser::process_inline(std::string_view str, ASTNode &ast, Syntax&& syn, int pos, HeadSyntax&& hsyn, TailSyntax&&... tsyn){
int newpos = std::invoke(hsyn, str);
if (newpos < pos){
// syntax with nearer match detected
Expand All @@ -25,8 +25,8 @@ void InlineParser::process_inline(const std::string &str, ASTNode &ast, Syntax&&
}
}

void InlineParser::process(const std::string &str, ASTNode &ast){
if (str == "") return ;
void InlineParser::process(std::string_view str, ASTNode &ast){
if (str.empty()) return ;
process_inline(
str, ast,
RawTextSyntax{}, std::numeric_limits<int>::max(),
Expand Down Expand Up @@ -92,4 +92,4 @@ void MarkdownParser::process(ASTNode &ast){
}
}

} // namespace almo
} // namespace almo
50 changes: 28 additions & 22 deletions src/render.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
#include <functional>
#include <iostream>
#include <map>
#include <regex>
#include <sstream>
#include <string>
#include <vector>
Expand All @@ -13,6 +12,25 @@
#include "utils.hpp"

namespace almo {

namespace detail {

inline bool has_node_class(const ASTNode& node, const std::string& classname) {
if (node.get_classname() == classname) {
return true;
}

for (const auto& child : node.childs) {
if (has_node_class(*child, classname)) {
return true;
}
}

return false;
}

} // namespace detail

std::string load_html_template(std::string html_path, std::string css_setting,
bool required_pyodide) {
const std::string pyodide_loader =
Expand All @@ -31,15 +49,15 @@ std::string load_html_template(std::string html_path, std::string css_setting,
std::string result;
if (css_setting == "light") {
std::string css = "<style>" + LIGHT_THEME + "</style>";
result = std::regex_replace(html, std::regex("\\{\\{style\\}\\}"), css);
result = replace_all(html, "{{style}}", css);
} else if (css_setting == "dark") {
std::string css = "<style>" + DARK_THEME + "</style>";
result = std::regex_replace(html, std::regex("\\{\\{style\\}\\}"), css);
result = replace_all(html, "{{style}}", css);
} else if (css_setting.ends_with(".css")) {
std::string css =
"<style>" + join(read_file(css_setting), "\n") + "</style>";

result = std::regex_replace(html, std::regex("\\{\\{style\\}\\}"), css);
result = replace_all(html, "{{style}}", css);
} else {
throw InvalidCommandLineArgumentsError(
"不正なCSSの設定です。 `light`, `dark` もしくは `.css` "
Expand All @@ -55,8 +73,7 @@ std::string load_html_template(std::string html_path, std::string css_setting,
runner = "<!-- Runner is not required. Skip this. -->";
}
// runner を挿入
result =
std::regex_replace(result, std::regex("\\{\\{runner\\}\\}"), runner);
result = replace_all(result, "{{runner}}", runner);

return result;
}
Expand All @@ -67,17 +84,13 @@ std::string replace_template(std::string html_template,
std::string output_html = html_template;

for (auto [key, value] : meta_data) {
std::string replace_key = "\\{\\{" + key + "\\}\\}";
output_html =
std::regex_replace(output_html, std::regex(replace_key), value);
output_html = replace_all(output_html, "{{" + key + "}}", value);
}

std::string syntax_theme = meta_data["syntax_theme"];

output_html = std::regex_replace(
output_html, std::regex("\\{\\{syntax_theme\\}\\}"), syntax_theme);
output_html = std::regex_replace(
output_html, std::regex("\\{\\{contents\\}\\}"), content);
output_html = replace_all(output_html, "{{syntax_theme}}", syntax_theme);
output_html = replace_all(output_html, "{{contents}}", content);

return output_html;
}
Expand All @@ -97,24 +110,18 @@ void move_footnote_to_end(Markdown& ast) {
}

bool required_pyodide(Markdown& ast) {
if (ast.nodes_byclass("ExecutableCodeBlock").size() > 0) {
if (detail::has_node_class(ast, "ExecutableCodeBlock")) {
return true;
}

if (ast.nodes_byclass("Judge").size() > 0) {
if (detail::has_node_class(ast, "Judge")) {
return true;
}

return false;
}

std::string render(Markdown ast, std::map<std::string, std::string> meta_data) {
std::vector<std::shared_ptr<ASTNode>> footnote_defs =
ast.nodes_byclass("FootnoteDefinition");

std::shared_ptr<DivBlock> footnote_div =
std::make_shared<DivBlock>("footnote");

std::string content = ast.to_html();

std::string html_template =
Expand Down Expand Up @@ -185,7 +192,6 @@ ParseSummary md_to_summary(const std::vector<std::string>& md_content,

move_footnote_to_end(ast);

render(ast, meta_data);
ParseSummary summary = {
.ast = ast,
.html = render(ast, meta_data),
Expand Down
29 changes: 13 additions & 16 deletions src/syntax/InlineCodeBlock.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "../interfaces/parse.hpp"
#include "../interfaces/syntax.hpp"
#include "../utils.hpp"
#include "inline_match_utils.hpp"

namespace almo {

Expand All @@ -12,7 +13,7 @@ struct InlineCodeBlock : public ASTNode {
std::string code;

public:
InlineCodeBlock(std::string code) : code(code) { set_uuid(); }
InlineCodeBlock(std::string_view code) : code(code) { set_uuid(); }

std::string to_html() const override {
return "<span class=\"inline-code\"><code>" + escape(code, EscapeFormat::HTML) +
Expand All @@ -26,25 +27,21 @@ struct InlineCodeBlock : public ASTNode {
};

struct InlineCodeBlockSyntax : public InlineSyntax {
static inline const std::regex rex = std::regex(R"((.*?)\`(.*?)\`(.*))");
int operator()(const std::string &str) const override {
std::smatch sm;
if (std::regex_search(str, sm, rex)) {
return sm.position(2) - 1;
int operator()(std::string_view str) const override {
inline_match::DelimitedMatch match;
if (inline_match::find_delimited(str, "`", "`", match)) {
return static_cast<int>(match.start);
}
return std::numeric_limits<int>::max();
}
void operator()(const std::string &str, ASTNode &ast) const override {
std::smatch sm;
std::regex_search(str, sm, rex);
std::string prefix = sm.format("$1");
std::string code = sm.format("$2");
std::string suffix = sm.format("$3");
InlineParser::process(prefix, ast);
InlineCodeBlock node(code);
void operator()(std::string_view str, ASTNode &ast) const override {
inline_match::DelimitedMatch match;
inline_match::find_delimited(str, "`", "`", match);
InlineParser::process(match.prefix, ast);
InlineCodeBlock node(match.content);
ast.pushback_child(std::make_shared<InlineCodeBlock>(node));
InlineParser::process(suffix, ast);
InlineParser::process(match.suffix, ast);
}
};

} // namespace almo
} // namespace almo
29 changes: 13 additions & 16 deletions src/syntax/InlineFootnoteReference.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@
#include "../interfaces/parse.hpp"
#include "../interfaces/syntax.hpp"
#include "../utils.hpp"
#include "inline_match_utils.hpp"

namespace almo {
struct InlineFootnoteReference : public ASTNode {
private:
std::string symbol;

public:
InlineFootnoteReference(std::string _symbol) : symbol(_symbol) {
InlineFootnoteReference(std::string_view _symbol) : symbol(_symbol) {
set_uuid();
}

Expand All @@ -34,24 +35,20 @@ struct InlineFootnoteReference : public ASTNode {
}
};
struct InlineFootnoteReferenceSyntax : public InlineSyntax {
static inline const std::regex rex = std::regex(R"((.*?)\[\^(.*?)\](.*))");
int operator()(const std::string &str) const override {
std::smatch sm;
if (std::regex_search(str, sm, rex)) {
return sm.position(2) - 1;
int operator()(std::string_view str) const override {
inline_match::DelimitedMatch match;
if (inline_match::find_delimited(str, "[^", "]", match)) {
return static_cast<int>(match.start);
}
return std::numeric_limits<int>::max();
}
void operator()(const std::string &str, ASTNode &ast) const override {
std::smatch sm;
std::regex_search(str, sm, rex);
std::string prefix = sm.format("$1");
std::string symbol = sm.format("$2");
std::string suffix = sm.format("$3");
InlineParser::process(prefix, ast);
InlineFootnoteReference node(symbol);
void operator()(std::string_view str, ASTNode &ast) const override {
inline_match::DelimitedMatch match;
inline_match::find_delimited(str, "[^", "]", match);
InlineParser::process(match.prefix, ast);
InlineFootnoteReference node(match.content);
ast.pushback_child(std::make_shared<InlineFootnoteReference>(node));
InlineParser::process(suffix, ast);
InlineParser::process(match.suffix, ast);
}
};
} // namespace almo
} // namespace almo
Loading
Loading