Skip to content

Commit 7919148

Browse files
committed
Fixing api.js to get expression grammar working properly
* fix MultiplicativeExpression * ability to fetch solver and variables from API * quad reimplemented using parser (in /demos/parser) * fix reference to mutation-summary
1 parent e0417d6 commit 7919148

File tree

5 files changed

+260
-14
lines changed

5 files changed

+260
-14
lines changed

.gitmodules

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
url = git://github.com/slightlyoff/ometa-js.git
44
[submodule "third_party/mutation-summary"]
55
path = third_party/mutation-summary
6-
url = https://code.google.com/p/mutation-summary/
6+
url = https://github.com/rafaelw/mutation-summary.git
77
[submodule "third_party/benchmarkjs"]
88
path = third_party/benchmarkjs
99
url = https://github.com/bestiejs/benchmark.js.git

demos/parser/index.html

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta http-equiv="X-UA-Compatible" content="chrome=1">
5+
6+
<title>Quadrilateral demo - Cassowary Javascript</title>
7+
<style type="text/css">
8+
canvas { background-color: lightgray }
9+
* { font-family: sans-serif}
10+
</style>
11+
</head>
12+
<body>
13+
<h1>Quadrilateral demo - Cassowary Javascript</h1>
14+
<p>Below is the bounded quadrilateral demo reimplemented using expressions. <a href="../quad/quaddemo.html">See original implementation</a></p>
15+
<canvas id="c" width="800" height="600"></canvas>
16+
</body>
17+
18+
<script src='../../src/c.js'></script>
19+
<script src='../../src/HashTable.js'></script>
20+
<script src='../../src/HashSet.js'></script>
21+
<script src='../../src/Error.js'></script>
22+
<script src='../../src/SymbolicWeight.js'></script>
23+
<script src='../../src/Strength.js'></script>
24+
<script src='../../src/Variable.js'></script>
25+
<script src='../../src/Point.js'></script>
26+
<script src='../../src/Expression.js'></script>
27+
<script src='../../src/Constraint.js'></script>
28+
<script src='../../src/EditInfo.js'></script>
29+
<script src='../../src/Tableau.js'></script>
30+
<script src='../../src/SimplexSolver.js'></script>
31+
<script src='../../src/Timer.js'></script>
32+
<script src='../../src/parser/parser.js'></script>
33+
<script src='../../src/parser/api.js'></script>
34+
35+
<script src='quadparser.js'></script>
36+
</html>

demos/parser/quadparser.js

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
/*global c*/
2+
/**
3+
* [c1, c2, c3, c4] for corners starting from top left clockwise
4+
* [m1, m2, m3, m4] for midpoints starting from top clockwise
5+
*/
6+
var expressions = [
7+
// midpoints constrained in corners
8+
'(c1x + c2x) / 2 == m1x', '(c1y + c2y) / 2 == m1y',
9+
'(c2x + c3x) / 2 == m2x', '(c2y + c3y) / 2 == m2y',
10+
'(c4x + c3x) / 2 == m3x', '(c4y + c3y) / 2 == m3y',
11+
'(c1x + c4x) / 2 == m4x', '(c1y + c4y) / 2 == m4y',
12+
13+
// spaces between points
14+
'c1x + 20 <= c2x', 'c1x + 20 <= c3x',
15+
'c4x + 20 <= c2x', 'c4x + 20 <= c3x',
16+
'c1y + 20 <= c3y', 'c1y + 20 <= c4y',
17+
'c2y + 20 <= c3y', 'c2y + 20 <= c4y',
18+
19+
// contained inside canvas
20+
'c1x >= 0', 'c2x >= 0', 'c3x >= 0', 'c4x >= 0',
21+
'c1y >= 0', 'c2y >= 0', 'c3y >= 0', 'c4y >= 0',
22+
'c1x <= 800', 'c2x <= 800', 'c3x <= 800', 'c4x <= 800',
23+
'c1y <= 600', 'c2y <= 600', 'c3y <= 600', 'c4y <= 600',
24+
].join(';');
25+
26+
var cOut = c(expressions);
27+
var solver = c('solver');
28+
29+
30+
/**
31+
* Point - holds c.Variable coordinate representing a point
32+
*/
33+
function Point(x, y) {
34+
this.x = x;
35+
this.y = y;
36+
this.size = 15;
37+
}
38+
39+
Point.prototype = {
40+
// checks if a given coordinate is inside the box representing the point
41+
contains: function(x, y) {
42+
return (Math.abs(x - this.x.value) <= this.size/2 &&
43+
Math.abs(y - this.y.value) <= this.size/2);
44+
},
45+
46+
// draws a box representing the point
47+
draw: function(ctx) {
48+
var z = this.size;
49+
ctx.strokeRect(this.x.value - z/2, this.y.value - z/2, z, z);
50+
},
51+
52+
// sets stay value on the point
53+
stay: function(x, y) {
54+
this.x.value = x;
55+
this.y.value = y;
56+
solver.addStay(this.x).addStay(this.y);
57+
},
58+
59+
// makes point coordinate variables editable
60+
edit: function() {
61+
return solver.addEditVar(this.x).addEditVar(this.y);
62+
},
63+
64+
// suggests coordinate values for the point
65+
suggest: function(x, y) {
66+
return solver.suggestValue(this.x, x).suggestValue(this.y, y);
67+
}
68+
};
69+
70+
71+
72+
/**
73+
* Application
74+
*/
75+
var App = {
76+
init: function() {
77+
this.canvas = document.getElementById('c');
78+
this.cwidth = this.canvas.width;
79+
this.cheight = this.canvas.height;
80+
this._ctx = this.canvas.getContext('2d');
81+
this._dragPoint = null;
82+
83+
// populating corners, midpoints
84+
var ps = this.points = [];
85+
var cs = this.corners = [];
86+
var ms = this.midpoints = [];
87+
var point;
88+
for(var i=1; i<=4; i++) {
89+
point = new Point(c(`c${i}x`), c(`c${i}y`));
90+
cs.push(point);
91+
ps.push(point);
92+
93+
point = new Point(c(`m${i}x`), c(`m${i}y`));
94+
ms.push(point);
95+
ps.push(point);
96+
}
97+
98+
// set initial position
99+
cs[0].stay(100, 100);
100+
cs[1].stay(400, 100);
101+
cs[2].stay(400, 400);
102+
cs[3].stay(100, 400);
103+
ms[0].stay(250, 100);
104+
ms[1].stay(400, 250);
105+
ms[2].stay(250, 400);
106+
ms[3].stay(100, 250);
107+
108+
this.draw();
109+
110+
this._bindEvents();
111+
},
112+
113+
draw: function() {
114+
var g = this._ctx;
115+
g.clearRect(0, 0, this.cwidth, this.cheight);
116+
g.strokeStyle = 'black';
117+
118+
this.points.forEach(function(point) { point.draw(g); });
119+
120+
this._drawLine(this.midpoints);
121+
this._drawLine(this.corners);
122+
},
123+
124+
_drawLine: function(points) {
125+
var g = this._ctx;
126+
127+
g.beginPath();
128+
g.moveTo(points[0].x.value, points[0].y.value);
129+
g.lineTo(points[1].x.value, points[1].y.value);
130+
g.lineTo(points[2].x.value, points[2].y.value);
131+
g.lineTo(points[3].x.value, points[3].y.value);
132+
g.closePath();
133+
g.stroke();
134+
},
135+
136+
_bindEvents: function() {
137+
this.canvas.addEventListener('mousedown', this._mousedown.bind(this));
138+
document.body.addEventListener('mousemove', this._mousemove.bind(this));
139+
document.body.addEventListener('mouseup', this._mouseup.bind(this));
140+
},
141+
142+
_mousedown: function(ev) {
143+
var x = ev.pageX - this.canvas.offsetLeft;
144+
var y = ev.pageY - this.canvas.offsetTop;
145+
146+
for(var i=0; i<this.points.length; i++) {
147+
if(this.points[i].contains(x, y)) {
148+
this._dragPoint = this.points[i];
149+
this._dragPoint.edit().beginEdit();
150+
document.body.style.cursor = 'move';
151+
}
152+
}
153+
},
154+
155+
_mousemove: function(ev) {
156+
if(!this._dragPoint) return;
157+
158+
var x = ev.pageX - this.canvas.offsetLeft;
159+
var y = ev.pageY - this.canvas.offsetTop;
160+
this._dragPoint.suggest(x, y).resolve();
161+
this.draw();
162+
},
163+
164+
_mouseup: function(ev) {
165+
if(this._dragPoint) {
166+
solver.endEdit();
167+
document.body.style.cursor = '';
168+
}
169+
this._dragPoint = null;
170+
}
171+
};
172+
App.init();

src/parser/api.js

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,30 +18,39 @@ var _c = function(expr) {
1818
if (exprs[expr]) {
1919
return exprs[expr];
2020
}
21+
var i;
2122
switch(expr.type) {
2223
case "Inequality":
23-
var op = (expr.operator == "<=") ? c.LEQ : c.GEQ;
24-
var i = new c.Inequality(_c(expr.left), op, _c(expr.right), weak);
24+
var op = (expr.operator === "<=") ? c.LEQ : c.GEQ;
25+
i = new c.Inequality(_c(expr.left), op, _c(expr.right), strong);
2526
solver.addConstraint(i);
2627
return i;
2728
case "Equality":
28-
var i = new c.Equation(_c(expr.left), _c(expr.right), weak);
29+
i = new c.Equation(_c(expr.left), _c(expr.right), strong);
2930
solver.addConstraint(i);
3031
return i;
3132
case "MultiplicativeExpression":
32-
var i = c.times(_c(expr.left), _c(expr.right));
33-
solver.addConstraint(i);
33+
if (expr.operator === "/") {
34+
i = c.divide(_c(expr.left), _c(expr.right));
35+
} else {
36+
i = c.times(_c(expr.left), _c(expr.right));
37+
}
3438
return i;
3539
case "AdditiveExpression":
36-
if (expr.operator == "+") {
37-
return c.plus(_c(expr.left), _c(expr.right));
40+
if (expr.operator === "+") {
41+
i = c.plus(_c(expr.left), _c(expr.right));
3842
} else {
39-
return c.minus(_c(expr.left), _c(expr.right));
43+
i = c.minus(_c(expr.left), _c(expr.right));
4044
}
45+
return i;
4146
case "NumericLiteral":
4247
return new c.Expression(expr.value);
4348
case "Variable":
44-
// console.log(expr);
49+
// special variable to get the solver instance
50+
if(expr.name === 'solver') {
51+
return solver;
52+
}
53+
4554
if(!vars[expr.name]) {
4655
vars[expr.name] = new c.Variable({ name: expr.name });
4756
}
@@ -59,12 +68,28 @@ var compile = function(expressions) {
5968
// Global API entrypoint
6069
c._api = function() {
6170
var args = Array.prototype.slice.call(arguments);
62-
if (args.length == 1) {
63-
if(typeof args[0] == "string") {
71+
var out = {};
72+
73+
if (args.length === 1) {
74+
if(typeof args[0] === "string") {
6475
// Parse and execute it
6576
var r = c.parser.parse(args[0]);
66-
return compile(r);
67-
} else if(typeof args[0] == "function") {
77+
out = compile(r);
78+
79+
// easy getters for solver instance and variables
80+
// allows you to perform c('solver') and c('variableName')
81+
if(out.length === 1 && (
82+
out[0] instanceof c.SimplexSolver ||
83+
out[0] instanceof c.Variable
84+
)) { return out[0]; }
85+
86+
// attach solver and variable list
87+
out.solver = solver;
88+
out.vars = vars;
89+
90+
return out;
91+
92+
} else if(typeof args[0] === "function") {
6893
solver._addCallback(args[0]);
6994
}
7095
}

tests/parser/smoketest.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,5 +70,18 @@ define([
7070
});
7171
});
7272
});
73+
74+
it("can parse multiplication", function() {
75+
expect(c("10*a==30")[0]).to.be.instanceOf(c.Constraint);
76+
});
77+
78+
it("can parse multiple operators along with division", function() {
79+
var constraint = c("x/2 - 1 == 29")[0];
80+
expect(constraint).to.be.instanceOf(c.Constraint);
81+
expect(constraint.expression.terms.size).to.equal(1);
82+
constraint.expression.terms.each(function(cVar) {
83+
expect(cVar.value).to.equal(60);
84+
});
85+
});
7386
});
7487
});

0 commit comments

Comments
 (0)