Added docs directory

This commit is contained in:
yhirose 2019-02-09 01:00:30 -05:00
parent e12ab41b40
commit cc053fd9ad
6 changed files with 310 additions and 0 deletions

33
docs/index.html Normal file
View 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
View 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
View 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

File diff suppressed because one or more lines are too long

BIN
docs/native.wasm Normal file

Binary file not shown.

68
docs/style.css Normal file
View 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;
}