34
34
from colored import Fore , Style
35
35
36
36
37
+ is_terminal = sys .stdout .isatty ()
38
+ colors = {n : '' for n in ["off" , "input_prompt" , "var" , "freevar" , "combinator" , "lambda" , "output_prompt" ]}
39
+ if is_terminal :
40
+ for k in colors :
41
+ match k :
42
+ case "input_prompt" :
43
+ newval = Fore .rgb (242 , 45 , 57 )
44
+ case "output_prompt" :
45
+ newval = Fore .rgb (45 , 242 , 57 )
46
+ case "var" :
47
+ newval = Fore .rgb (242 , 185 , 45 )
48
+ case "freevar" :
49
+ newval = Fore .rgb (255 , 64 , 23 )
50
+ case "combinator" :
51
+ newval = Fore .rgb (255 , 0 , 163 )
52
+ case "lambda" :
53
+ newval = Fore .rgb (45 , 135 , 242 )
54
+ case "off" :
55
+ newval = Style .reset
56
+ case _:
57
+ print (f'unhandled color { k } ' )
58
+ sys .exit (1 )
59
+ colors [k ] = newval
60
+
61
+
37
62
# These are the characters accepted and used s variable names. The list
38
63
# could be extended here and everything else should just work. But it
39
64
# should be noted that
@@ -189,8 +214,6 @@ class Var(Obj):
189
214
"""Object to represent a variable in the lambda expression graph. This implements
190
215
the de Bruijn notation by representing each new variable with a unique number."""
191
216
varcnt : ClassVar [int ] = 1
192
- color : ClassVar [str ] = Fore .rgb (242 , 185 , 45 )
193
- color_free : ClassVar [str ] = Fore .rgb (255 , 64 , 23 )
194
217
195
218
def __init__ (self , freename : Optional [str ] = None ):
196
219
self .id = Var .varcnt
@@ -210,7 +233,7 @@ def __str__(self):
210
233
@override
211
234
def fmt (self , varmap : Naming , highlight : bool ) -> str :
212
235
res = self .freename or varmap .get (self )
213
- return f'{ Var . color_free if self .freename else Var . color } { res } { Style . reset } ' if highlight else res
236
+ return f'{ colors [ "freevar" if self .freename else "var" ] } { res } { colors [ "off" ] } '
214
237
215
238
@override
216
239
def replace (self , v : Var , expr : Obj ) -> Obj :
@@ -262,8 +285,6 @@ def fmt(self, varmap: Naming, highlight: bool) -> str:
262
285
263
286
class Combinator (Obj ):
264
287
"""Object to represent a recombined combinator."""
265
- color : ClassVar [str ] = Fore .rgb (255 , 0 , 163 )
266
-
267
288
def __init__ (self , combinator : str , arguments : Optional [List [Obj ]] = None ):
268
289
self .combinator = combinator
269
290
self .arguments = [] if arguments is None else arguments
@@ -280,7 +301,7 @@ def __str__(self):
280
301
281
302
@override
282
303
def fmt (self , varmap : Naming , highlight : bool ) -> str :
283
- combres = f'{ Combinator . color } { self .combinator } { Style . reset } ' if highlight else self . combinator
304
+ combres = f'{ colors [ "combinator" ] } { self .combinator } { colors [ "off" ] } '
284
305
if self .arguments :
285
306
combres += ' ' + ' ' .join ([a .fmt (varmap , highlight ) for a in self .arguments ])
286
307
return combres
@@ -341,8 +362,6 @@ def beta(self) -> Obj:
341
362
342
363
class Lambda (Obj ):
343
364
"""Object to represent a lambda expression in the lambda expression graph."""
344
- color : ClassVar [str ] = Fore .rgb (45 , 135 , 242 )
345
-
346
365
def __init__ (self , params : List [Var ], code : Obj ):
347
366
if not params :
348
367
raise SyntaxError ('lambda parameter list cannot be empty' )
@@ -368,7 +387,7 @@ def fmt(self, varmap: Naming, highlight: bool) -> str:
368
387
nvarmap = Naming (varmap .avoid )
369
388
paramstr = '' .join ([a .fmt (nvarmap , highlight ) for a in self .params ])
370
389
varmap .add (nvarmap )
371
- la = f'{ Lambda . color } λ{ Style . reset } ' if highlight else 'λ '
390
+ la = f'{ colors [ "lambda" ] } λ{ colors [ "off" ] } '
372
391
return f'({ la } { paramstr } .{ remove_braces (self .code .fmt (varmap , highlight ))} )'
373
392
374
393
@override
@@ -574,17 +593,20 @@ def handle(al: List[str], echo: bool, is_terminal: bool = False) -> int:
574
593
"""Loop over given list of strings, parse, simplify, and print the lambda
575
594
expression."""
576
595
ec = 0
577
- pr = f'{ Fore .rgb (45 , 242 , 57 )} ⇒{ Style .reset } ' if is_terminal else '⇒ ' if is_terminal else ''
596
+ input_prompt = f'{ colors ["input_prompt" ]} »{ colors ["off" ]} '
597
+ output_prompt = f'{ colors ["output_prompt" ]} ⇒{ colors ["off" ]} ' if is_terminal else ''
598
+ separator_len = os .get_terminal_size ()[0 ] if is_terminal else 72
599
+
578
600
for a in al :
579
601
if echo and is_terminal :
580
- print (f'{ Fore . rgb ( 242 , 45 , 57 ) } » { Style . reset } { a } ' if is_terminal else f'» { a } ' )
602
+ print (f'{ input_prompt } { a } ' )
581
603
try :
582
- print (f'{ pr } { to_string (from_string (a ), is_terminal )} ' )
604
+ print (f'{ output_prompt } { to_string (from_string (a ), is_terminal )} ' )
583
605
except SyntaxError as e :
584
606
print (f'eval("{ a } ") failed: { e .args [0 ]} ' )
585
607
ec = 1
586
608
if not echo :
587
- print ('\u2501 ' * ( os . get_terminal_size ()[ 0 ] if is_terminal else 72 ) )
609
+ print ('\u2501 ' * separator_len )
588
610
return ec
589
611
590
612
@@ -593,8 +615,9 @@ def repl() -> int:
593
615
ec = 0
594
616
try :
595
617
is_terminal = sys .stdout .isatty ()
618
+ input_prefix = f'{ colors ["input_prompt" ]} »{ colors ["off" ]} '
596
619
while True :
597
- s = input (f' { Fore . rgb ( 242 , 45 , 57 ) } » { Style . reset } ' if is_terminal else '» ' )
620
+ s = input (input_prefix )
598
621
if not s :
599
622
break
600
623
ec = ec | handle ([s ], False , is_terminal )
0 commit comments