Skip to content

Commit cc053fd

Browse files
committed
Added docs directory
1 parent e12ab41 commit cc053fd

File tree

6 files changed

+310
-0
lines changed

6 files changed

+310
-0
lines changed

docs/index.html

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<title>PEG Playground</title>
5+
<link rel="stylesheet" href="style.css" media="all">
6+
</head>
7+
<body>
8+
<div id="main">
9+
<div class="editor-container">
10+
<ul class="editor-header">
11+
<li><span>Grammar:</span></li>
12+
<li><span id="grammar-validation" class="editor-validation">Valid</span></li>
13+
</ul>
14+
<pre id="grammar-editor" class="editor-area">{{syntax}}</pre>
15+
<div id="grammar-info" class="editor-info"></div>
16+
</div>
17+
<div class="editor-container">
18+
<ul class="editor-header">
19+
<li><span>Code:</span></li>
20+
<li><span id="code-validation" class="editor-validation">Valid</span></li>
21+
</ul>
22+
<pre id="code-editor" class="editor-area">{{source}}</pre>
23+
<pre id="code-ast" class="editor-area"></pre>
24+
<pre id="code-ast-optimized" class="editor-area"></pre>
25+
<div id="code-info" class="editor-info"></div>
26+
</div>
27+
</div>
28+
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.1.9/ace.js"></script>
29+
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
30+
<script src="index.js"></script>
31+
<script src="native.js"></script>
32+
</body>
33+
</html>

docs/index.js

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// Setup editros
2+
const grammar = ace.edit("grammar-editor");
3+
grammar.setShowPrintMargin(false);
4+
grammar.setValue(localStorage.getItem('grammarText'));
5+
grammar.moveCursorTo(0, 0);
6+
7+
const code = ace.edit("code-editor");
8+
code.setShowPrintMargin(false);
9+
code.setValue(localStorage.getItem('codeText'));
10+
code.moveCursorTo(0, 0);
11+
12+
const codeAst = ace.edit("code-ast");
13+
codeAst.setShowPrintMargin(false);
14+
codeAst.setOptions({
15+
readOnly: true,
16+
highlightActiveLine: false,
17+
highlightGutterLine: false
18+
})
19+
codeAst.renderer.$cursorLayer.element.style.opacity=0;
20+
21+
const codeAstOptimized = ace.edit("code-ast-optimized");
22+
codeAstOptimized.setShowPrintMargin(false);
23+
codeAstOptimized.setOptions({
24+
readOnly: true,
25+
highlightActiveLine: false,
26+
highlightGutterLine: false
27+
})
28+
codeAstOptimized.renderer.$cursorLayer.element.style.opacity=0;
29+
30+
function generateErrorListHTML(errors) {
31+
let html = '<ul>';
32+
33+
html += $.map(errors, function (x) {
34+
return '<li data-ln="' + x.ln + '" data-col="' + x.col + '"><span>' + x.ln + ':' + x.col + '</span> <span>' + x.msg + '</span></li>';
35+
}).join('');
36+
37+
html += '<ul>';
38+
39+
return html;
40+
}
41+
42+
function parse() {
43+
const $grammarValidation = $('#grammar-validation');
44+
const $grammarInfo = $('#grammar-info');
45+
const grammarText = grammar.getValue();
46+
47+
const $codeValidation = $('#code-validation');
48+
const $codeInfo = $('#code-info');
49+
const codeText = code.getValue();
50+
51+
localStorage.setItem('grammarText', grammarText);
52+
localStorage.setItem('codeText', codeText);
53+
54+
$grammarInfo.html('');
55+
$grammarValidation.hide();
56+
$codeInfo.html('');
57+
$codeValidation.hide();
58+
codeAst.setValue('');
59+
codeAstOptimized.setValue('');
60+
61+
if (grammarText.length === 0) {
62+
return;
63+
}
64+
65+
const data = JSON.parse(Module.lint(grammarText, codeText));
66+
67+
const isValid = data.grammar.length === 0;
68+
if (isValid) {
69+
$grammarValidation.removeClass('editor-validation-invalid').text('Valid').show();
70+
71+
const isValid = data.code.length === 0;
72+
if (isValid) {
73+
codeAst.insert(data.ast);
74+
codeAstOptimized.insert(data.astOptimized);
75+
$codeValidation.removeClass('editor-validation-invalid').text('Valid').show();
76+
} else {
77+
const html = generateErrorListHTML(data.code);
78+
$codeInfo.html(html);
79+
$codeValidation.addClass('editor-validation-invalid').text('Invalid').show();
80+
}
81+
} else {
82+
const html = generateErrorListHTML(data.grammar);
83+
$grammarInfo.html(html);
84+
$grammarValidation.addClass('editor-validation-invalid').text('Invalid').show();
85+
}
86+
}
87+
88+
// Event handing for text editiing
89+
let timer;
90+
function setupTimer() {
91+
clearTimeout(timer);
92+
timer = setTimeout(parse, 750);
93+
};
94+
grammar.getSession().on('change', setupTimer);
95+
code.getSession().on('change', setupTimer);
96+
97+
// Event handing in the info area
98+
function makeOnClickInInfo(editor) {
99+
return function () {
100+
const el = $(this);
101+
editor.navigateTo(el.data('ln') - 1, el.data('col') - 1);
102+
editor.focus();
103+
}
104+
};
105+
$('#grammar-info').on('click', 'li', makeOnClickInInfo(grammar));
106+
$('#code-info').on('click', 'li', makeOnClickInInfo(code));
107+
108+
// Show page
109+
$('#main').css({
110+
'display': 'flex',
111+
});
112+
113+
// WebAssembly
114+
var Module = {
115+
onRuntimeInitialized: function() {
116+
// Initial parse
117+
parse();
118+
}
119+
};

docs/native.cpp

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#include <emscripten/bind.h>
2+
#include "../peglib.h"
3+
#include <cstdio>
4+
#include <functional>
5+
#include <iomanip>
6+
#include <sstream>
7+
8+
// https://stackoverflow.com/questions/7724448/simple-json-string-escape-for-c/33799784#33799784
9+
std::string escape_json(const std::string& s) {
10+
std::ostringstream o;
11+
for (auto c : s) {
12+
if (c == '"' || c == '\\' || ('\x00' <= c && c <= '\x1f')) {
13+
o << "\\u" << std::hex << std::setw(4) << std::setfill('0') << (int)c;
14+
} else {
15+
o << c;
16+
}
17+
}
18+
return o.str();
19+
}
20+
21+
std::function<void(size_t, size_t, const std::string&)> makeJSONFormatter(std::string& json) {
22+
auto init = std::make_shared<bool>(true);
23+
24+
return [&json, init](size_t ln, size_t col, const std::string& msg) mutable {
25+
if (!init) {
26+
json += ",";
27+
}
28+
json += "{";
29+
json += R"("ln":)" + std::to_string(ln) + ",";
30+
json += R"("col":)" + std::to_string(col) + ",";
31+
json += R"("msg":")" + escape_json(msg) + R"(")";
32+
json += "}";
33+
*init = false;
34+
};
35+
}
36+
37+
bool parse_grammar(const std::string& text, peg::parser& peg, std::string& json) {
38+
peg.log = makeJSONFormatter(json);
39+
json += "[";
40+
auto ret = peg.load_grammar(text.data(), text.size());
41+
json += "]";
42+
return ret;
43+
}
44+
45+
bool parse_code(const std::string& text, peg::parser& peg, std::string& json,
46+
std::shared_ptr<peg::Ast>& ast) {
47+
peg.enable_ast();
48+
peg.log = makeJSONFormatter(json);
49+
json += "[";
50+
auto ret = peg.parse_n(text.data(), text.size(), ast);
51+
json += "]";
52+
return ret;
53+
}
54+
55+
std::string lint(const std::string& grammarText, const std::string& codeText) {
56+
std::string grammarResult;
57+
std::string codeResult;
58+
std::string astResult;
59+
std::string astResultOptimized;
60+
61+
peg::parser peg;
62+
auto ret = parse_grammar(grammarText, peg, grammarResult);
63+
64+
if (ret && peg) {
65+
std::shared_ptr<peg::Ast> ast;
66+
if (parse_code(codeText, peg, codeResult, ast)) {
67+
astResult = escape_json(peg::ast_to_s(ast));
68+
astResultOptimized =
69+
escape_json(peg::ast_to_s(peg::AstOptimizer(true).optimize(ast)));
70+
}
71+
}
72+
73+
std::string json;
74+
json += "{";
75+
json += "\"grammar\":" + grammarResult;
76+
if (!codeResult.empty()) {
77+
json += ",\"code\":" + codeResult;
78+
json += ",\"ast\":\"" + astResult + "\"";
79+
json += ",\"astOptimized\":\"" + astResultOptimized + "\"";
80+
}
81+
json += "}";
82+
83+
return json;
84+
}
85+
86+
EMSCRIPTEN_BINDINGS(native) { emscripten::function("lint", &lint); }

docs/native.js

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/native.wasm

263 KB
Binary file not shown.

docs/style.css

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
* {
2+
box-sizing: border-box;
3+
margin: 0;
4+
padding: 0;
5+
text-decoration: none;
6+
list-style: none;
7+
}
8+
body {
9+
display: flex;
10+
flex-direction: column;
11+
height: 100vh;
12+
}
13+
#main {
14+
flex: 1;
15+
display: none;
16+
}
17+
.editor-container {
18+
flex: 1;
19+
width: 100%;
20+
display: flex;
21+
flex-direction: column;
22+
margin: 8px;
23+
}
24+
.editor-container:first-child {
25+
margin-right: 0;
26+
}
27+
.editor-header {
28+
display: flex;
29+
height: 48px;
30+
padding: 4px 8px;
31+
}
32+
.editor-header > li:last-child {
33+
margin-left: auto;
34+
}
35+
.editor-header > li > span {
36+
height: 38px;
37+
line-height: 38px;
38+
}
39+
.editor-header > li > a {
40+
height: 38px;
41+
line-height: 38px;
42+
padding: .3em .5em;
43+
border: 1px solid red;
44+
}
45+
.editor-validation {
46+
padding: 9px 11px;
47+
color: green;
48+
background-color: lightgreen;
49+
border-radius: 5px;
50+
}
51+
.editor-validation-invalid {
52+
color: red;
53+
background-color: pink;
54+
}
55+
.editor-area {
56+
flex: 1;
57+
border: 1px solid lightgray;
58+
}
59+
.editor-info {
60+
margin-top: 6px;
61+
height: 160px;
62+
border: 1px solid lightgray;
63+
padding: 8px;
64+
}
65+
.editor-info li {
66+
cursor: pointer;
67+
}
68+

0 commit comments

Comments
 (0)