• R/O
  • HTTP
  • SSH
  • HTTPS

提交

标签
No Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-cqtcocoa誰得pythonphprubygameguibathyscaphec翻訳計画中(planning stage)omegatframeworktwittertestdomvb.netdirectxbtronarduinopreviewerゲームエンジン

A categorical programming language


Commit MetaInfo

修订版7a65a2ad61556360b675678d99db2c2a3599afb8 (tree)
时间2022-02-18 14:32:04
作者Corbin <cds@corb...>
CommiterCorbin

Log Message

Split cammy-run into cammy-draw and pieces.

The parser and arrow-builder are now in their own module, so that both
cammy-draw and cammy-repl can use them. cammy-draw is finally around the
proper size, carrying proper responsibilities.

更改概述

差异

--- a/cammy-rpy/main.py
+++ b/cammy-rpy/cammylib/arrows.py
@@ -1,13 +1,10 @@
1+import math
12
2-import math, sys
3-
4-from rpython.rlib.jit import JitDriver, isconstant, set_param, unroll_safe, we_are_jitted
3+from rpython.rlib.jit import JitDriver, isconstant, we_are_jitted
54 from rpython.rlib.rbigint import rbigint
6-from rpython.rlib.rfloat import string_to_float
7-from rpython.rlib.rstring import StringBuilder, split
85
9-from cammylib.hax import patch_ctypes_for_ffi
10-from cammylib import stb
6+from cammylib.parser import Atom, Functor
7+
118
129 class TypeFail(Exception):
1310 def __init__(self, reason):
@@ -395,161 +392,15 @@ def buildCompound(name, args):
395392 else:
396393 raise BuildProblem("Invalid compound functor: " + name)
397394
398-
399-class CammyParser(object):
400-
401- def __init__(self, s):
402- self._i = 0
403- self._s = s
404-
405- def eatWhitespace(self):
406- while self._i < len(self._s) and self._s[self._i] in (" ", "\n"):
407- self._i += 1
408-
409- def canAndDoesEat(self, c):
410- if self._s[self._i] == c:
411- self._i += 1
412- return True
413- else:
414- return False
415-
416- def takeName(self):
417- start = self._i
418- while self._i < len(self._s) and self._s[self._i] not in (")", "(", " ", "\n"):
419- self._i += 1
420- stop = self._i
421- return self._s[start:stop]
422-
423- def takeExpression(self):
424- self.eatWhitespace()
425- if self.canAndDoesEat('('):
426- return self.startFunctor()
427- else:
428- return buildUnary(self.takeName())
429-
430- def startFunctor(self):
431- head = self.takeName()
432- self.eatWhitespace()
433- args = []
434- while not self.canAndDoesEat(')'):
435- args.append(self.takeExpression())
436- return buildCompound(head, args)
437-
438-
439-def parse(s):
395+def buildArrow(sexp):
440396 try:
441- return CammyParser(s).takeExpression()
397+ if isinstance(sexp, Atom):
398+ return buildUnary(sexp.symbol)
399+ elif isinstance(sexp, Functor):
400+ args = [buildArrow(arg) for arg in sexp.arguments]
401+ return buildCompound(sexp.constructor, args)
402+ else:
403+ assert False, "inconceivable"
442404 except BuildProblem as bp:
443- print "Couldn't parse Cammy expression:", bp.message
444-
445-
446-# Borrowed from stub.scm and Typhon's colors.mt
447-
448-def scale(bot, top, x):
449- d = top - bot
450- return bot + d * x
451-
452-def linear2sRGB(u):
453- try:
454- return u * 25 / 323 if u <= 0.04045 else math.pow((u * 200 + 11) / 211, 12 / 5)
455- except OverflowError:
456- return 1.0
457-
458-def finishChannel(c):
459- return int(255 * max(0.0, min(1.0, linear2sRGB(c))))
460-
461-# Pixel area: 4 / (w * h)
462-# Pixel radius: √(area / pi) = 2 / √(w * h * pi) = (2 / √pi) / √(w * h)
463-# This constant is the first half of that.
464-TWOSQRTPI = 2.0 / math.sqrt(math.pi)
465-
466-class Window(object):
467- _immutable_ = True
468-
469- def __init__(self, corners, width, height):
470- self._corners = corners[0], corners[1], corners[2], corners[3]
471- self._w = width
472- self._h = height
473- area = abs((corners[0] - corners[2]) * (corners[1] - corners[3]))
474- self.pixelRadius = TWOSQRTPI * area / math.sqrt(width * height)
475-
476- def coordsForPixel(self, i):
477- w = i % self._w
478- h = i // self._w
479- iw = 1.0 / self._w
480- dw = 0.5 * iw
481- ih = 1.0 / self._h
482- dh = 0.5 * ih
483- c1 = scale(self._corners[0], self._corners[2], dw + iw * w)
484- c2 = scale(self._corners[1], self._corners[3], dh + ih * h)
485- return c1, c2
486-
487-sample_driver = JitDriver(name="sample",
488- greens=["program"], reds=["x", "y"],
489- is_recursive=True)
490-
491-def sample(program, x, y):
492- sample_driver.jit_merge_point(program=program, x=x, y=y)
493- rgb = program.run(P(F(x), F(y)))
494- r = rgb.first().f()
495- g = rgb.second().first().f()
496- b = rgb.second().second().f()
497- return r, g, b
498-
499-offsets = [(0.0, 0.0), (1.0, 1.0), (1.0, -1.0), (-1.0, 1.0), (-1.0, -1.0)]
500-
501-@unroll_safe
502-def multisample(program, radius, x, y):
503- r = g = b = 0.0
504- for ox, oy in offsets:
505- sr, sg, sb = sample(program, x + radius * ox, y + radius * oy)
506- r += sr
507- g += sg
508- b += sb
509- l = len(offsets)
510- return finishChannel(r / l), finishChannel(g / l), finishChannel(b / l)
511-
512-def drawPixels(size, program, window):
513- sb = StringBuilder()
514- i = 0
515- while i < size:
516- c1, c2 = window.coordsForPixel(i)
517- r, g, b = multisample(program, window.pixelRadius, c1, c2)
518- sb.append(chr(r) + chr(g) + chr(b))
519- i += 1
520- return sb.build()
521-
522-def drawPNG(program, filename, corners, width, height):
523- window = Window(corners, width, height)
524- size = width * height
525- buf = drawPixels(size, program, window)
526- channels = 3
527- stb.i_write_png(filename, width, height, channels, buf, width * channels)
528-
529-
530-def main(argv):
531- set_param(None, "trace_limit", 50001)
532-
533- prog = argv[1]
534- window = [string_to_float(s) for s in split(argv[2])]
535- width = int(argv[3])
536- height = int(argv[4])
537- out = argv[5]
538- with open(prog) as handle:
539- func = parse(handle.read())
540- try:
541- drawPNG(func, out, window, width, height)
542- except TypeFail as tf:
543- print "Type failure:", tf.reason
405+ print "Couldn't find Cammy expression:", bp.message
544406 raise
545- return 0
546-
547-
548-def target(driver, *args):
549- patch_ctypes_for_ffi()
550- driver.exe_name = "cammy-run"
551- return main, None
552-
553-
554-if __name__ == "__main__":
555- sys.exit(main(sys.argv))
--- /dev/null
+++ b/cammy-rpy/cammylib/parser.py
@@ -0,0 +1,53 @@
1+from cammylib.sexp import Atom, Functor
2+
3+
4+class CammyParser(object):
5+
6+ def __init__(self, s):
7+ self._i = 0
8+ self._s = s
9+
10+ def position(self):
11+ return self._i
12+
13+ def eatWhitespace(self):
14+ while self._i < len(self._s) and self._s[self._i] in (" ", "\n"):
15+ self._i += 1
16+
17+ def canAndDoesEat(self, c):
18+ if self._s[self._i] == c:
19+ self._i += 1
20+ return True
21+ else:
22+ return False
23+
24+ def takeName(self):
25+ start = self._i
26+ while self._i < len(self._s) and self._s[self._i] not in (")", "(", " ", "\n"):
27+ self._i += 1
28+ stop = self._i
29+ return self._s[start:stop]
30+
31+ def takeExpression(self):
32+ self.eatWhitespace()
33+ if self.canAndDoesEat('('):
34+ return self.startFunctor()
35+ else:
36+ return Atom(self.takeName())
37+
38+ def startFunctor(self):
39+ head = self.takeName()
40+ self.eatWhitespace()
41+ args = []
42+ while not self.canAndDoesEat(')'):
43+ args.append(self.takeExpression())
44+ return Functor(head, args)
45+
46+
47+def parse(s):
48+ parser = CammyParser(s)
49+ sexp = parser.takeExpression()
50+ # Parser is now fast-forwarded to the end of the S-expression, so we can
51+ # slice from that point and get the docstring/etc.
52+ trail = s[parser.position():]
53+ return sexp, trail
--- /dev/null
+++ b/cammy-rpy/cammylib/sexp.py
@@ -0,0 +1,19 @@
1+class SExp(object):
2+ "An S-expression."
3+
4+class Atom(SExp):
5+ "An S-expression atom."
6+
7+ _immutable_fields_ = "symbol",
8+
9+ def __init__(self, symbol):
10+ self.symbol = symbol
11+
12+class Functor(SExp):
13+ "A list of S-expressions with a distinguished head."
14+
15+ _immutable_fields_ = "constructor", "arguments[:]",
16+
17+ def __init__(self, constructor, arguments):
18+ self.constructor = constructor
19+ self.arguments = arguments
--- a/cammy-rpy/default.nix
+++ /dev/null
@@ -1,5 +0,0 @@
1-{ nixpkgs ? import <nixpkgs> {} }:
2-let
3- makeBuilder = import ./builder.nix { inherit nixpkgs; };
4-in
5- makeBuilder ./main.py "cammy-run" true
--- a/cammy-rpy/repl.py
+++ b/cammy-rpy/repl.py
@@ -2,20 +2,35 @@
22
33 from rpython.rlib.rfile import create_stdio
44
5+from cammylib.arrows import buildArrow, BuildProblem
6+from cammylib.parser import parse
7+
58 LINE_BUFFER_LENGTH = 1024
69
710 def repl(stdin, stdout):
811 while True:
912 stdout.write("> ")
1013 line = stdin.readline(LINE_BUFFER_LENGTH)
11- print line
14+ if not line:
15+ # Empty read means EOF.
16+ break
17+ sexp, trail = parse(line)
18+ print "Got:", line
19+ print "S-expression:", sexp
20+ print "Trail:", trail
21+ try:
22+ arrow = buildArrow(sexp)
23+ print "Arrow:", arrow
24+ except BuildProblem as bp:
25+ print "Couldn't build arrow:", bp.message
26+ return 0
1227
1328 def main(argv):
1429 stdin, stdout, stderr = create_stdio()
1530 try:
16- repl(stdin, stdout)
31+ return repl(stdin, stdout)
1732 except:
18- return 0
33+ return 1
1934
2035 def target(driver, *args):
2136 driver.exe_name = "cammy-repl"
--- a/default.nix
+++ b/default.nix
@@ -4,7 +4,7 @@ let
44 frame = import ./frame { inherit nixpkgs; };
55 jelly = (import jelly/Cargo.nix { pkgs = nixpkgs; }).rootCrate.build;
66 movelist = import ./movelist { inherit nixpkgs; };
7- cammy-run = import ./cammy-rpy { inherit nixpkgs; };
7+ cammy-draw = import ./cammy-rpy/draw.nix { inherit nixpkgs; };
88 cammy-repl = import ./cammy-rpy/repl.nix { inherit nixpkgs; };
99 eggs = builtins.attrValues (removeAttrs (import ./eggs.nix {
1010 inherit pkgs;
@@ -46,7 +46,7 @@ in pkgs.stdenv.mkDerivation {
4646
4747 makeWrapper ${movelist}/bin/movelist $out/bin/cammy-movelist
4848
49- makeWrapper ${cammy-run}/bin/cammy-run $out/bin/cammy-draw
49+ makeWrapper ${cammy-draw}/bin/cammy-draw $out/bin/cammy-draw
5050 makeWrapper ${cammy-repl}/bin/cammy-repl $out/bin/cammy-repl
5151 '';
5252 }
--- a/shell.nix
+++ b/shell.nix
@@ -17,6 +17,10 @@ in pkgs.stdenv.mkDerivation {
1717 egg2nix
1818 # maintaining frame/
1919 ocamlformat
20+ # maintaining cammy-rpy/
21+ pythonPackages.pyflakes
22+ # using cammy-repl
23+ rlwrap
2024 # working with sexps
2125 ocamlPackages.sexp
2226 # benchmarking
--- a/todo.txt
+++ b/todo.txt
@@ -44,3 +44,7 @@
4444 * Interval type?
4545 * Cantor's type of bitstrings: N -> 2
4646 * The square type: For a type X, 2 -> X
47+* The double type: For a type X, X + X
48+* Moore machines: For state type Q and input type S, Q × S -> Q
49+ * Moore transducers: [Q × S, Q] -> [Q × S, Q]
50+* Mealy machines: For state type Q, input type S, and output type L, Q × S -> Q × L