Skip to content

Commit 34743f2

Browse files
committed
Update README, fix -f, tidy up
1 parent 8446d19 commit 34743f2

6 files changed

Lines changed: 91 additions & 71 deletions

File tree

README.md

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# rueltabel
2-
A compiler for a reimagined Golly ruletable language to the traditional format. See [`examples/`](/examples) for examples.
2+
A transpiler from a reimagined Golly ruletable language to the traditional format. See [`examples/`](/examples) for examples.
33

44
## Setup
55

@@ -15,8 +15,18 @@ A compiler for a reimagined Golly ruletable language to the traditional format.
1515
$ python to_ruletable.py [infile] [outdir] [flags...]
1616
```
1717
The output file will be written to `outdir` with a .rule extension and the same filename as `infile`.
18-
Currently, the only supported flag is `-v` (`--verbose`), which will cause more info to be printed the
19-
more it is repeated (up to three repetitions).
18+
Supported flags:
19+
- `-v`: Verbose. Can be repeated up to four times, causing more info to be displayed each time.
20+
- `-t [HEADER]`: Change the "COMPILED FROM RUELTABEL" header that is added by default to transpiled
21+
rules. (If `-t` is given no argument the header will be removed)
22+
- `-f TRANSITION`: Find a certain transition defined within a tabel section; requires, of course, that
23+
the rule have a `@TABEL` section to search within. Makes it so that, if a certain
24+
cell isn't behaving the way it's supposed to, you can `-f` the transition it's
25+
undergoing and the script will find the offending transition for you (instead of
26+
making you guess at what you typo'd).
27+
Transition should be given in the standard Golly form `C,N,...,C'` -- that is, state of the
28+
current center cell, then its neighborhood, and finally the state it transitions into
29+
on the next tick. Example [here](https://user-images.githubusercontent.com/32081933/39951382-2b37fca0-553e-11e8-87b5-69685dfe4881.png)!
2030

2131
## Spec
2232
- All variables unbound by default, because needing to define eight "any state" vars is ridiculous.
@@ -104,6 +114,19 @@ foo, N..NW bar, baz -> S:2 E[(2, 3)] SE[wutz] N[NE: (2, 3)] NE[E]
104114
- Support switching symmetries partway through via the `symmetries:` directive. (When parsing, this results in all transitions being expanded to the 'lowest'
105115
symmetry type specified overall.)
106116

117+
## Non-table-related changes
118+
- The `@COLORS` segment in a ruelfile allows multiple states with the same color to be defined as such
119+
on the same line as each other, and for colors to be written as either base-10 `R G B` values or as
120+
hexadecimal color codes. `1 10: FFF`, for instance, says to assign the color `#FFFFFF` to states 1 and
121+
10, and can also be written as `1 10: FFFFFF` or `1 10: 255 255 255` (or as two separate lines, although
122+
the colon is still mandatory). Comments in this segment start with `#` and go until the end of their line.
123+
- The `@ICONS` segment uses an ad-hoc RLE syntax instead of Gollyesque XPM data. See [this post](http://conwaylife.com/forums/viewtopic.php?f=7&t=3361&p=59944#p59944)
124+
for an explanation + example.
125+
- **All segments are optional**. The parser will also transcribe unidentified segments as is, meaning that
126+
a file can have a `@TABLE` segment (under which the normal Golly ruletable language is used) rather than
127+
`@TABEL` and it will not be modified by the parser.
128+
- Specially-treated ruel segments whose names are not respellings, like `@ICONS` and `@COLORS`, will still be
129+
ignored by the parser if their header is immediately followed by the comment `#golly`, either on the same line (after whitespace) or on the line immediately below.
107130

108131
## To do
109132
- DOCS! Or at least a proper introductory writeup.

examples/compiled_ruletables/bct.rule

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,11 @@ var any_7 = any_0
7070

7171
var live_0 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}
7272

73-
var _233626425726624_0 = {14, 15}
73+
var _149636772488731_0 = {14, 15}
7474

75-
var _227631875077152_0 = {3, 4}
75+
var _764365149070759_0 = {3, 4}
7676

77-
var _328669587150795_0 = {10, 11}
77+
var _945675959837757_0 = {10, 11}
7878

7979
vacddata_0, 1, any_0, any_1, any_2, any_3, any_4, any_5, 5, 16
8080
vacddata_0, 2, any_0, any_1, any_2, any_3, any_4, any_5, 5, 17
@@ -87,7 +87,7 @@ vacrdata_0, any_0, any_1, any_2, any_3, any_4, any_5, rdata_0, any_6, rdata_0
8787
rdata_0, any_0, any_1, any_2, any_3, any_4, any_5, 0, any_6, 0
8888
0, 5, any_0, any_1, any_2, any_3, any_4, 0, rdata_0, 14
8989
0, 5, data_0, 0, any_0, any_1, any_2, any_3, any_4, 14
90-
_233626425726624_0, any_0, any_1, any_2, any_3, any_4, any_5, any_6, any_7, 0
90+
_149636772488731_0, any_0, any_1, any_2, any_3, any_4, any_5, any_6, any_7, 0
9191
any_0, 14, any_1, any_2, __all__0, __all__1, __all__2, any_3, any_4, 15
9292
any_0, 15, any_1, any_2, __all__0, __all__1, __all__2, any_3, any_4, 5
9393
5, 0, 0, 0, ddata_0, 0, 0, 0, 0, 0
@@ -106,7 +106,7 @@ data_0, any_0, any_1, 5, any_2, any_3, any_4, any_5, any_6, 0
106106
0, 8, any_0, any_1, __all__0, __all__1, __all__2, any_2, any_3, 10
107107
9, any_0, any_1, any_2, any_3, any_4, any_5, any_6, any_7, 2
108108
0, 9, any_0, any_1, __all__0, __all__1, __all__2, any_2, any_3, 11
109-
_328669587150795_0, any_0, any_1, any_2, any_3, any_4, any_5, any_6, any_7, 0
109+
_945675959837757_0, any_0, any_1, any_2, any_3, any_4, any_5, any_6, any_7, 0
110110
any_0, 10, any_1, any_2, __all__0, __all__1, __all__2, any_3, any_4, 3
111111
any_0, 11, any_1, any_2, __all__0, __all__1, __all__2, any_3, any_4, 4
112112
data_0, any_0, any_1, 0, any_2, data_1, any_3, any_4, any_5, data_1
@@ -123,14 +123,14 @@ vacdata_0, any_0, any_1, vacdata_1, any_2, any_3, any_4, any_5, any_6, vacdata_1
123123

124124

125125
@COLORS
126-
1 235 235 235 lighter gray
127-
2 30 30 30 darker gray
128-
12 235 235 235 lighter gray
129-
13 30 30 30 darker gray
130-
16 235 235 235 lighter gray
131-
17 30 30 30 darker gray
132-
3 200 200 200 light gray
133-
4 90 90 90 dark gray
134-
5 0 255 255 cyan
135-
14 0 255 255 cyan
136-
15 0 255 255 cyan
126+
3 200 200 200
127+
4 90 90 90
128+
1 235 235 235
129+
12 235 235 235
130+
16 235 235 235
131+
2 30 30 30
132+
13 30 30 30
133+
17 30 30 30
134+
5 0 255 255
135+
14 0 255 255
136+
15 0 255 255

examples/rueltabels/Simpl.ruel

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,16 @@ off = {0..10}
4242

4343

4444
@COLORS
45-
0: 808080
46-
1: 000
47-
2: 6E0000
48-
3: 6E4800
49-
4: 486E00
50-
5: 006E00
51-
6: 006E48
52-
7: 00486E
53-
8: 00006E
54-
9: 48006E
45+
0: 808080
46+
1: 000
47+
2: 6E0000
48+
3: 6E4800
49+
4: 486E00
50+
5: 006E00
51+
6: 006E48
52+
7: 00486E
53+
8: 00006E
54+
9: 48006E
5555
10: 6E0048
5656
11: FFC8C8
5757
12: FFECC8

examples/rueltabels/bct.ruel

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
@RUEL bct
2-
32
An implementation of bitwise cyclic tag.
43

54
state 0: Vacuum.
@@ -12,8 +11,6 @@ state 4: Program-tape 1.
1211

1312
state 5: Shifter. Moves both itself and the data tape one unit down to render program execution cyclic.
1413

15-
16-
1714
state 6: Transitory program-tape 0.
1815
state 7: Transitory program-tape 1.
1916

@@ -32,31 +29,27 @@ state 15: Ditto but about to turn into normal reflector.
3229
state 16: To-be-moved-down data-tape 0.
3330
state 17: To-be-moved-down data-tape 1.
3431

35-
@COLORS: golly
36-
1 235 235 235 lighter gray
37-
2 30 30 30 darker gray
38-
12 235 235 235 lighter gray
39-
13 30 30 30 darker gray
40-
16 235 235 235 lighter gray
41-
17 30 30 30 darker gray
42-
3 200 200 200 light gray
43-
4 90 90 90 dark gray
44-
5 0 255 255 cyan
45-
14 0 255 255 cyan
46-
15 0 255 255 cyan
32+
@COLORS
33+
3: C8C8C8 # light gray
34+
4: 5A5A5A # dark gray
35+
1 12 16: EBEBEB # lighter gray
36+
2 13 17: 1E1E1E # darker gray
37+
5 14 15: 00FFFF # cyan
4738

4839
@TABEL
4940
states: 18
5041
neighborhood: Moore
5142
symmetries: none
5243

44+
5345
data = {1, 2}
5446
rdata = {12, 13}
5547
ddata = {16, 17}
56-
vacdata = {0, 1, 2}
48+
vacdata = {0..2}
5749
vacrdata = {0, 12, 13}
5850
vacddata = {0, 16, 17}
5951

52+
6053
# If a shifter is encountered, reflect + shift data tape down 2 cell
6154
# go right
6255
vacddata, (1, 2), NE..W any, 5, [N: (16, 17)]
@@ -72,20 +65,20 @@ rdata, any, any, any, any, any, any, 0, any, 0
7265

7366
# shift the shifter down two as well
7467
# right
75-
0, 5, any, any, any, any, any, 0, rdata, 14
68+
0, 5, NE..SW any, 0, rdata, 14
7669
# left
77-
0, 5, data, 0, any, any, any, any, any, 14
70+
0, 5, data, 0, SE..NW any, 14
7871
# finally
7972
(14, 15), N..NW any, 0 -> S[0: (15, 5)]
8073
# delete shifter at end of its input stream
81-
5, 0, 0, 0, ddata, 0, 0, 0, 0, 0
82-
5, 0, 0, 0, 0, 0, data, 0, 0, 0
74+
5, N..E 0, SE ddata, S..NW 0, 0
75+
5, N..S 0, data, 0, 0, 0
8376

8477
# Shift prgm tape down 1 if rightward data above it
8578
(3, 4), rdata, NE..NW any, [0: (10, 11)]
8679

8780
# If a data bit has a shifter to its right, don't attempt to copy it
88-
data, any, any, 5, any, any, any, any, any, 0
81+
data, N..NE any, E 5, SE..NW any, 0
8982

9083
# If a prgm-tape 1 is encountered, shift it downward
9184
# and append the command to its left (by copying+shifting down) onto the right end of the data tape,

magic/segment_types/icons.py

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ def lazylen(iterable):
2323
return sum(1 for _ in iterable)
2424

2525

26+
def maybe_double(symbol: str):
27+
if len(symbol.encode()) < 2:
28+
return symbol * 2
29+
return symbol
30+
31+
2632
class Icon:
2733
HEIGHT = None
2834
_FILL = None
@@ -34,7 +40,7 @@ def __init__(self, rle):
3440
self._FILL = ['..' * self.HEIGHT]
3541
self._rle = rle
3642
self._split =''.join(
37-
(val * 2 if len(val.encode()) < 2 else val) * int(run_length or 1)
43+
maybe_double(val) * int(run_length or 1)
3844
for run_length, val in
3945
self._rRUNS.findall(self._rle)
4046
).split('$$')
@@ -50,9 +56,7 @@ def set_height(cls, dims):
5056

5157
@classmethod
5258
def solid_color(cls, color):
53-
if len(color.encode()) < 2:
54-
color *= 2
55-
return [color * cls.HEIGHT] * cls.HEIGHT
59+
return [maybe_double(color) * cls.HEIGHT] * cls.HEIGHT
5660

5761
def _pad(self):
5862
# Horizontal padding
@@ -87,13 +91,15 @@ def __iter__(self):
8791
# /* width height num_colors chars_per_pixel */
8892
yield f'"{Icon.HEIGHT} {len(self.icons)*Icon.HEIGHT} {len(self.colormap)} 2"'
8993
# /* colors */
90-
yield from (f'"{(symbol * 2 if len(symbol.encode()) < 2 else symbol)} c #{color}"' for symbol, color in self.colormap.items())
94+
yield from (f'"{maybe_double(symbol)} c #{color}"' for symbol, color in self.colormap.items())
9195
# /* icons */
9296
yield from (f'"{line}"' for icon in (self.icons[key] for key in sorted(self.icons)) for line in icon)
9397

94-
@staticmethod
95-
def _make_name():
96-
return ''.join(random.sample(SAFE_CHARS, 2))
98+
def _make_color_symbol(self):
99+
name = ''.join(random.sample(SAFE_CHARS, 2))
100+
while name in self.colormap.values():
101+
name = ''.join(random.sample(SAFE_CHARS, 2))
102+
return name
97103

98104
def _parse_colors(self, start=0):
99105
lno, colormap = start, {}
@@ -106,7 +112,7 @@ def _parse_colors(self, start=0):
106112
state, color = match.groups()
107113
if len(color) < 6:
108114
color *= 2
109-
colormap[SYMBOL_MAP[int(state)] if state.isdigit() else state * 2 if len(state.encode()) < 2 else state] = color.upper()
115+
colormap[SYMBOL_MAP[int(state)] if state.isdigit() else maybe_double(state)] = color.upper()
110116
return colormap, lno
111117

112118
def _sep_states(self, start) -> dict:
@@ -131,9 +137,6 @@ def _fill_missing_states(self):
131137
color = self._parsed_color_segment[state]
132138
except KeyError:
133139
raise TabelReferenceError(self._start, f'No @ICONS-defined icon (and, subsequently, no substitute @COLORS-defined fill color) found for state {state}')
134-
_name = self._make_name()
135-
while _name in self.colormap.values():
136-
_name = self._make_name()
137-
symbol = _colormap_inv.get(color, _name)
140+
symbol = _colormap_inv.get(color, self._make_color_symbol())
138141
self.colormap[symbol] = color
139-
self.icons[state] = Icon.solid_color(symbol)
142+
self.icons[state] = list(Icon.solid_color(symbol))

magic/segment_types/table.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -115,13 +115,14 @@ def match(self, tr):
115115
for lno, tr in self.transitions
116116
)
117117
for idx, (lno, tr) in _trs_no_names:
118-
for in_state, tr_state in (zip(in_tr, tr) for in_tr in ((start, *napkin, end) for napkin in in_napkins.expand())):
119-
while isinstance(tr_state, str):
120-
tr_state = tr[int(tr_state)]
121-
if not (in_state == tr_state if isinstance(tr_state, int) else in_state in tr_state):
122-
break
123-
else:
124-
return f'Found!\n\nLine {1+self._start+lno}: "{self[lno]}"\n(compiled line "{", ".join(map(str, self.transitions[idx][1]))}")\n'
118+
for in_tr in ((start, *napkin, end) for napkin in in_napkins.expand()):
119+
for in_state, tr_state in zip(in_tr, tr):
120+
while isinstance(tr_state, str): # binding
121+
tr_state = tr[int(tr_state)]
122+
if not (in_state == tr_state if isinstance(tr_state, int) else in_state in tr_state):
123+
break
124+
else:
125+
return f'Found!\n\nLine {1+self._start+lno}: "{self._tbl[lno]}"\n(compiled line "{", ".join(map(str, self.transitions[idx][1]))}")\n'
125126
return None
126127

127128
def _cardinal_sub(self, match):

0 commit comments

Comments
 (0)