Mercurial > repo
comparison bin/gs2.py @ 9075:c989a1669243
<fizzie> revert 58b9ee8f97a7
author | HackBot |
---|---|
date | Sun, 25 Sep 2016 20:31:46 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
9074:560a73f4f0a4 | 9075:c989a1669243 |
---|---|
1 # gs2 interpreter (version 0.2) | |
2 # (c) nooodl 2014 | |
3 | |
4 import copy | |
5 import inspect | |
6 import itertools as it | |
7 import math | |
8 import operator | |
9 import os | |
10 import random | |
11 import re | |
12 import string | |
13 import struct | |
14 import sys | |
15 import traceback | |
16 | |
17 from collections import namedtuple | |
18 from fractions import gcd | |
19 | |
20 Block = namedtuple('Block', 'code') | |
21 STRING_ENDS = '\x05\x06' + ''.join(map(chr, range(0x9b, 0xa0))) | |
22 | |
23 DEBUG = False | |
24 | |
25 def log(x): | |
26 if not DEBUG: return | |
27 line, name = inspect.stack()[1][2:4] | |
28 sys.stderr.write('\x1b[36m%s:%d\x1b[34m: %r\x1b[0m\n' % (name, line, x)) | |
29 | |
30 def lcm(a, b): | |
31 if (a, b) == (0, 0): return 0 | |
32 return abs(a * b) // gcd(a, b) | |
33 | |
34 def product(xs): | |
35 p = 1 | |
36 for x in xs: | |
37 p *= x | |
38 return p | |
39 | |
40 def split(a, b, clean=False): | |
41 res = [[]] | |
42 lb = len(b) | |
43 | |
44 i = 0 | |
45 while i < len(a): | |
46 if a[i:i + lb] == b: | |
47 res.append([]) | |
48 i += lb | |
49 else: | |
50 res[-1].append(a[i]) | |
51 i += 1 | |
52 | |
53 return filter(None, res) if clean else res | |
54 | |
55 def join(a, b): | |
56 res = [] | |
57 for i, x in enumerate(a): | |
58 if i > 0: | |
59 res.extend(b) | |
60 res.extend(x if is_list(x) else [x]) | |
61 return res | |
62 | |
63 def set_diff(a, b): | |
64 res = [] | |
65 for i in a: | |
66 if i not in b: | |
67 res.append(i) | |
68 return res | |
69 | |
70 def set_and(a, b): | |
71 res = [] | |
72 for i in a: | |
73 if i in b: | |
74 res.append(i) | |
75 return res | |
76 | |
77 def set_or(a, b): | |
78 return a + set_diff(b, a) | |
79 | |
80 def set_xor(a, b): | |
81 return set_diff(a, b) + set_diff(b, a) | |
82 | |
83 # prime number functions | |
84 prime_list = [] | |
85 sieved = 2 | |
86 composite = set([1]) | |
87 | |
88 def sieve(limit): | |
89 global prime_list | |
90 global sieved | |
91 global composite | |
92 if limit <= sieved: return | |
93 | |
94 prime_list = [] | |
95 for i in range(2, limit): | |
96 if i in composite: continue | |
97 for j in range(i*i, limit, i): | |
98 composite.add(j) | |
99 prime_list.append(i) | |
100 sieved = limit | |
101 | |
102 sieve(1000) | |
103 | |
104 def is_prime(n): | |
105 global prime_list | |
106 sieve(n+1) | |
107 return n not in composite | |
108 | |
109 def nth_prime(n): | |
110 global prime_list | |
111 sieve(int(math.log(n) * n) + 100) | |
112 return prime_list[n-1] | |
113 | |
114 def n_primes(n): | |
115 global prime_list | |
116 sieve(int(math.log(n) * n) + 100) | |
117 return prime_list[:n] | |
118 | |
119 def primes_below(n): | |
120 global prime_list | |
121 sieve(n+1) | |
122 return list(it.takewhile(lambda x: x < n, prime_list)) | |
123 | |
124 def next_prime(n): | |
125 n += 1 | |
126 while not is_prime(n): n += 1 | |
127 return n | |
128 | |
129 def totient(n): | |
130 count = 0 | |
131 for i in xrange(1, n+1): | |
132 if gcd(n, i) == 1: count += 1 | |
133 return count | |
134 | |
135 def factor(n, exps=False): | |
136 if is_num(n): | |
137 p = 2 | |
138 res = [] | |
139 while n > 1: | |
140 while n % p == 0: | |
141 res.append(p) | |
142 n //= p | |
143 p = next_prime(p) | |
144 if exps: | |
145 res = [[k, len(list(g))] for k, g in it.groupby(res)] | |
146 return res | |
147 elif is_list(n): | |
148 if n and is_num(n[0]): | |
149 n = zip(n[0::2], n[1::2]) | |
150 p = 1 | |
151 for b, e in n: p *= b ** e | |
152 return p | |
153 else: | |
154 raise TypeError('factor') | |
155 | |
156 def chunks(x, y): | |
157 # chunks(range(12), 3) ==> [[0, 1, 2], [3, 4, 5], ...] | |
158 while x: | |
159 yield x[:y] | |
160 x = x[y:] | |
161 | |
162 def tokenize(prog): | |
163 # string hack | |
164 cs = STRING_ENDS | |
165 if re.match('^[^\x04]*[%s]' % cs, prog): | |
166 prog = '\x04' + prog | |
167 | |
168 mode = None | |
169 if prog[0] in '\x30\x31\x32': # set mode | |
170 mode = prog[0] | |
171 prog = prog[1:] | |
172 | |
173 token_re = [ | |
174 '\x04[^%s]*[%s]' % (cs, cs), # string (array) | |
175 '\x01.', # unsigned byte | |
176 '\x02..', # signed short | |
177 '\x03....', # signed long | |
178 '\x07.', # 1 char string | |
179 '.', # regular token | |
180 ] | |
181 | |
182 tokens = re.findall('|'.join(token_re), prog, re.DOTALL) | |
183 | |
184 final = [] | |
185 blocks = [Block([])] | |
186 i = 0 | |
187 while i < len(tokens): | |
188 t = tokens[i] | |
189 log(tokens[i:]) | |
190 if t == '\x08': #= { | |
191 blocks.append(Block([])) | |
192 final.append('\x00') | |
193 elif t == '\x09': #= } | |
194 blocks[-2].code.append(blocks.pop()) | |
195 blocks[-1].code.append(final.pop()) | |
196 elif '\xe0' <= t <= '\xff' and ord(t) & 7 < 6: | |
197 # quick block | |
198 # 0b111XXYYY -- Y+1 is number of tokens, X is end token: | |
199 # 0 = nop (0x00) 2 = filter (0x35) | |
200 # 1 = map (0x34) 3 = both (0x38) | |
201 # but 0xfe and 0xff are special (see below.) | |
202 num = (ord(t) & 7) + 1 | |
203 ts = blocks[-1].code[-num:] | |
204 del blocks[-1].code[-num:] | |
205 blocks[-1].code.append(Block(ts)) | |
206 blocks[-1].code.append('\x00\x34\x35\x38'[(ord(t) >> 3) & 3]) | |
207 elif t in '\xee\xef': #= z1 zipwith1, z2 zipwith2 | |
208 # zipwith (1/2 tokens) | |
209 num = (ord(t) & 1) + 1 | |
210 ts = blocks[-1].code[-num:] | |
211 del blocks[-1].code[-num:] | |
212 blocks[-1].code.append(Block(ts)) | |
213 blocks[-1].code.append('\xb1') | |
214 elif t in '\xf6\xf7': #= dm1 dump-map1, df1 dump-filter1 | |
215 # like m1/f1 with dump prepended to block | |
216 # useful with transpose, pairwise, cartesian-product, etc. | |
217 f = {'\xf6': '\x34', '\xf7': '\x35'}[t] | |
218 x = blocks[-1].code.pop() | |
219 blocks[-1].code.extend([Block(['\x0e', x]), f]) | |
220 elif t == '\xfe': #= m: | |
221 blocks.append(Block([])) | |
222 final.append('\x34') | |
223 elif t == '\xff': #= f: | |
224 blocks.append(Block([])) | |
225 final.append('\x35') | |
226 else: | |
227 blocks[-1].code.append(t) | |
228 i += 1 | |
229 | |
230 while final: | |
231 blocks[-2].code.append(blocks.pop()) | |
232 blocks[-1].code.append(final.pop()) | |
233 | |
234 assert len(blocks) == 1 | |
235 main = blocks[0] | |
236 | |
237 if mode == '\x30': #= line-mode | |
238 main = Block(['\x2a', main, '\x34', '\x54']) | |
239 elif mode == '\x31': #= word-mode | |
240 main = Block(['\x2c', main, '\x34', '\x55']) | |
241 elif mode == '\x32': #= line-mode-skip-first | |
242 main = Block(['\x2a', '\x22', main, '\x34', '\x54']) | |
243 | |
244 main.code.extend(final) | |
245 return main | |
246 | |
247 is_num = lambda v: isinstance(v, (int, long)) | |
248 is_list = lambda v: isinstance(v, list) | |
249 is_block = lambda v: isinstance(v, Block) | |
250 | |
251 def to_gs(ps): return map(ord, ps) | |
252 | |
253 def to_ps(gs): | |
254 if is_list(gs): return ''.join(map(chr, gs)) | |
255 else: return chr(gs) | |
256 | |
257 def regex_count(pattern): | |
258 c = 0 | |
259 if pattern[0] == ']': | |
260 c = 1 | |
261 pattern = pattern[1:] | |
262 elif pattern[0] == '}': | |
263 c = ord(pattern[1]) | |
264 pattern = pattern[2:] | |
265 return (c, pattern) | |
266 | |
267 def show(value, nest=False): | |
268 if is_list(value): | |
269 return ''.join(show(x, nest=True) for x in value) | |
270 elif nest and is_num(value): | |
271 return chr(value) | |
272 else: | |
273 return str(value) | |
274 | |
275 class Stack(list): | |
276 def __init__(self, *args): | |
277 list.__init__(self, *args) | |
278 self.junk = [] | |
279 def pop(self, i=-1, junk=True): | |
280 x = list.pop(self, i) | |
281 if junk: self.junk.append(x) | |
282 return x | |
283 | |
284 class GS2(object): | |
285 def __init__(self, code, stdin=''): | |
286 self.code = code | |
287 self.stdin = to_gs(stdin) | |
288 self.stack = Stack([self.stdin]) | |
289 self.regs = { | |
290 0: to_gs(stdin), # A | |
291 1: len(stdin), # B | |
292 2: to_gs(code), # C | |
293 3: random.randint(0, 2), # D | |
294 } | |
295 self.counter = 1 | |
296 | |
297 def run(self): | |
298 try: | |
299 self.evaluate(tokenize(self.code)) | |
300 sys.stdout.write(''.join(map(show, self.stack))) | |
301 except Exception: | |
302 # If the code fails, print something meaningful to stderr, | |
303 # but quine on stdout: this allows GS2 to good at simple | |
304 # "print this string" programs -- just upload a plaintext | |
305 # file, it's unlikely to be valid GS2 code. | |
306 traceback.print_exc() | |
307 if not DEBUG: sys.stdout.write(self.code) | |
308 | |
309 def evaluate(self, block): | |
310 log(block) | |
311 for t in block.code: | |
312 if is_block(t): | |
313 self.stack.append(t) | |
314 elif t[0] == '\x00': #= nop | |
315 pass | |
316 elif t[0] == '\x01': # push unsigned byte | |
317 self.stack.append(struct.unpack('<B', t[1:])[0]) | |
318 elif t[0] == '\x02': # push signed short | |
319 self.stack.append(struct.unpack('<h', t[1:])[0]) | |
320 elif t[0] == '\x03': # push signed long | |
321 self.stack.append(struct.unpack('<l', t[1:])[0]) | |
322 | |
323 elif t[0] == '\x04': # string | |
324 assert len(t) >= 2 | |
325 assert t[-1] in STRING_ENDS | |
326 strings = t[1:-1].split('\x07') | |
327 strings = map(to_gs, strings) | |
328 if t[-1] == '\x05': # regular | |
329 self.stack += strings | |
330 elif t[-1] == '\x06': # array | |
331 self.stack.append(strings) | |
332 elif t[-1] == '\x9b': # printf | |
333 f = to_ps(strings.pop()) | |
334 n = f.count('%') - f.count('%%') * 2 | |
335 x = tuple(map(to_ps, self.stack[-n:])) | |
336 del self.stack[-n:] | |
337 self.stack.append(to_gs(f % x)) | |
338 elif t[-1] == '\x9c': # regex match | |
339 pattern = to_ps(strings.pop()) | |
340 c, pattern = regex_count(pattern) | |
341 s = to_ps(self.stack.pop()) | |
342 f = re.match if c else re.search | |
343 self.stack.append(1 if f(pattern, s) else 0) | |
344 elif t[-1] == '\x9d': # regex sub | |
345 repl = to_ps(strings.pop()) | |
346 pattern = to_ps(strings.pop()) | |
347 c, pattern = regex_count(pattern) | |
348 s = to_ps(self.stack.pop()) | |
349 m = re.sub(pattern, repl, s, count=c) | |
350 self.stack.append(to_gs(m)) | |
351 elif t[-1] == '\x9e': # regex find | |
352 pattern = to_ps(strings.pop()) | |
353 c, pattern = regex_count(pattern) | |
354 s = to_ps(self.stack.pop()) | |
355 ms = re.findall(pattern, s) | |
356 if c > 0: ms = ms[0] if ms else [] | |
357 self.stack.append(map(to_gs, ms)) | |
358 elif t[-1] == '\x9f': # regex split | |
359 pattern = to_ps(strings.pop()) | |
360 c, pattern = regex_count(pattern) | |
361 s = to_ps(self.stack.pop()) | |
362 m = re.split(pattern, s, maxsplit=c) | |
363 self.stack.append(map(to_gs, m)) | |
364 | |
365 elif t[0] == '\x07': # single char string | |
366 self.stack.append([ord(t[1])]) | |
367 | |
368 # \x08 and \x09 are block syntax | |
369 elif t == '\x0a': #= new-line | |
370 self.stack.append([ord('\n')]) | |
371 elif t == '\x0b': #= empty-list | |
372 self.stack.append([]) | |
373 elif t == '\x0c': #= empty-block | |
374 self.stack.append(Block([])) | |
375 elif t == '\x0d': #= space | |
376 self.stack.append([ord(' ')]) | |
377 elif t == '\x0e': #= make-array extract-array dump | |
378 x = self.stack.pop() | |
379 if is_num(x): | |
380 self.stack[-x:] = [self.stack[-x:]] | |
381 elif is_list(x): | |
382 for i in x: | |
383 self.stack.append(i) | |
384 else: | |
385 raise TypeError('make-array / extract-array') | |
386 | |
387 elif t == '\x0f': #= exit | |
388 break | |
389 | |
390 elif 0x10 <= ord(t[0]) <= 0x1a: # push small number | |
391 self.stack.append(ord(t[0]) - 0x10) | |
392 elif t == '\x1b': self.stack.append(100) | |
393 elif t == '\x1c': self.stack.append(1000) | |
394 elif t == '\x1d': self.stack.append(16) | |
395 elif t == '\x1e': self.stack.append(64) | |
396 elif t == '\x1f': self.stack.append(256) | |
397 | |
398 elif t == '\x20': #= negate reverse eval | |
399 x = self.stack.pop() | |
400 if is_num(x): | |
401 self.stack.append(-x) | |
402 elif is_list(x): | |
403 self.stack.append(x[::-1]) | |
404 elif is_block(x): | |
405 self.evaluate(x) | |
406 else: | |
407 raise TypeError('negate / reverse') | |
408 | |
409 elif t == '\x21': #= bnot head | |
410 x = self.stack.pop() | |
411 if is_num(x): | |
412 self.stack.append(~x) | |
413 elif is_list(x): | |
414 self.stack.append(x[0]) | |
415 else: | |
416 raise TypeError('bitwise not / head') | |
417 | |
418 elif t == '\x22': #= not tail | |
419 x = self.stack.pop() | |
420 if is_num(x): | |
421 self.stack.append(0 if x else 1) | |
422 elif is_list(x): | |
423 self.stack.append(x[1:]) | |
424 else: | |
425 raise TypeError('not / tail') | |
426 | |
427 elif t == '\x23': #= abs init | |
428 x = self.stack.pop() | |
429 if is_num(x): | |
430 self.stack.append(abs(x)) | |
431 elif is_list(x): | |
432 self.stack.append(x[:-1]) | |
433 else: | |
434 raise TypeError('abs / init') | |
435 | |
436 elif t == '\x24': #= digits last | |
437 x = self.stack.pop() | |
438 if is_num(x): | |
439 self.stack.append(map(int, str(abs(x)))) | |
440 elif is_list(x): | |
441 self.stack.append(x[-1]) | |
442 else: | |
443 raise ValueError('digits / last') | |
444 | |
445 elif t == '\x25': #= random | |
446 x = self.stack.pop() | |
447 if is_num(x): | |
448 self.stack.append(random.randrange(x)) | |
449 elif is_list(x): | |
450 self.stack.append(random.choice(x)) | |
451 else: | |
452 raise TypeError('random') | |
453 | |
454 elif t == '\x26': #= dec left-uncons | |
455 x = self.stack.pop() | |
456 if is_num(x): | |
457 self.stack.append(x - 1) | |
458 elif is_list(x): | |
459 self.stack.append(x[1:]) | |
460 self.stack.append(x[0]) | |
461 else: | |
462 raise TypeError('deincrement / left uncons') | |
463 | |
464 elif t == '\x27': #= inc right-uncons | |
465 x = self.stack.pop() | |
466 if is_num(x): | |
467 self.stack.append(x + 1) | |
468 elif is_list(x): | |
469 self.stack.append(x[:-1]) | |
470 self.stack.append(x[-1]) | |
471 else: | |
472 raise TypeError('increment / right uncons') | |
473 | |
474 elif t == '\x28': #= sign min | |
475 x = self.stack.pop() | |
476 if is_num(x): | |
477 self.stack.append(cmp(x, 0)) | |
478 elif is_list(x): | |
479 self.stack.append(min(x)) | |
480 else: | |
481 raise TypeError('sign / min') | |
482 | |
483 elif t == '\x29': #= thousand max | |
484 x = self.stack.pop() | |
485 if is_num(x): | |
486 self.stack.append(x * 1000) | |
487 elif is_list(x): | |
488 self.stack.append(max(x)) | |
489 else: | |
490 raise TypeError('thousand / max') | |
491 | |
492 elif t == '\x2a': #= double lines | |
493 x = self.stack.pop() | |
494 if is_num(x): | |
495 self.stack.append(x * 2) | |
496 elif is_list(x): | |
497 if x and x[-1] == ord('\n'): | |
498 x.pop() | |
499 self.stack.append(split(x, to_gs('\n'))) | |
500 else: | |
501 raise TypeError('double / line') | |
502 | |
503 elif t == '\x2b': #= half unlines | |
504 x = self.stack.pop() | |
505 if is_num(x): | |
506 self.stack.append(x // 2) | |
507 elif is_list(x): | |
508 x = [to_gs(show(i)) for i in x] | |
509 self.stack.append(join(x, to_gs('\n'))) | |
510 else: | |
511 raise TypeError('half / unlines') | |
512 | |
513 elif t == '\x2c': #= square words | |
514 x = self.stack.pop() | |
515 if is_num(x): | |
516 self.stack.append(x * x) | |
517 elif is_list(x): | |
518 self.stack.append(map(to_gs, to_ps(x).split())) | |
519 else: | |
520 raise TypeError('square / words') | |
521 | |
522 elif t == '\x2d': #= sqrt unwords | |
523 x = self.stack.pop() | |
524 if is_num(x): | |
525 self.stack.append(int(math.sqrt(x))) | |
526 elif is_list(x): | |
527 x = [to_gs(show(i)) for i in x] | |
528 self.stack.append(join(x, to_gs(' '))) | |
529 else: | |
530 raise TypeError('sqrt / unwords') | |
531 | |
532 elif t == '\x2e': #= range length | |
533 x = self.stack.pop() | |
534 if is_num(x): | |
535 self.stack.append(range(x)) | |
536 elif is_list(x): | |
537 self.stack.append(len(x)) | |
538 else: | |
539 raise TypeError('range / length') | |
540 | |
541 elif t == '\x2f': #= range1 sort | |
542 x = self.stack.pop() | |
543 if is_num(x): | |
544 self.stack.append(range(1, x + 1)) | |
545 elif is_list(x): | |
546 self.stack.append(list(sorted(x))) | |
547 elif is_block(x): | |
548 l = self.stack.pop() | |
549 def f(z): | |
550 self.stack.append(z) | |
551 self.evaluate(x) | |
552 return self.stack.pop(junk=False) | |
553 self.stack.append(list(sorted(l, key=f))) | |
554 else: | |
555 raise TypeError('range1 / sort') | |
556 | |
557 elif t == '\x30': #= + add catenate | |
558 y = self.stack.pop() | |
559 x = self.stack.pop() | |
560 if is_num(x) and is_num(y): | |
561 self.stack.append(x + y) | |
562 elif is_list(x) and is_list(y): | |
563 self.stack.append(x + y) | |
564 elif is_block(x) and is_block(y): | |
565 self.stack.append(Block(x.code + y.code)) | |
566 elif is_list(x) and not is_list(y): | |
567 self.stack.append(x + [y]) | |
568 elif not is_list(x) and is_list(y): | |
569 self.stack.append([x] + y) | |
570 else: | |
571 raise TypeError('add / catenate') | |
572 | |
573 elif t == '\x31': #= - sub diff | |
574 y = self.stack.pop() | |
575 x = self.stack.pop() | |
576 if is_num(x) and is_num(y): | |
577 self.stack.append(x - y) | |
578 elif is_list(x) and is_list(y): | |
579 self.stack.append(set_diff(x, y)) | |
580 elif is_list(x) and not is_list(y): | |
581 self.stack.append(set_diff(x, [y])) | |
582 elif not is_list(x) and is_list(y): | |
583 self.stack.append(set_diff(y, [x])) | |
584 else: | |
585 raise TypeError('subtract / set diff') | |
586 | |
587 elif t == '\x32': #= * mul join times fold | |
588 y = self.stack.pop() | |
589 x = self.stack.pop() | |
590 if is_num(x) and (is_block(y) or is_list(y)): | |
591 x, y = y, x | |
592 if is_block(x) and is_list(y): | |
593 x, y = y, x | |
594 | |
595 if is_num(x) and is_num(y): | |
596 self.stack.append(x * y) | |
597 elif is_list(x) and is_list(y): | |
598 self.stack.append(join(x, y)) | |
599 elif is_list(x) and is_num(y): | |
600 self.stack.append(x * y) | |
601 elif is_block(x) and is_num(y): | |
602 for i in xrange(y): | |
603 self.evaluate(x) | |
604 elif is_list(x) and is_block(y): | |
605 self.stack.append(x[0]) | |
606 for i in x[1:]: | |
607 self.stack.append(i) | |
608 self.evaluate(y) | |
609 else: | |
610 raise TypeError('multiply / join / times / fold') | |
611 | |
612 elif t == '\x33': #= / div chunks split each | |
613 y = self.stack.pop() | |
614 x = self.stack.pop() | |
615 | |
616 if not is_list(x) and is_list(y): | |
617 x, y = y, x | |
618 | |
619 if is_num(x) and is_num(y): | |
620 self.stack.append(x // y) | |
621 elif is_list(x) and is_num(y): | |
622 self.stack.append(list(chunks(x, y))) | |
623 elif is_list(x) and is_list(y): | |
624 self.stack.append(split(x, y)) | |
625 elif is_list(x) and is_block(y): | |
626 for i in x: | |
627 self.stack.append(i) | |
628 self.evaluate(y) | |
629 else: | |
630 raise TypeError('divide / chunks / split / each') | |
631 | |
632 elif t == '\x34': #= % mod step clean-split map | |
633 y = self.stack.pop() | |
634 x = self.stack.pop() | |
635 | |
636 if not is_list(x) and is_list(y): | |
637 x, y = y, x | |
638 | |
639 if is_num(x) and is_num(y): | |
640 self.stack.append(x % y) | |
641 elif is_list(x) and is_num(y): | |
642 self.stack.append(x[::y]) | |
643 elif is_list(x) and is_list(y): | |
644 self.stack.append(split(x, y, clean=True)) | |
645 elif is_list(x) and is_block(y): | |
646 self.eval_map(y, x) | |
647 else: | |
648 raise TypeError('modulo / step / split\' / map') | |
649 | |
650 elif t == '\x35': #= & and get when filter | |
651 y = self.stack.pop() | |
652 x = self.stack.pop() | |
653 | |
654 if is_block(x) and is_num(y): | |
655 x, y = y, x | |
656 if is_num(x) and is_list(y): | |
657 x, y = y, x | |
658 if is_block(x) and is_list(y): | |
659 x, y = y, x | |
660 | |
661 if is_num(x) and is_num(y): | |
662 self.stack.append(x & y) | |
663 elif is_list(x) and is_list(y): | |
664 self.stack.append(set_and(x, y)) | |
665 elif is_list(x) and is_num(y): | |
666 self.stack.append(x[y]) | |
667 elif is_num(x) and is_block(y): | |
668 if x: self.evaluate(y) | |
669 elif is_list(x) and is_block(y): | |
670 self.eval_filter(y, x) | |
671 else: | |
672 raise TypeError('and / get / when / filter') | |
673 | |
674 elif t == '\x36': #= | or unless | |
675 y = self.stack.pop() | |
676 x = self.stack.pop() | |
677 | |
678 if is_block(x) and is_num(y): | |
679 x, y = y, x | |
680 | |
681 if is_num(x) and is_num(y): | |
682 self.stack.append(x | y) | |
683 elif is_list(x) and is_list(y): | |
684 self.stack.append(set_or(x, y)) | |
685 elif is_num(x) and is_block(y): | |
686 if not x: self.evaluate(y) | |
687 else: | |
688 raise TypeError('bor / unless') | |
689 | |
690 elif t == '\x37': #= ^ xor concatmap | |
691 y = self.stack.pop() | |
692 x = self.stack.pop() | |
693 | |
694 if is_block(x) and is_list(y): | |
695 x, y = y, x | |
696 | |
697 if is_num(x) and is_num(y): | |
698 self.stack.append(x ^ y) | |
699 elif is_list(x) and is_list(y): | |
700 self.stack.append(set_xor(x, y)) | |
701 elif is_list(x) and is_block(y): | |
702 res = [] | |
703 for i in x: | |
704 self.stack.append(i) | |
705 self.evaluate(y) | |
706 res.extend(self.stack.pop(junk=False)) | |
707 self.stack.append(res) | |
708 else: | |
709 raise TypeError('xor / concatmap') | |
710 | |
711 elif t == '\x38': #= smallest both | |
712 y = self.stack.pop() | |
713 if is_block(y): | |
714 x = self.stack.pop() | |
715 self.evaluate(y) | |
716 self.stack.append(x) | |
717 self.evaluate(y) | |
718 else: | |
719 x = self.stack.pop() | |
720 self.stack.append(min(x, y)) | |
721 | |
722 elif t == '\x39': #= biggest | |
723 y = self.stack.pop() | |
724 x = self.stack.pop() | |
725 self.stack.append(max(x, y)) | |
726 | |
727 elif t == '\x3a': #= clamp | |
728 z = self.stack.pop() | |
729 y = self.stack.pop() | |
730 x = self.stack.pop() | |
731 self.stack.append(min(max(x, y), z)) | |
732 | |
733 elif t == '\x3c': #= gcd take | |
734 y = self.stack.pop() | |
735 x = self.stack.pop() | |
736 | |
737 if is_num(x) and is_list(y): | |
738 x, y = y, x | |
739 | |
740 if is_num(x) and is_num(y): | |
741 self.stack.append(gcd(x, y)) | |
742 elif is_list(x) and is_num(y): | |
743 self.stack.append(x[:y]) | |
744 else: | |
745 raise TypeError('gcd / take') | |
746 | |
747 elif t == '\x3d': #= lcm drop | |
748 y = self.stack.pop() | |
749 x = self.stack.pop() | |
750 | |
751 if is_num(x) and is_list(y): | |
752 x, y = y, x | |
753 | |
754 if is_num(x) and is_num(y): | |
755 self.stack.append(lcm(x, y)) | |
756 elif is_list(x) and is_num(y): | |
757 self.stack.append(x[y:]) | |
758 else: | |
759 raise TypeError('lcm / drop') | |
760 | |
761 elif t == '\x3e': #= pow index | |
762 y = self.stack.pop() | |
763 x = self.stack.pop() | |
764 | |
765 if is_num(x) and is_list(y): | |
766 x, y = y, x | |
767 | |
768 if is_num(x) and is_num(y): | |
769 self.stack.append(x ** y) | |
770 elif is_list(x) and is_num(y): | |
771 self.stack.append(x.index(y) if y in x else -1) | |
772 else: | |
773 raise TypeError('power / index') | |
774 | |
775 elif t == '\x3f': #= log member | |
776 y = self.stack.pop() | |
777 x = self.stack.pop() | |
778 | |
779 if is_list(y): | |
780 x, y = y, x | |
781 | |
782 if is_num(x) and is_num(y): | |
783 self.stack.append(int(math.log(x, y))) | |
784 elif is_list(x): | |
785 self.stack.append(1 if y in x else 0) | |
786 else: | |
787 raise TypeError('log / member') | |
788 | |
789 elif t == '\x40': #= dup | |
790 self.stack.append(self.stack[-1]) | |
791 elif t == '\x41': #= dup2 | |
792 self.stack.append(self.stack[-1]) | |
793 self.stack.append(self.stack[-1]) | |
794 elif t == '\x42': #= swap | |
795 self.stack.append(self.stack.pop(-2)) | |
796 elif t == '\x43': #= rot | |
797 self.stack.append(self.stack.pop(-3)) | |
798 elif t == '\x44': #= rrot | |
799 self.stack.append(self.stack.pop(-3)) | |
800 self.stack.append(self.stack.pop(-3)) | |
801 elif t == '\x45': #= over | |
802 self.stack.append(self.stack[-2]) | |
803 elif t == '\x46': #= nip | |
804 self.stack.pop(-2) | |
805 elif t == '\x47': #= tuck | |
806 self.stack.insert(-2, self.stack[-1]) | |
807 elif t == '\x48': #= 2dup | |
808 self.stack.append(self.stack[-2]) | |
809 self.stack.append(self.stack[-2]) | |
810 elif t == '\x49': #= pick | |
811 n = self.stack.pop() | |
812 self.stack.append(self.stack[-n]) | |
813 elif t == '\x4a': #= roll | |
814 n = self.stack.pop() | |
815 self.stack.append(self.stack.pop(-n)) | |
816 elif t == '\x4b': #= wrap-stack | |
817 self.stack = [copy.deepcopy(self.stack)] | |
818 elif t == '\x4c': #= leave-top | |
819 del self.stack[:-1] | |
820 elif t == '\x4d': #= itemize | |
821 self.stack.append([self.stack.pop()]) | |
822 elif t == '\x4e': #= rrange | |
823 x = self.stack.pop() | |
824 self.stack.append(range(x)[::-1]) | |
825 elif t == '\x4f': #= crange | |
826 y = self.stack.pop() | |
827 x = self.stack.pop() | |
828 if x > y: x, y = y, x | |
829 self.stack.append(range(x, y)) | |
830 elif t == '\x50': #= pop | |
831 self.stack.pop() | |
832 elif t == '\x51': #= pop2 | |
833 self.stack.pop() | |
834 self.stack.pop() | |
835 elif t == '\x52': #= show | |
836 x = self.stack.pop() | |
837 self.stack.append(to_gs(show(x))) | |
838 elif t == '\x53': #= map-show | |
839 x = self.stack.pop() | |
840 self.stack.append(map(to_gs, map(show, x))) | |
841 elif t == '\x54': #= show-lines | |
842 x = self.stack.pop() | |
843 self.stack.append(to_gs('\n'.join(map(show, x)))) | |
844 elif t == '\x55': #= show-words | |
845 x = self.stack.pop() | |
846 self.stack.append(to_gs(' '.join(map(show, x)))) | |
847 elif t in '\x56\x57': #= read-num, read-nums | |
848 x = to_ps(self.stack.pop()) | |
849 nums = map(int, re.findall(r'-?\d+', x)) | |
850 self.stack.append(nums[0] if t == '\x56' else nums) | |
851 elif t == '\x58': #= show-line | |
852 x = self.stack.pop() | |
853 self.stack.append(to_gs(show(x) + '\n')) | |
854 elif t == '\x59': #= show-space | |
855 x = self.stack.pop() | |
856 self.stack.append(to_gs(show(x) + ' ')) | |
857 elif t == '\x5a': #= show-comma | |
858 x = self.stack.pop() | |
859 self.stack.append(to_gs(', '.join(map(show, x)))) | |
860 elif t == '\x5b': #= show-python | |
861 x = self.stack.pop() | |
862 self.stack.append(to_gs(', '.join(map(show, x)).join('[]'))) | |
863 elif t in '\x5c\x5d\x5e': #= ljust, center, rjust | |
864 fill = ' ' | |
865 if is_num(self.stack[-2]): | |
866 fill = chr(self.stack.pop()) | |
867 width = self.stack.pop() | |
868 s = self.stack.pop() | |
869 if t == '\x5c': g = show(s).ljust(width, fill) | |
870 if t == '\x5d': g = show(s).center(width, fill) | |
871 if t == '\x5e': g = show(s).rjust(width, fill) | |
872 self.stack.append(to_gs(g)) | |
873 elif t == '\x5f': #= inspect | |
874 self.stack.append(to_gs(repr(self.stack.pop()))) | |
875 elif t == '\x60': #= logical-and | |
876 y = self.stack.pop() | |
877 x = self.stack.pop() | |
878 self.stack.append(x and y) | |
879 elif t == '\x61': #= logical-or | |
880 y = self.stack.pop() | |
881 x = self.stack.pop() | |
882 self.stack.append(x or y) | |
883 elif t == '\x62': #= divides left-cons | |
884 y = self.stack.pop() | |
885 x = self.stack.pop() | |
886 if is_num(x): | |
887 self.stack.append(0 if x % y else 1) | |
888 elif is_list(x): | |
889 self.stack.append([y] + x) | |
890 else: | |
891 raise TypeError('divides / left-cons') | |
892 elif t == '\x63': #= divmod group | |
893 y = self.stack.pop() | |
894 if is_num(y): | |
895 x = self.stack.pop() | |
896 self.stack.append(x // y) | |
897 self.stack.append(x % y) | |
898 elif is_list(y): | |
899 gb = [list(g) for k, g in it.groupby(y)] | |
900 self.stack.append(list(gb)) | |
901 else: | |
902 raise TypeError('divmod / group') | |
903 elif t == '\x64': #= sum even | |
904 x = self.stack.pop() | |
905 if is_num(x): | |
906 self.stack.append(1 if x % 2 == 0 else 0) | |
907 elif is_list(x): | |
908 self.stack.append(sum(x)) | |
909 elif t == '\x65': #= product odd | |
910 x = self.stack.pop() | |
911 if is_num(x): | |
912 self.stack.append(1 if x % 2 == 1 else 0) | |
913 elif is_list(x): | |
914 self.stack.append(product(x)) | |
915 elif t == '\x66': #= fizzbuzz | |
916 fizzbuzz = [] | |
917 for i in range(1, 101): | |
918 s = ("Fizz" if i % 3 == 0 else "") + \ | |
919 ("Buzz" if i % 5 == 0 else "") | |
920 fizzbuzz.append(s or str(i)) | |
921 self.stack.append(to_gs('\n'.join(fizzbuzz))) | |
922 elif t == '\x67': #= popcnt right-cons | |
923 x = self.stack.pop() | |
924 if is_num(x): | |
925 x = abs(x) | |
926 p = 0 | |
927 while x: | |
928 p += (x & 1) | |
929 x >>= 1 | |
930 self.stack.append(p) | |
931 elif is_list(x): | |
932 y = self.stack.pop() | |
933 self.stack.append(x + [y]) | |
934 elif t == '\x68': #= hello | |
935 x = 0 | |
936 if len(self.stack) >= 1 and is_num(self.stack[-1]): | |
937 x = self.stack.pop() | |
938 x = (range(0, 11) + [100, 1000, 16, 64, 256]).index(x) | |
939 s1 = 'h' if x & 1 else 'H' | |
940 s2 = 'W' if x & 2 else 'w' | |
941 s3 = ['!', '', '.', '...'][((x & 4) >> 2) | ((x & 16) >> 3)] | |
942 s4 = '' if x & 8 else ',' | |
943 f = '%sello%s %sorld%s' % (s1, s4, s2, s3) | |
944 self.stack.append(to_gs(f)) | |
945 elif t in '\x69\x6a': #= base, binary | |
946 b = 2 if t == '\x6a' else self.stack.pop() | |
947 x = self.stack.pop() | |
948 if is_num(x): | |
949 x = abs(x) | |
950 res = [] | |
951 while x: | |
952 res.append(x % b) | |
953 x //= b | |
954 self.stack.append(res[::-1]) | |
955 elif is_list(x): | |
956 res = 0 | |
957 for i in x: | |
958 res = res * b + i | |
959 self.stack.append(res) | |
960 else: | |
961 raise TypeError('base / binary') | |
962 elif t == '\x6b': #= is-prime | |
963 x = self.stack.pop() | |
964 if is_num(x): | |
965 self.stack.append(1 if is_prime(x) else 0) | |
966 elif is_list(x): | |
967 self.stack.append(filter(is_prime, x)) | |
968 else: | |
969 raise TypeError('is-prime') | |
970 elif t == '\x6c': #= primes | |
971 op = self.stack.pop() | |
972 x = self.stack.pop() | |
973 if op == 0: self.stack.append(n_primes(x)) | |
974 elif op == 1: self.stack.append(primes_below(x)) | |
975 elif op == 2: self.stack.append(next_prime(x)) | |
976 elif op == 3: self.stack.append(totient(x)) | |
977 elif op == 4: self.stack.append(factor(x, exps=False)) | |
978 elif op == 5: self.stack.append(factor(x, exps=True)) | |
979 elif t == '\x6d': #= scan | |
980 f = self.stack.pop() | |
981 def call_f(x, y): | |
982 self.stack.append(x) | |
983 self.stack.append(y) | |
984 self.evaluate(f) | |
985 return self.stack.pop() | |
986 xs = self.stack.pop() | |
987 res = [xs.pop(0)] | |
988 while xs: | |
989 res.append(call_f(res[-1], xs.pop(0))) | |
990 self.stack.append(res) | |
991 elif t in '\x70\x71\x72\x73\x74\x75': #= lt <, eq =, gt >, ge >=, ne !=, le <= | |
992 y = self.stack.pop() | |
993 x = self.stack.pop() | |
994 ops = { | |
995 '\x70': operator.lt, | |
996 '\x71': operator.eq, | |
997 '\x72': operator.gt, | |
998 '\x73': operator.ge, | |
999 '\x74': operator.ne, | |
1000 '\x75': operator.le, | |
1001 } | |
1002 self.stack.append(1 if ops[t](x, y) else 0) | |
1003 elif t == '\x76': #= cmp | |
1004 y = self.stack.pop() | |
1005 x = self.stack.pop() | |
1006 self.stack.append(cmp(x, y)) | |
1007 elif t == '\x77': #= is-sorted | |
1008 x = self.stack.pop() | |
1009 if is_list(x): | |
1010 self.stack.append(1 if x == list(sorted(x)) else 0) | |
1011 elif is_block(x): | |
1012 l = self.stack.pop() | |
1013 def f(z): | |
1014 self.stack.append(z) | |
1015 self.evaluate(x) | |
1016 return self.stack.pop() | |
1017 sorted_l = list(sorted(l, key=f)) | |
1018 self.stack.append(1 if l == sorted_l else 0) | |
1019 else: | |
1020 raise TypeError('sorted') | |
1021 elif t == '\x78': #= shift-left inits | |
1022 y = self.stack.pop() | |
1023 if is_list(y): | |
1024 inits = [] | |
1025 for i in xrange(len(y) + 1): | |
1026 inits.append(y[:i]) | |
1027 self.stack.append(inits) | |
1028 else: | |
1029 x = self.stack.pop() | |
1030 self.stack.append(x << y) | |
1031 elif t == '\x79': #= shift-right tails | |
1032 y = self.stack.pop() | |
1033 if is_list(y): | |
1034 tails = [] | |
1035 for i in xrange(len(y) + 1): | |
1036 tails.append(y[len(y)-i:]) | |
1037 self.stack.append(tails) | |
1038 else: | |
1039 x = self.stack.pop() | |
1040 self.stack.append(x >> y) | |
1041 elif t == '\x7a': #= digit-left enumerate | |
1042 y = self.stack.pop() | |
1043 if is_list(y): | |
1044 self.stack.append(list(map(list, enumerate(y)))) | |
1045 else: | |
1046 x = self.stack.pop() | |
1047 self.stack.append(x * (10 ** y)) | |
1048 elif t == '\x7b': #= digit-right | |
1049 y = self.stack.pop() | |
1050 x = self.stack.pop() | |
1051 self.stack.append(x // (10 ** y)) | |
1052 elif t == '\x7c': #= power-of-2 | |
1053 self.stack.append(2 ** self.stack.pop()) | |
1054 elif t == '\x7d': #= power-of-10 | |
1055 self.stack.append(10 ** self.stack.pop()) | |
1056 elif t == '\x7e': #= sub-power-of-2 | |
1057 self.stack.append(2 ** self.stack.pop() - 1) | |
1058 elif t == '\x7f': #= sub-power-of-10 | |
1059 self.stack.append(10 ** self.stack.pop() - 1) | |
1060 | |
1061 elif t == '\x80': #= pair | |
1062 y = self.stack.pop() | |
1063 x = self.stack.pop() | |
1064 self.stack.append([x, y]) | |
1065 elif t == '\x81': #= copies | |
1066 n = self.stack.pop() | |
1067 x = self.stack.pop() | |
1068 self.stack.append([x for _ in xrange(n)]) | |
1069 elif t == '\x82': #= take-end | |
1070 y = self.stack.pop() | |
1071 x = self.stack.pop() | |
1072 if is_num(x) and is_list(y): | |
1073 x, y = y, x | |
1074 self.stack.append(x[-y:]) | |
1075 elif t == '\x83': #= cartesian-product | |
1076 y = self.stack.pop() | |
1077 x = self.stack.pop() | |
1078 p = it.product(x, y) | |
1079 self.stack.append(list(map(list, p))) | |
1080 elif t == '\x84': #= uppercase-alphabet | |
1081 self.stack.append(range(ord('A'), ord('Z') + 1)) | |
1082 elif t == '\x85': #= lowercase-alphabet | |
1083 self.stack.append(range(ord('a'), ord('z') + 1)) | |
1084 elif t == '\x86': #= ascii-digits | |
1085 self.stack.append(range(ord('0'), ord('9') + 1)) | |
1086 elif t == '\x87': #= printable-ascii | |
1087 self.stack.append(range(32, 127)) | |
1088 elif t in '\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f': #= is-alnum, is-alpha, is-digit, is-lower, is-space, is-upper, is-printable, is-hexdigit | |
1089 m = [str.isalnum, str.isalpha, str.isdigit, | |
1090 str.islower, str.isspace, str.isupper, | |
1091 lambda x: all(32 <= ord(c) <= 126 for c in x), | |
1092 lambda x: x in '0123456789abcdefABCDEF'] | |
1093 p = m[ord(t) - 0x88] | |
1094 x = to_ps(self.stack.pop()) | |
1095 self.stack.append(1 if p(x) else 0) | |
1096 elif t == '\x90': #= uniq nub | |
1097 xs = self.stack.pop() | |
1098 uniq = [] | |
1099 for x in xs: | |
1100 if x not in uniq: | |
1101 uniq.append(x) | |
1102 self.stack.append(uniq) | |
1103 elif t == '\x91': #= compress | |
1104 ns = self.stack.pop() | |
1105 xs = self.stack.pop() | |
1106 new = [] | |
1107 for n, x in zip(ns, xs): | |
1108 new += [x for _ in xrange(n)] | |
1109 self.stack.append(new) | |
1110 elif t == '\x92': #= select | |
1111 xs = self.stack.pop() | |
1112 iis = self.stack.pop() | |
1113 new = [] | |
1114 for i in iis: | |
1115 new.append(xs[i]) | |
1116 self.stack.append(new) | |
1117 elif t == '\x93': #= permutations | |
1118 xs = self.stack.pop() | |
1119 if is_num(xs): | |
1120 n = xs | |
1121 xs = self.stack.pop() | |
1122 else: | |
1123 n = None | |
1124 ps = list(map(list, it.permutations(xs, n))) | |
1125 self.stack.append(ps) | |
1126 elif t == '\x94': #= fold-product | |
1127 xss = self.stack.pop() | |
1128 ys = list(map(list, it.product(*xss))) | |
1129 self.stack.append(ys) | |
1130 elif t == '\x95': #= repeat-product | |
1131 n = self.stack.pop() | |
1132 xs = self.stack.pop() | |
1133 ys = list(map(list, it.product(xs, repeat=n))) | |
1134 self.stack.append(ys) | |
1135 elif t == '\x96': #= combinations | |
1136 n = self.stack.pop() | |
1137 xs = self.stack.pop() | |
1138 ys = list(map(list, it.combinations(xs, n))) | |
1139 self.stack.append(ys) | |
1140 elif t == '\x97': #= combinations-with-replacement | |
1141 n = self.stack.pop() | |
1142 xs = self.stack.pop() | |
1143 ys = list(map(list, it.combinations_with_replacement(xs, n))) | |
1144 self.stack.append(ys) | |
1145 elif t == '\x98': #= pairwise | |
1146 xs = self.stack.pop() | |
1147 ys = map(list, zip(xs, xs[1:])) | |
1148 self.stack.append(ys) | |
1149 elif t == '\x99': #= flatten | |
1150 def flatten(xs): | |
1151 acc = [] | |
1152 for x in xs: | |
1153 if is_list(x): | |
1154 acc += flatten(x) | |
1155 else: | |
1156 acc.append(x) | |
1157 return acc | |
1158 xs = self.stack.pop() | |
1159 self.stack.append(flatten(xs)) | |
1160 elif t == '\x9a': #= transpose | |
1161 xs = self.stack.pop() | |
1162 self.stack.append(map(list, zip(*xs))) | |
1163 elif '\xa0' <= t <= '\xaf': # junk (recently popped items) | |
1164 self.stack.append(self.stack.junk[-1 - (ord(t) & 15)]) | |
1165 elif t == '\xb0': #= zip | |
1166 ys = self.stack.pop() | |
1167 xs = self.stack.pop() | |
1168 self.stack.append(map(list, zip(xs, ys))) | |
1169 elif t == '\xb1': #= zipwith | |
1170 f = self.stack.pop() | |
1171 ys = self.stack.pop() | |
1172 xs = self.stack.pop() | |
1173 l0 = len(self.stack) | |
1174 for x, y in zip(xs, ys): | |
1175 self.stack.append(x) | |
1176 self.stack.append(y) | |
1177 self.evaluate(f) | |
1178 self.stack[l0:] = [self.stack[l0:]] | |
1179 elif t == '\xb2': #= counter | |
1180 self.stack.append(self.counter) | |
1181 self.counter += 1 | |
1182 elif '\xc8' <= t <= '\xcb': # save | |
1183 self.regs[ord(t) & 3] = self.stack[-1] | |
1184 elif '\xcc' <= t <= '\xcf': # put | |
1185 self.regs[ord(t) & 3] = self.stack.pop() | |
1186 elif '\xd0' <= t <= '\xd3': # get | |
1187 self.stack.append(self.regs[ord(t) & 3]) | |
1188 elif '\xd4' <= t <= '\xd7': # nip | |
1189 self.regs[ord(t) & 3] = self.stack.pop(-2) | |
1190 elif '\xd8' <= t <= '\xdb': # tuck | |
1191 self.stack.insert(-1, self.regs[ord(t) & 3]) | |
1192 elif '\xdc' <= t <= '\xdf': # show | |
1193 self.stack.append(to_gs(show(self.regs[ord(t) & 3]))) | |
1194 else: | |
1195 raise ValueError('invalid token %r' % t) | |
1196 | |
1197 def eval_map(self, f, x): | |
1198 l0 = len(self.stack) | |
1199 for i in x: | |
1200 self.stack.append(i) | |
1201 self.evaluate(f) | |
1202 self.stack[l0:] = [self.stack[l0:]] | |
1203 | |
1204 def eval_filter(self, f, x): | |
1205 l0 = len(self.stack) | |
1206 for i in x: | |
1207 self.stack.append(i) | |
1208 self.evaluate(f) | |
1209 if self.stack.pop(): | |
1210 self.stack.append(i) | |
1211 self.stack[l0:] = [self.stack[l0:]] | |
1212 | |
1213 if __name__ == '__main__': | |
1214 if len(sys.argv) <= 1: | |
1215 print >> sys.stderr, 'usage: python %s [-d] <code file>' % sys.argv[0] | |
1216 sys.exit(1) | |
1217 | |
1218 if sys.argv[1] == '-d': | |
1219 DEBUG = True | |
1220 sys.argv.pop(1) | |
1221 | |
1222 code = open(sys.argv[1], 'rb').read() | |
1223 stdin = '' if sys.stdin.isatty() else sys.stdin.read() | |
1224 GS2(code, stdin).run() |