# -*- 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 . # ''' 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 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 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) 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