Quiet mode for testing. Misc cleanup.

This commit is contained in:
Simon Forman 2022-09-07 17:27:36 -07:00
parent 660fdb0bef
commit d7b445fdd4
1 changed files with 61 additions and 14 deletions

View File

@ -37,7 +37,9 @@ import operator
class NotAListError(Exception): class NotAListError(Exception):
'''Raised when a stack is expected.''' '''
Raised when a stack is expected but not received.
'''
class NotAnIntError(Exception): class NotAnIntError(Exception):
@ -48,6 +50,12 @@ class NotABoolError(Exception):
pass pass
class ParseError(ValueError):
'''
Raised when there is a error while parsing text.
'''
class StackUnderflowError(Exception): class StackUnderflowError(Exception):
pass pass
@ -110,11 +118,11 @@ the fact that they are not Symbol objects.
A crude grammar:: A crude grammar::
joy = term* joy = <term>*
term = integer | '[' joy ']' | symbol term = <integer> | 'true' | 'false' | '[' <joy> ']' | <symbol>
A Joy expression is a sequence of zero or more terms. A term is a A Joy expression is a sequence of zero or more terms. A term is a
literal value (integer or quoted Joy expression) or a function symbol. literal value (integer, Boolean, or quoted Joy expression) or a function symbol.
Function symbols are sequences of non-blanks and cannot contain square Function symbols are sequences of non-blanks and cannot contain square
brackets. Terms must be separated by blanks, which can be omitted brackets. Terms must be separated by blanks, which can be omitted
around square brackets. around square brackets.
@ -168,12 +176,6 @@ def text_to_expression(text):
return _parse(_tokenize(text)) return _parse(_tokenize(text))
class ParseError(ValueError):
'''
Raised when there is a error while parsing text.
'''
def _tokenize(text): def _tokenize(text):
'''Convert a text into a stream of tokens. '''Convert a text into a stream of tokens.
@ -349,7 +351,7 @@ def concat(quote, expression):
# recursion limit on long quotes.) # recursion limit on long quotes.)
if not isinstance(quote, tuple): if not isinstance(quote, tuple):
raise NotAListError('Not a list.') raise NotAListError(f'Not a list {_s(quote)}')
temp = [] temp = []
while quote: while quote:
item, quote = quote item, quote = quote
@ -480,6 +482,36 @@ def run(text, stack, dictionary):
return joy(stack, expr, dictionary) return joy(stack, expr, dictionary)
def interp(stack=(), dictionary=None):
'''
Simple REPL with no extra output, suitable for use in scripts.
'''
if dictionary is None:
dictionary = {}
try:
while True:
try:
text = input()
except (EOFError, KeyboardInterrupt):
break
try:
stack, _, dictionary = run(text, stack, dictionary)
except UnknownSymbolError as sym:
print('Unknown:', sym)
except StackUnderflowError as e:
print(e) # 'Not enough values on stack.'
except NotAnIntError:
print('Not an integer.')
except NotAListError as e:
print(e)
except:
print_exc()
print(stack_to_string(stack))
except:
print_exc()
return stack
''' '''
@ -586,6 +618,12 @@ def branch(stack, expr, dictionary):
''' '''
(then, (else_, (flag, stack))) = stack (then, (else_, (flag, stack))) = stack
if not isinstance(flag, bool):
raise NotABoolError(f'Not a Boolean value: {_s(flag)}')
if not isinstance(else_, tuple):
raise NotAListError(f'Not a list {_s(else_)}')
if not isinstance(then, tuple):
raise NotAListError(f'Not a list {_s(then)}')
do = then if flag else else_ do = then if flag else else_
return stack, concat(do, expr), dictionary return stack, concat(do, expr), dictionary
@ -791,7 +829,7 @@ def swaack(stack):
1 2 3 [4 5 6] swaack 1 2 3 [4 5 6] swaack
-------------------------- --------------------------
6 5 4 [3 2 1] 6 5 4 [3 2 1]
''' '''
(s1, s0) = stack (s1, s0) = stack
@ -967,7 +1005,7 @@ class Def(object):
the pending expression. the pending expression.
''' '''
tribar = '\u2261' # '≡' # tribar = '\u2261' # '≡'
def __init__(self, name, body): def __init__(self, name, body):
self.__doc__ = f'{name}{expression_to_string(body)}' self.__doc__ = f'{name}{expression_to_string(body)}'
@ -999,6 +1037,13 @@ Start with increment and decrement:
-- 1 - -- 1 -
++ 1 + ++ 1 +
= eq
+ add
> gt
< lt
>= ge
<= le
? dup bool ? dup bool
&& nulco [nullary [false]] dip branch && nulco [nullary [false]] dip branch
@ -1122,6 +1167,8 @@ _map2 [infrst] cons dipd roll< swons
if __name__ == '__main__': if __name__ == '__main__':
import sys
J = interp if '-q' in sys.argv else repl
dictionary = initialize() dictionary = initialize()
Def.load_definitions(DEFS.splitlines(), dictionary) Def.load_definitions(DEFS.splitlines(), dictionary)
stack = repl(dictionary=dictionary) stack = J(dictionary=dictionary)