Skip to content

Commit

Permalink
Merge pull request #7 from abap34/table
Browse files Browse the repository at this point in the history
Tableを実装 🎉
  • Loading branch information
abap34 authored Aug 8, 2023
2 parents 8b4b7b6 + 0d760e4 commit 2c54e5a
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 60 deletions.
6 changes: 6 additions & 0 deletions example/example.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,9 @@ in=example/in/*.txt
out=example/out/*.txt
judge=equal
:::


| **TOKYO** | 2 | 3 |
|:---|:---:|---:|
| *4* | **おい** | 9 |
| 7 | 8 | 9 |
6 changes: 6 additions & 0 deletions src/ast.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ namespace almo {
NewLine, // 改行
ListBlock, // 箇条書きのブロック
Item, // 箇条書きの要素
Table, // テーブル
};

// 構文木のノードを表す構造体
Expand All @@ -45,5 +46,10 @@ namespace almo {

// typeがCodeRunnerのときのみ使用されます。CodeRunnerの情報を持ちます。
std::vector<std::pair<std::string, std::string>> code_runner;

// typeがTableのときのみ使用されます。Tableの情報を持ちます。
std::vector<std::pair<std::string, std::string>> table;
std::vector<int> col_format;
std::vector<std::string> col_names;
};
}
12 changes: 12 additions & 0 deletions src/makejson.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,20 @@ nlohmann::json dp_on_AST(AST::node_ptr ptr){
sub["uuid"] = uuid();
cur_json["content"].push_back(sub);
}
else if (ptr->type == Table){
cur_json["class"] = "Table";
for (AST::node_ptr child : ptr->childs){
cur_json["content"].push_back(dp_on_AST(child));
}

for (auto [property, name] : ptr->table){
cur_json[property] = name;
}

cur_json["col_format"] = ptr->col_format;
cur_json["col_names"] = ptr->col_names;

}
else {
if (ptr->type == H1) cur_json["class"] = "H1";
if (ptr->type == H2) cur_json["class"] = "H2";
Expand Down
143 changes: 83 additions & 60 deletions src/parse.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,20 @@ namespace almo {
memo.emplace_back(std::regex_replace(s, math_regex, "$2"));
s = std::regex_replace(s, math_regex, format);
}
else if(std::regex_match(s, image_regex)) {
else if (std::regex_match(s, image_regex)) {
auto& memo = map[InlineImage];
int id_url = memo.size();
int id_str = id_url+1;
int id_str = id_url + 1;
std::string format = "$1<__image=" + std::to_string(id_url) + ">" + std::to_string(id_str) + "</__image>$4";
memo.emplace_back(std::regex_replace(s, url_regex, "$3"));
memo.emplace_back(std::regex_replace(s, url_regex, "$2"));

s = std::regex_replace(s, url_regex, format);
}
else if(std::regex_match(s, url_regex)) {
else if (std::regex_match(s, url_regex)) {
auto& memo = map[InlineUrl];
int id_url = memo.size();
int id_str = id_url+1;
int id_str = id_url + 1;
std::string format = "$1<__url=" + std::to_string(id_url) + ">" + std::to_string(id_str) + "</__url>$4";
memo.emplace_back(std::regex_replace(s, url_regex, "$3"));
memo.emplace_back(std::regex_replace(s, url_regex, "$2"));
Expand Down Expand Up @@ -81,7 +81,7 @@ namespace almo {
return node;
}

private:
private:
// パースの内部で呼ばれるdfsです。
// processer以外で呼ばれることはないです
std::vector<AST::node_ptr> dfs(std::string s) {
Expand Down Expand Up @@ -131,7 +131,7 @@ namespace almo {
nodes.emplace_back(node);
nodes.insert(nodes.end(), d3.begin(), d3.end());
}
else if(std::regex_match(s, url_html_regex)) {
else if (std::regex_match(s, url_html_regex)) {
auto node = std::make_shared<AST>(InlineUrl);
int id_url = std::stoi(std::regex_replace(s, url_html_regex, "$2"));
int id_str = std::stoi(std::regex_replace(s, url_html_regex, "$3"));
Expand Down Expand Up @@ -288,14 +288,14 @@ namespace almo {
}
asts.emplace_back(block);
}
else if (line.starts_with("- ")){
else if (line.starts_with("- ")) {
// item が途切れるまで行を跨いでパースする。 cur は indent 分だけずらしたカーソルを表す。
// 返り値は item が終了した直後の行の idx と パース結果を表す構文木のポインタ 。
auto item_parser = [&](int line_id, int cur = 0) -> std::pair<int,AST::node_ptr> {
auto item_parser = [&](int line_id, int cur = 0) -> std::pair<int, AST::node_ptr> {
auto block = std::make_shared<AST>(Item);
assert(lines[line_id].substr(cur,2) == "- ");
std::string aitem = lines[line_id].substr(cur+2);
while (true){
assert(lines[line_id].substr(cur, 2) == "- ");
std::string aitem = lines[line_id].substr(cur + 2);
while (true) {
line_id++;
if (line_id == (int)(lines.size())) break;
if (lines[line_id].starts_with("- ")) break;
Expand All @@ -307,10 +307,10 @@ namespace almo {
aitem += lines[line_id];
}
block->childs.emplace_back(inline_parser.processer(aitem));
return std::make_pair(line_id,block);
};
return std::make_pair(line_id, block);
};
auto block = std::make_shared<AST>(ListBlock);
while (true){
while (true) {
auto [nxt, ptr] = item_parser(idx);
block->childs.emplace_back(ptr);
idx = nxt;
Expand All @@ -320,56 +320,79 @@ namespace almo {
idx--;
asts.emplace_back(block);
}
else if (line.starts_with("- ")){
// // item が途切れるまで行を跨いでパースする。返り値は item が終了した直後の行の idx と パース結果を表す構文木のポインタ 。
// auto item_parser = [&](int line_id, int cur = 0) -> std::pair<int,AST::node_ptr> {
// auto block = std::make_shared<AST>(Item);
// assert(lines[line_id].substr(cur,2) == "- ");
// std::string aitem = lines[line_id].substr(cur+2);
// while (true){
// line_id++;
// if (line_id == (int)(lines.size())) break;
// if (lines[line_id].starts_with("- ")) break;
// if (lines[line_id].starts_with("#")) break;
// if (lines[line_id].starts_with(":::")) break;
// if (lines[line_id].starts_with("```")) break;
// if (lines[line_id].starts_with("$$")) break;
// if (lines[line_id] == "") break;
// // TODO ここには、item -> ListBlock の遷移が書かれる
// aitem += lines[line_id];
// }
// block->childs.emplace_back(inline_parser.processer(aitem));
// };
// auto get_indent = [](const std::string &____str){
// int indent_cur = 0;
// while (indent_cur < (int)(____str.size()) && ____str[indent_cur] == ' ') indent_cur++;
// return indent_cur;
// };
// auto list_dfs = [&](auto list_dfs, int line_id, int ListBlock_Item_PlainText) -> std::pair<int,AST::node_ptr> {
// if (ListBlock_Item_PlainText == 2){
// int indent_cur = get_indent(lines[line_id]);
// assert(lines[line_id].substr(indent_cur,2) == "- ");
// auto block = std::make_shared<AST>();
// block->childs.emplace_back(inline_parser.processer(lines[line_id].substr(indent_cur+2)));
// }
// int indent_cur = get_indent(lines[line_id]);
// assert(lines[line_id].substr(indent_cur,2) == "- ");
// auto block = std::make_shared<AST>(ListBlock);
// int cur_id = line_id;
// while (true){
// if ((int)lines[cur_id].size() >= indent_cur+2 && lines[cur_id].substr(indent_cur,2) == "- "){
// block->childs.emplace_back(std::make_shared<AST>())
// }
// }
// };
// auto [next_idx, block] = list_dfs(list_dfs,idx,0);
// idx = next_idx;
// asts.emplace_back(block);
}
else if (line == "") {
auto block = std::make_shared<AST>(NewLine);
asts.emplace_back(block);
}
else if (std::regex_match(line, std::regex("(\\|[^\\|]+).+\\|"))) {
const std::regex each_col_regex = std::regex("\\|[^\\|]+");

int n_col = 0;

std::vector<std::string> col_names(n_col);
std::smatch match;

while (std::regex_search(line, match, each_col_regex)) {
col_names.push_back(match[0].str().substr(1, match[0].str().size()));
line = match.suffix();
n_col++;
}

// 0 -> 左寄せ, 1 -> 中央寄せ, 2 -> 右寄せ
std::vector<int> col_format(0);

idx++;

std::string line2 = lines[idx];
std::smatch match2;
while (std::regex_search(line2, match2, each_col_regex)) {
if (match2[0].str().starts_with("|:") && match2[0].str().ends_with(":")) {
col_format.push_back(1);
}
else if (match2[0].str().starts_with("|:")) {
col_format.push_back(0);
}
else if (match2[0].str().ends_with(":")) {
col_format.push_back(2);
}
else {
col_format.push_back(0);
}

line2 = match2.suffix();
}


idx++;
int n_row = 0;
std::vector<std::string> table;


while (idx < (int)(lines.size()) && lines[idx] != "") {
n_row++;
std::string line = lines[idx];
std::smatch match;
std::regex_search(line, match, each_col_regex);
while (std::regex_search(line, match, each_col_regex)) {
table.push_back(match[0].str().substr(1, match[0].str().size()));
line = match.suffix();
}
idx++;
}


auto block = std::make_shared<AST>(Table);
block->table.emplace_back("n_col", std::to_string(n_col));
block->table.emplace_back("n_row", std::to_string(n_row));
block->col_format = col_format;
block->col_names = col_names;

for (int i = 0; i < table.size(); i++) {
block->childs.emplace_back(inline_parser.processer(table[i]));
}

asts.emplace_back(block);
}
else {
auto plain_block = std::make_shared<AST>();
asts.emplace_back(inline_parser.processer(line));
Expand Down
53 changes: 53 additions & 0 deletions src/render.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,21 @@ namespace almo {
width: 50%;
}
table {
border-collapse: collapse;
width: 100%;
}
th {
border: 1px solid #ddd;
padding: 8px;
}
td {
border: 1px solid #ddd;
padding: 8px;
}
</style>
</head>
Expand Down Expand Up @@ -795,6 +810,26 @@ namespace almo {
return output;
}

std::string render_table(std::vector<std::string> from_render, int n_row, int n_col, std::vector<std::string> col_names, std::vector<int> col_format) {
// std::cout << "render table" << std::endl;
std::string output = "<table>";
output += "<tr>";
for (int i = 0; i < n_col; i++) {
output += "<th>" + col_names[i] + "</th>";
}

output += "</tr>";

for (int i = 0; i < n_row; i++) {
output += "<tr>";
for (int j = 0; j < n_col; j++) {
std::string align = col_format[j] == 0 ? "left" : col_format[j] == 1 ? "center" : "right";
output += "<td align=\"" + align + "\">" + from_render[i * n_col + j] + "</td>";
}
output += "</tr>";
}
return output;
}



Expand All @@ -819,6 +854,24 @@ namespace almo {
}
render_str = render_map[j["class"]](url, from_render);
}
else if (j["class"] == "Table") {
std::vector<std::string> from_render;
for (nlohmann::json child : j["content"]) {
from_render.push_back(build_block(child, render_map));
}
std::vector<int> col_format = j["col_format"];
std::vector<std::string> col_names = j["col_names"];

std::string n_row_str = j["n_row"];
std::string n_col_str = j["n_col"];

int n_row = std::stoi(n_row_str);
int n_col = std::stoi(n_col_str);


return render_table(from_render, n_row, n_col, col_names, col_format);

}
else if (haschild(j)) {
for (nlohmann::json child : j["content"]) {
std::string from_render = build_block(child, render_map);
Expand Down

0 comments on commit 2c54e5a

Please sign in to comment.