A categorical programming language
Révision | d69bf980c4d66a809825c8cbe85914b04004fad5 (tree) |
---|---|
l'heure | 2022-08-14 13:35:28 |
Auteur | Corbin <cds@corb...> |
Commiter | Corbin |
Hack up a basic concept for a packed JSON hive.
@@ -0,0 +1,106 @@ | ||
1 | +#!/usr/bin/env nix-shell | |
2 | +#! nix-shell -i python3 -p python3 | |
3 | + | |
4 | +import json | |
5 | +import os | |
6 | +import sys | |
7 | + | |
8 | +class CammyParser: | |
9 | + def __init__(self, s): | |
10 | + self._i = 0 | |
11 | + self._s = s | |
12 | + | |
13 | + def position(self): | |
14 | + return self._i | |
15 | + | |
16 | + def hasMore(self): | |
17 | + return self._i < len(self._s) | |
18 | + | |
19 | + def eatWhitespace(self): | |
20 | + while self.hasMore() and self._s[self._i] in (" ", "\n"): | |
21 | + self._i += 1 | |
22 | + | |
23 | + def canAndDoesEat(self, c): | |
24 | + if self._s[self._i] == c: | |
25 | + self._i += 1 | |
26 | + return True | |
27 | + else: | |
28 | + return False | |
29 | + | |
30 | + def takeName(self): | |
31 | + start = self._i | |
32 | + while self.hasMore() and self._s[self._i] not in (")", "(", " ", "\n"): | |
33 | + self._i += 1 | |
34 | + stop = self._i | |
35 | + return self._s[start:stop] | |
36 | + | |
37 | + def takeExpression(self): | |
38 | + self.eatWhitespace() | |
39 | + if self.canAndDoesEat('('): | |
40 | + return self.startFunctor() | |
41 | + else: | |
42 | + return self.takeName() | |
43 | + | |
44 | + def startFunctor(self): | |
45 | + start = self._i | |
46 | + head = self.takeName() | |
47 | + self.eatWhitespace() | |
48 | + args = [] | |
49 | + while not self.canAndDoesEat(')'): | |
50 | + args.append(self.takeExpression()) | |
51 | + self.eatWhitespace() | |
52 | + if not self.hasMore(): | |
53 | + raise ValueError("Unterminated functor starting at %d" % start) | |
54 | + return tuple([head] + args) | |
55 | + | |
56 | + | |
57 | +def parse(s): | |
58 | + "Parse a Cammy expression, preserving any trailing text." | |
59 | + parser = CammyParser(s) | |
60 | + sexp = parser.takeExpression() | |
61 | + # Parser is now fast-forwarded to the end of the S-expression, so we can | |
62 | + # slice from that point and get the docstring/etc. | |
63 | + trail = s[parser.position():] | |
64 | + return sexp, trail | |
65 | + | |
66 | +symbols = {} | |
67 | +heap = [] | |
68 | + | |
69 | +strs = {} | |
70 | +tuples = {} | |
71 | + | |
72 | +def merge(sexp): | |
73 | + if isinstance(sexp, str): | |
74 | + if sexp not in strs: | |
75 | + strs[sexp] = len(heap) | |
76 | + heap.append(sexp) | |
77 | + return strs[sexp] | |
78 | + elif isinstance(sexp, tuple): | |
79 | + merged = tuple([sexp[0]] + [merge(arg) for arg in sexp[1:]]) | |
80 | + if merged not in tuples: | |
81 | + tuples[merged] = len(heap) | |
82 | + heap.append(merged) | |
83 | + return tuples[merged] | |
84 | + else: | |
85 | + raise ValueError("not sure how to merge", sexp) | |
86 | + | |
87 | + | |
88 | +hiveroot = sys.argv[-1] | |
89 | +for root, dirs, files in os.walk(hiveroot): | |
90 | + for file in files: | |
91 | + path = os.path.join(root, file) | |
92 | + key = os.path.splitext(path)[0][len(hiveroot):] | |
93 | + with open(path, "r") as handle: | |
94 | + sexp, trail = parse(handle.read()) | |
95 | + symbols[key] = merge(sexp), trail | |
96 | + | |
97 | +# Fixup aliased symbols. | |
98 | +for i, cell in enumerate(heap): | |
99 | + if cell in symbols: | |
100 | + heap[i] = symbols[cell][0] | |
101 | + | |
102 | + | |
103 | +print(json.dumps({ | |
104 | + "symbols": symbols, | |
105 | + "heap": heap, | |
106 | +})) |
@@ -26,6 +26,8 @@ in pkgs.stdenv.mkDerivation { | ||
26 | 26 | rlwrap |
27 | 27 | # working with sexps |
28 | 28 | # ocamlPackages.sexp |
29 | + # working with JSON | |
30 | + jq | |
29 | 31 | # benchmarking |
30 | 32 | busybox feedgnuplot linuxPackages.perf |
31 | 33 | # publishing |