Skip to content

Instantly share code, notes, and snippets.

@PetarKirov
Created July 30, 2017 13:43
Show Gist options
  • Save PetarKirov/5545e5bdac41a7ef1ac90c5d6cba0c14 to your computer and use it in GitHub Desktop.
Save PetarKirov/5545e5bdac41a7ef1ac90c5d6cba0c14 to your computer and use it in GitHub Desktop.
Parsing logic formulas with pegged
/++ dub.sdl:
name "pegged_logic"
dependency "pegged" version="~>0.4.2"
+/
import std.json;
struct Text
{
string name;
string title;
//this(string name, string matchedInput, size_t begin, size_t end)
//{
// import std.format : format;
// this.name = "{ %s } -> %s [%s .. %s]"
// .format(matchedInput, name, begin, end);
//}
}
struct Node(T)
{
T text;
bool collapsed = true;
Node[] children;
alias ValueType = T;
}
JSONValue treeToJson(NodeType, Tree)(auto ref Tree tree)
{
NodeType toNode()(auto ref Tree t)
{
auto result = NodeType(
NodeType.ValueType(t.input[t.begin .. t.end], t.name));//, t.begin, t.end));
foreach (child; t.children)
result.children ~= toNode(child);
return result;
}
return toNode(tree).toJson;
}
JSONValue toJson(T)(T obj)
{
import std.traits;
JSONValue json;
static if (isScalarType!T || isSomeString!T)
{
json = JSONValue(obj);
}
else static if (is(T == struct))
{
JSONValue[string] result;
foreach (idx, field; obj.tupleof)
result[T.tupleof[idx].stringof] = toJson(field);
json = result;
}
else static if (isArray!T)
{
json = new JSONValue[obj.length];
foreach (idx, elem; obj)
json.array[idx] = toJson(elem);
}
else
assert (0, "Unsupported type: " ~ T.stringof ~ "!");
return json;
}
immutable htmlTemplate = `
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title></title>
<link rel="stylesheet prefetch" type="text/css" href="https://fperucic.github.io/treant-js/Treant.css">
<style class="">
.node { width: auto !important; height: auto !important; color: #9CB5ED; border: 2px solid #C8C8C8; border-radius: 3px; padding: 0px; background: #fff;}
.node p { font-size: 20px; font-weight: bold; margin: 5px; }
.Treant .collapse-switch { width: 100%%; height: 100%%; border: none; background: transparent !important; }
</style>
</head>
<body>
<script src="https://fperucic.github.io/treant-js/Treant.js"></script>
<script src="https://fperucic.github.io/treant-js/vendor/raphael.js"></script>
<script src="https://fperucic.github.io/treant-js/vendor/jquery.min.js"></script>
<script src="https://fperucic.github.io/treant-js/vendor/jquery.easing.js"></script>
%-(%s%)
</body>
</html>`;
immutable itemTemplate = `
<div id="tree-simple-%1$s" style="height: 100vh;"> </div>
<script>
simple_chart_config_%1$s = {
chart: {
container: "#tree-simple-%1$s",
animateOnInit: false,
node: {
collapsable: true,
},
animation: {
nodeSpeed: 100,
connectorsSpeed: 100
}
},
nodeStructure: %2$s
};
var my_chart = new Treant(simple_chart_config_%1$s);
</script>`;
void main()
{
import pegged.grammar, std.stdio;
//mixin(grammar(`
//Arithmetic:
// Term < Factor (Add / Sub)*
// Add < "+" Factor
// Sub < "-" Factor
// Factor < Primary (Mul / Div)*
// Mul < "*" Primary
// Div < "/" Primary
// Primary < Parens / Neg / Pos / Number / Variable
// Parens < "(" Term ")"
// Neg < "-" Primary
// Pos < "+" Primary
// Number < ~([0-9]+)
// Variable <- identifier
//`));
//mixin(grammar(`
//Logic:
// Formula < (Connective / Negation / Variable)
// Variable < identifier
// Negation < ("!" / "~" / "¬") Formula
// Connective < (And / Or / Implication)
// And < Formula "&" Formula
// Or < Formula ("∨" / "|") Formula
// Implication < Formula ("=>") Formula
//`));
//mixin(grammar(`
//Logic:
// Term < Factor (Implication / Equivalence)?
// Implication < "=>" Factor
// Equivalence < "<=>" Factor
// Factor < Primary (And / Or)*
// And < "&" Primary
// Or < "/" Primary
// Primary < Parens / Neg / Literal / Variable
// Parens < "(" Term ")"
// Neg < ("!" / "~" / "¬") Primary
// Literal < (True / False)
// True < ("true" / "1")
// False < ("false" / "1")
// Variable <- identifier
//`));
//mixin(grammar(`
//Logic:
// Term < Factor (Implication / Equivalence)?
// Implication < "=>" Factor
// Equivalence < "<=>" Factor
// Factor < Primary (And / Or)*
// And < "&" Primary
// Or < "/" Primary
// Primary < Parens / Neg / Literal / Variable
// Parens < "(" Term ")"
// Neg < ("!" / "~" / "¬") Primary
// Literal < (True / False)
// True < ("true" / "1")
// False < ("false" / "1")
// Variable <- identifier
//`));
//mixin(grammar(`
//Logic:
// Formula <
// / Formula "=>" Term
// / Formula "<=>" Term
// / Term
// Term <
// / Term '&' Primary
// / Term '|' Primary
// / Primary
// Primary <
// / Variable
// / ('!' / '~' / '¬') Primary
// / '(' Formula ')'
// Variable <- identifier
//`));
//mixin(grammar(`
//Logic:
// Formula < Implication / Term
// Implication < Formula "=>" Term
// Term < And / Or / Primary
// And < Term '&' Primary
// Or < Term '|' Primary
// Primary < Variable / Negation / '(' Formula ')'
// Negation < ('!' / '~' / '¬') Primary
// Variable <- identifier
//`));
//mixin(grammar(`
//Logic:
// Parenthesis < '(' Parenthesis ')' / Formula
// Formula < Implication / Term
// Implication < Formula "=>" Term
// Term < And / Or / Primary
// And < Term '&' Primary
// Or < Term '|' Primary
// Primary < Variable / Negation / Parenthesis
// Negation < ('!' / '~' / '¬') Primary
// Variable <- identifier
//`));
//mixin(grammar(`
//Logic:
// Parenthesis < '(' Formula ')' / '(' Parenthesis ')'
// Formula < Implication / Term
// Implication < Formula "=>" Term
// Term < Or / And / Primary
// And < Term '&' Primary
// Or < Term '|' Primary
// Primary < Variable / Negation / '(' Formula ')' / Parenthesis
// Negation < ('!' / '~' / '¬') (Variable / Negation / '(' Formula ')' / Parenthesis)
// Variable <- identifier
//`));
mixin(grammar(`
Logic:
Formula < '(' Formula ')' / Implication / Or / And / Negation / Variable
Implication < '(' Formula "=>" Formula ')'
And < '(' Formula '&' Formula ')'
Or < '(' Formula '|' Formula ')'
Negation < ('!' / '~' / '¬') Formula
Variable <- identifier
`));
//mixin(grammar(`
//Logic:
// Parenthesis < '(' Parenthesis ')' / Formula
// Formula < Implication / Term
// Implication < Formula "=>" Term
// Term < And / Or / Primary
// And < Term '&' Primary
// Or < Term '|' Primary
// Primary < Variable / Negation
// Negation < ('!' / '~' / '¬') Primary
// Variable <- identifier
//`));
//mixin(grammar(`
//Logic:
// Formula < Connective / Negation / Variable
// Negation < ( "!" / "~" / "¬" ) Formula
// Variable < identifier
// Connective < Implication / Or / And
// And < Formula ( '∧' / '&' ) Formula
// Or < Formula ( '∨' / '|' ) Formula
// Implication < Formula ( "⇒" / "=>" ) Formula
//`));
auto ps =
[
Logic("p"),
Logic("(p)"),
Logic("((p))"),
//Logic("~p"),
//Logic("~(p)"),
//Logic("~((p))"),
//Logic("(~p)"),
//Logic("((~p))"),
//Logic("(~((p)))"),
//Logic("(((((~((((p)))))))))"),
//Logic("p & q"),
Logic("(p) & q"),
//Logic("((p) & q)"),
//Logic("p & (q)"),
//Logic("(p & (q))"),
//Logic("((p) & (q))"),
Logic("(p & q)"),
//Logic("p & ¬r => ¬p & r"),
//Logic("p & ¬(r) => ¬p & r"),
//Logic("p & ¬(r & p) => ¬p & r"),
//Logic("p & ¬(r & p => r) => ¬p & r"),
//Logic("(p & ¬((r & p) => (r)) => (¬p) & r)"),
Logic("((p & ¬((r & p) => (r))) => ((¬p) & r))"),
];
"%(%s\n%)".writefln(ps);
import pegged.tohtml;
import std.algorithm, std.array, std.range, std.format, std.file : write_file = write;
auto last = ps[$-1];
last.toHTML("out");
auto nodes = ps.map!(node => node.treeToJson!(Node!Text).toString())
.enumerate
.map!(x => itemTemplate.format(x[0], x[1]))
.array;
"tree.html".write_file(
htmlTemplate.format(nodes)
);
//enum parseTree1 = Logic("(p & ¬r) (¬p & r)");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment