Source code for joy.joy
# -*- coding: utf-8 -*-
#
# Copyright © 2014, 2015, 2017, 2018 Simon Forman
#
# This file is part of Thun
#
# Thun is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Thun is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Thun. If not see <http://www.gnu.org/licenses/>.
#
'''
This module implements an interpreter for a dialect of Joy that
attempts to stay very close to the spirit of Joy but does not precisely
match the behaviour of the original version(s) written in C.
'''
from __future__ import print_function
try:
input = raw_input
except NameError:
pass
from traceback import print_exc, format_exc
from .parser import text_to_expression, ParseError, Symbol
from .utils.stack import stack_to_string
from .utils.pretty_print import TracePrinter
[docs]def joy(stack, expression, dictionary, viewer=None):
'''Evaluate the Joy expression on the stack.
The basic joy() function is quite straightforward. It iterates through a
sequence of terms which are either literals (strings, numbers, sequences)
or functions. Literals are put onto the stack and functions are
executed.
:param stack stack: The stack.
:param stack expression: The expression to evaluate.
:param dict dictionary: A ``dict`` mapping names to Joy functions.
:param function viewer: Optional viewer function.
:rtype: (stack, (), dictionary)
'''
while expression:
if viewer: viewer(stack, expression)
term, expression = expression
if isinstance(term, Symbol):
term = dictionary[term]
stack, expression, dictionary = term(stack, expression, dictionary)
else:
stack = term, stack
if viewer: viewer(stack, expression)
return stack, expression, dictionary
[docs]def run(text, stack, dictionary, viewer=None):
'''
Return the stack resulting from running the Joy code text on the stack.
:param str text: Joy code.
:param stack stack: The stack.
:param dict dictionary: A ``dict`` mapping names to Joy functions.
:param function viewer: Optional viewer function.
:rtype: (stack, (), dictionary)
'''
expression = text_to_expression(text)
return joy(stack, expression, dictionary, viewer)
[docs]def repl(stack=(), dictionary=None):
'''
Read-Evaluate-Print Loop
Accept input and run it on the stack, loop.
:param stack stack: The stack.
:param dict dictionary: A ``dict`` mapping names to Joy functions.
:rtype: stack
'''
if dictionary is None:
dictionary = {}
try:
while True:
print()
print(stack_to_string(stack), '<-top')
print()
try:
text = input('joy? ')
except (EOFError, KeyboardInterrupt):
break
viewer = TracePrinter()
try:
stack, _, dictionary = run(text, stack, dictionary, viewer.viewer)
except:
exc = format_exc() # Capture the exception.
viewer.print_() # Print the Joy trace.
print('-' * 73)
print(exc) # Print the original exception.
else:
viewer.print_()
except:
print_exc()
print()
return stack