A categorical programming language
Revision | af6d60d0b960cae2aa7609da89215eadd1f59911 (tree) |
---|---|
Time | 2022-12-05 03:33:01 |
Author | Corbin <cds@corb...> |
Commiter | Corbin |
Try to display equalities.
Dunno how to represent ASTs well yet.
@@ -136,7 +136,7 @@ def compilePurescriptStub(token): | ||
136 | 136 | return response |
137 | 137 | except subprocess.CalledProcessError as cpe: |
138 | 138 | print("Couldn't compile", sexpify(expr)) |
139 | - print(cpe.output.encode("utf-8")) | |
139 | + print(cpe.output.decode("utf-8")) | |
140 | 140 | raise |
141 | 141 | |
142 | 142 | @app.route("/dippers") |
@@ -166,7 +166,9 @@ def dissolve(sexp): | ||
166 | 166 | if merged not in hive.tuples: |
167 | 167 | hive.tuples[merged] = len(hive.heap) |
168 | 168 | hive.heap.append(merged) |
169 | - return hive.tuples[merged] | |
169 | + rv = hive.tuples[merged] | |
170 | + print("dissolve", sexp, "=>", rv) | |
171 | + return rv | |
170 | 172 | |
171 | 173 | class Dip(MethodView): |
172 | 174 | def get(self, name): |
@@ -200,8 +202,10 @@ def isTemplate(expr): | ||
200 | 202 | |
201 | 203 | def jellify(sexp): |
202 | 204 | try: |
203 | - return subprocess.check_output(JELLY + "jelly", | |
205 | + rv = subprocess.check_output(JELLY + "jelly", | |
204 | 206 | input=sexp.encode("utf-8")).decode("utf-8") |
207 | + print("jellify", sexp, "=>", rv) | |
208 | + return rv | |
205 | 209 | except subprocess.CalledProcessError: |
206 | 210 | print("Couldn't jellify", sexp) |
207 | 211 | raise |
@@ -209,13 +213,16 @@ def jellify(sexp): | ||
209 | 213 | @app.route("/dissolve", methods=["POST"]) |
210 | 214 | def dissolveNewExpression(): |
211 | 215 | sexp = request.get_data(as_text=True) |
212 | - sexp = jellify(sexp) | |
213 | 216 | expr, trail = parse(sexp) |
214 | 217 | if isTemplate(expr): |
215 | 218 | print("can't handle templates yet") |
216 | 219 | abort(500) |
220 | + # First dissolution gets the desugared input. | |
217 | 221 | index = dissolve(expr) |
218 | - return jsonify({"expr": index, "trail": trail}) | |
222 | + # Second dissolution gets an approximate normal form. | |
223 | + expr = resolve(index) | |
224 | + index = dissolve(parse(jellify(sexpify(expr)))[0]) | |
225 | + return jsonify({"index": index, "expr": expr, "trail": trail}) | |
219 | 226 | |
220 | 227 | if __name__ == "__main__": |
221 | 228 | app.run(debug=True) |
@@ -206,14 +206,19 @@ class FetchTile extends Component { | ||
206 | 206 | } |
207 | 207 | } |
208 | 208 | |
209 | +function dissolve(sexp) { | |
210 | + console.log("dissolve", sexp); | |
211 | + return fetchJSON("/dissolve", { method: "POST", body: sexp }); | |
212 | +} | |
213 | + | |
209 | 214 | class AnonymousTile extends Component { |
210 | 215 | state = { expr: "" }; |
211 | 216 | |
212 | 217 | onSubmit = addTile => e => { |
213 | - fetchJSON("/dissolve", { method: "POST", body: this.state.expr }).then(({expr, trail}) => { | |
218 | + dissolve(this.state.expr).then(({index, expr, trail}) => { | |
214 | 219 | const title = this.state.expr.startsWith("(") ? "anonymous expression" : this.state.expr; |
215 | - const compiledPromise = import(`/extract/${expr}/compile`); | |
216 | - const tyPromise = fetchJSON(`/extract/${expr}/type`); | |
220 | + const compiledPromise = import(`/extract/${index}/compile`); | |
221 | + const tyPromise = fetchJSON(`/extract/${index}/type`); | |
217 | 222 | return tyPromise.then(ty => |
218 | 223 | compiledPromise.then(compiled => |
219 | 224 | addTile(h(Tile, { ty, compiled, title, trail: trail.trim() })))); |
@@ -234,6 +239,53 @@ class AnonymousTile extends Component { | ||
234 | 239 | } |
235 | 240 | } |
236 | 241 | |
242 | +class Equality extends Component { | |
243 | + render({ trail, lhs, rhs, index }) { | |
244 | + return h("div", { class: "tile" }, | |
245 | + h("h2", {}, "Equality"), | |
246 | + h("p", {}, lhs), | |
247 | + h("p", {}, rhs), | |
248 | + ); | |
249 | + } | |
250 | +} | |
251 | + | |
252 | +class MakeEquality extends Component { | |
253 | + state = { expr1: "", expr2: "" }; | |
254 | + | |
255 | + onSubmit = addTile => e => { | |
256 | + const p1 = dissolve(this.state.expr1); | |
257 | + const p2 = dissolve(this.state.expr2); | |
258 | + p1.then(e1 => { | |
259 | + p2.then(e2 => { | |
260 | + console.log("makeEquality", e1, e2); | |
261 | + if (e1.index === e2.index) { | |
262 | + addTile(h(Equality, { | |
263 | + trail: `Generated from ${this.state.expr1} = ${this.state.expr2}`, | |
264 | + lhs: e1.expr, | |
265 | + rhs: e2.expr, | |
266 | + index: e1.index, | |
267 | + })); | |
268 | + } | |
269 | + }); | |
270 | + }); | |
271 | + e.preventDefault(); | |
272 | + }; | |
273 | + | |
274 | + setExpr1 = e => this.setState({ expr1: e.target.value }); | |
275 | + setExpr2 = e => this.setState({ expr2: e.target.value }); | |
276 | + | |
277 | + render({ addTile }) { | |
278 | + return h("div", { class: "tile" }, | |
279 | + h("h2", {}, "Make an Equality"), | |
280 | + h("form", { onSubmit: this.onSubmit(addTile) }, | |
281 | + h("input", { type: "textbox", onInput: this.setExpr1 }), | |
282 | + h("input", { type: "textbox", onInput: this.setExpr2 }), | |
283 | + h("button", { type: "submit" }, "Go!"), | |
284 | + ), | |
285 | + ); | |
286 | + } | |
287 | +} | |
288 | + | |
237 | 289 | class App extends Component { |
238 | 290 | state = { tiles: [] }; |
239 | 291 |
@@ -246,6 +298,7 @@ class App extends Component { | ||
246 | 298 | return [ |
247 | 299 | h(FetchTile, { addTile }), |
248 | 300 | h(AnonymousTile, { addTile }), |
301 | + h(MakeEquality, { addTile }), | |
249 | 302 | ].concat(this.state.tiles); |
250 | 303 | } |
251 | 304 | } |