mirror of
https://github.com/yhirose/cpp-peglib.git
synced 2024-12-22 20:05:31 +00:00
Added docs directory
This commit is contained in:
parent
e12ab41b40
commit
cc053fd9ad
33
docs/index.html
Normal file
33
docs/index.html
Normal file
@ -0,0 +1,33 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>PEG Playground</title>
|
||||
<link rel="stylesheet" href="style.css" media="all">
|
||||
</head>
|
||||
<body>
|
||||
<div id="main">
|
||||
<div class="editor-container">
|
||||
<ul class="editor-header">
|
||||
<li><span>Grammar:</span></li>
|
||||
<li><span id="grammar-validation" class="editor-validation">Valid</span></li>
|
||||
</ul>
|
||||
<pre id="grammar-editor" class="editor-area">{{syntax}}</pre>
|
||||
<div id="grammar-info" class="editor-info"></div>
|
||||
</div>
|
||||
<div class="editor-container">
|
||||
<ul class="editor-header">
|
||||
<li><span>Code:</span></li>
|
||||
<li><span id="code-validation" class="editor-validation">Valid</span></li>
|
||||
</ul>
|
||||
<pre id="code-editor" class="editor-area">{{source}}</pre>
|
||||
<pre id="code-ast" class="editor-area"></pre>
|
||||
<pre id="code-ast-optimized" class="editor-area"></pre>
|
||||
<div id="code-info" class="editor-info"></div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.1.9/ace.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
|
||||
<script src="index.js"></script>
|
||||
<script src="native.js"></script>
|
||||
</body>
|
||||
</html>
|
119
docs/index.js
Normal file
119
docs/index.js
Normal file
@ -0,0 +1,119 @@
|
||||
// Setup editros
|
||||
const grammar = ace.edit("grammar-editor");
|
||||
grammar.setShowPrintMargin(false);
|
||||
grammar.setValue(localStorage.getItem('grammarText'));
|
||||
grammar.moveCursorTo(0, 0);
|
||||
|
||||
const code = ace.edit("code-editor");
|
||||
code.setShowPrintMargin(false);
|
||||
code.setValue(localStorage.getItem('codeText'));
|
||||
code.moveCursorTo(0, 0);
|
||||
|
||||
const codeAst = ace.edit("code-ast");
|
||||
codeAst.setShowPrintMargin(false);
|
||||
codeAst.setOptions({
|
||||
readOnly: true,
|
||||
highlightActiveLine: false,
|
||||
highlightGutterLine: false
|
||||
})
|
||||
codeAst.renderer.$cursorLayer.element.style.opacity=0;
|
||||
|
||||
const codeAstOptimized = ace.edit("code-ast-optimized");
|
||||
codeAstOptimized.setShowPrintMargin(false);
|
||||
codeAstOptimized.setOptions({
|
||||
readOnly: true,
|
||||
highlightActiveLine: false,
|
||||
highlightGutterLine: false
|
||||
})
|
||||
codeAstOptimized.renderer.$cursorLayer.element.style.opacity=0;
|
||||
|
||||
function generateErrorListHTML(errors) {
|
||||
let html = '<ul>';
|
||||
|
||||
html += $.map(errors, function (x) {
|
||||
return '<li data-ln="' + x.ln + '" data-col="' + x.col + '"><span>' + x.ln + ':' + x.col + '</span> <span>' + x.msg + '</span></li>';
|
||||
}).join('');
|
||||
|
||||
html += '<ul>';
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
function parse() {
|
||||
const $grammarValidation = $('#grammar-validation');
|
||||
const $grammarInfo = $('#grammar-info');
|
||||
const grammarText = grammar.getValue();
|
||||
|
||||
const $codeValidation = $('#code-validation');
|
||||
const $codeInfo = $('#code-info');
|
||||
const codeText = code.getValue();
|
||||
|
||||
localStorage.setItem('grammarText', grammarText);
|
||||
localStorage.setItem('codeText', codeText);
|
||||
|
||||
$grammarInfo.html('');
|
||||
$grammarValidation.hide();
|
||||
$codeInfo.html('');
|
||||
$codeValidation.hide();
|
||||
codeAst.setValue('');
|
||||
codeAstOptimized.setValue('');
|
||||
|
||||
if (grammarText.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const data = JSON.parse(Module.lint(grammarText, codeText));
|
||||
|
||||
const isValid = data.grammar.length === 0;
|
||||
if (isValid) {
|
||||
$grammarValidation.removeClass('editor-validation-invalid').text('Valid').show();
|
||||
|
||||
const isValid = data.code.length === 0;
|
||||
if (isValid) {
|
||||
codeAst.insert(data.ast);
|
||||
codeAstOptimized.insert(data.astOptimized);
|
||||
$codeValidation.removeClass('editor-validation-invalid').text('Valid').show();
|
||||
} else {
|
||||
const html = generateErrorListHTML(data.code);
|
||||
$codeInfo.html(html);
|
||||
$codeValidation.addClass('editor-validation-invalid').text('Invalid').show();
|
||||
}
|
||||
} else {
|
||||
const html = generateErrorListHTML(data.grammar);
|
||||
$grammarInfo.html(html);
|
||||
$grammarValidation.addClass('editor-validation-invalid').text('Invalid').show();
|
||||
}
|
||||
}
|
||||
|
||||
// Event handing for text editiing
|
||||
let timer;
|
||||
function setupTimer() {
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(parse, 750);
|
||||
};
|
||||
grammar.getSession().on('change', setupTimer);
|
||||
code.getSession().on('change', setupTimer);
|
||||
|
||||
// Event handing in the info area
|
||||
function makeOnClickInInfo(editor) {
|
||||
return function () {
|
||||
const el = $(this);
|
||||
editor.navigateTo(el.data('ln') - 1, el.data('col') - 1);
|
||||
editor.focus();
|
||||
}
|
||||
};
|
||||
$('#grammar-info').on('click', 'li', makeOnClickInInfo(grammar));
|
||||
$('#code-info').on('click', 'li', makeOnClickInInfo(code));
|
||||
|
||||
// Show page
|
||||
$('#main').css({
|
||||
'display': 'flex',
|
||||
});
|
||||
|
||||
// WebAssembly
|
||||
var Module = {
|
||||
onRuntimeInitialized: function() {
|
||||
// Initial parse
|
||||
parse();
|
||||
}
|
||||
};
|
86
docs/native.cpp
Normal file
86
docs/native.cpp
Normal file
@ -0,0 +1,86 @@
|
||||
#include <emscripten/bind.h>
|
||||
#include "../peglib.h"
|
||||
#include <cstdio>
|
||||
#include <functional>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
// https://stackoverflow.com/questions/7724448/simple-json-string-escape-for-c/33799784#33799784
|
||||
std::string escape_json(const std::string& s) {
|
||||
std::ostringstream o;
|
||||
for (auto c : s) {
|
||||
if (c == '"' || c == '\\' || ('\x00' <= c && c <= '\x1f')) {
|
||||
o << "\\u" << std::hex << std::setw(4) << std::setfill('0') << (int)c;
|
||||
} else {
|
||||
o << c;
|
||||
}
|
||||
}
|
||||
return o.str();
|
||||
}
|
||||
|
||||
std::function<void(size_t, size_t, const std::string&)> makeJSONFormatter(std::string& json) {
|
||||
auto init = std::make_shared<bool>(true);
|
||||
|
||||
return [&json, init](size_t ln, size_t col, const std::string& msg) mutable {
|
||||
if (!init) {
|
||||
json += ",";
|
||||
}
|
||||
json += "{";
|
||||
json += R"("ln":)" + std::to_string(ln) + ",";
|
||||
json += R"("col":)" + std::to_string(col) + ",";
|
||||
json += R"("msg":")" + escape_json(msg) + R"(")";
|
||||
json += "}";
|
||||
*init = false;
|
||||
};
|
||||
}
|
||||
|
||||
bool parse_grammar(const std::string& text, peg::parser& peg, std::string& json) {
|
||||
peg.log = makeJSONFormatter(json);
|
||||
json += "[";
|
||||
auto ret = peg.load_grammar(text.data(), text.size());
|
||||
json += "]";
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool parse_code(const std::string& text, peg::parser& peg, std::string& json,
|
||||
std::shared_ptr<peg::Ast>& ast) {
|
||||
peg.enable_ast();
|
||||
peg.log = makeJSONFormatter(json);
|
||||
json += "[";
|
||||
auto ret = peg.parse_n(text.data(), text.size(), ast);
|
||||
json += "]";
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string lint(const std::string& grammarText, const std::string& codeText) {
|
||||
std::string grammarResult;
|
||||
std::string codeResult;
|
||||
std::string astResult;
|
||||
std::string astResultOptimized;
|
||||
|
||||
peg::parser peg;
|
||||
auto ret = parse_grammar(grammarText, peg, grammarResult);
|
||||
|
||||
if (ret && peg) {
|
||||
std::shared_ptr<peg::Ast> ast;
|
||||
if (parse_code(codeText, peg, codeResult, ast)) {
|
||||
astResult = escape_json(peg::ast_to_s(ast));
|
||||
astResultOptimized =
|
||||
escape_json(peg::ast_to_s(peg::AstOptimizer(true).optimize(ast)));
|
||||
}
|
||||
}
|
||||
|
||||
std::string json;
|
||||
json += "{";
|
||||
json += "\"grammar\":" + grammarResult;
|
||||
if (!codeResult.empty()) {
|
||||
json += ",\"code\":" + codeResult;
|
||||
json += ",\"ast\":\"" + astResult + "\"";
|
||||
json += ",\"astOptimized\":\"" + astResultOptimized + "\"";
|
||||
}
|
||||
json += "}";
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_BINDINGS(native) { emscripten::function("lint", &lint); }
|
4
docs/native.js
Normal file
4
docs/native.js
Normal file
File diff suppressed because one or more lines are too long
BIN
docs/native.wasm
Normal file
BIN
docs/native.wasm
Normal file
Binary file not shown.
68
docs/style.css
Normal file
68
docs/style.css
Normal file
@ -0,0 +1,68 @@
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
text-decoration: none;
|
||||
list-style: none;
|
||||
}
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
}
|
||||
#main {
|
||||
flex: 1;
|
||||
display: none;
|
||||
}
|
||||
.editor-container {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 8px;
|
||||
}
|
||||
.editor-container:first-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
.editor-header {
|
||||
display: flex;
|
||||
height: 48px;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
.editor-header > li:last-child {
|
||||
margin-left: auto;
|
||||
}
|
||||
.editor-header > li > span {
|
||||
height: 38px;
|
||||
line-height: 38px;
|
||||
}
|
||||
.editor-header > li > a {
|
||||
height: 38px;
|
||||
line-height: 38px;
|
||||
padding: .3em .5em;
|
||||
border: 1px solid red;
|
||||
}
|
||||
.editor-validation {
|
||||
padding: 9px 11px;
|
||||
color: green;
|
||||
background-color: lightgreen;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.editor-validation-invalid {
|
||||
color: red;
|
||||
background-color: pink;
|
||||
}
|
||||
.editor-area {
|
||||
flex: 1;
|
||||
border: 1px solid lightgray;
|
||||
}
|
||||
.editor-info {
|
||||
margin-top: 6px;
|
||||
height: 160px;
|
||||
border: 1px solid lightgray;
|
||||
padding: 8px;
|
||||
}
|
||||
.editor-info li {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user