zmbc/shakespearelang

View on GitHub
shakespearelang/_repl.py

Summary

Maintainability
A
3 hrs
Test Coverage
F
0%
from .shakespeare import Shakespeare
from .errors import ShakespeareError
from ._utils import normalize_name
from tatsu.exceptions import FailedParse

try:
    import readline
except ModuleNotFoundError:
    print("readline module is not supported in Windows, continuing without it.")

import sys


DEFAULT_PLAY_TEMPLATE = """
A REPL-tastic Adventure.

<dramatis personae>

                    Act I: All the World.
                    Scene I: A Stage.

[Enter <entrance list>]
"""


def start_console(characters=["Romeo", "Juliet"]):
    dramatis_personae = "\n".join([name + ", a player." for name in characters])
    entrance_list = _entrance_list_from_characters(characters)
    play = DEFAULT_PLAY_TEMPLATE.replace(
        "<dramatis personae>", dramatis_personae
    ).replace("<entrance list>", entrance_list)

    print(play)
    interpreter = Shakespeare(play)
    # Run the entrance
    interpreter.step_forward()
    run_repl(interpreter)


# E.g. ["Mercutio", "Romeo", "Tybalt"] => "Mercutio, Romeo and Tybalt"
def _entrance_list_from_characters(characters):
    all_commas = ", ".join(characters)
    split_on_last = all_commas.rsplit(", ", 1)
    return " and ".join(split_on_last)


def debug_play(text, input_style="interactive", output_style="verbose"):
    interpreter = Shakespeare(text, input_style=input_style, output_style=output_style)

    def on_breakpoint():
        print("-----\n" + interpreter.next_operation_text() + "\n-----\n")
        run_repl(interpreter)

    interpreter.run(on_breakpoint)


def run_repl(interpreter):
    previous_input_style = interpreter.settings.input_style
    previous_output_style = interpreter.settings.output_style
    interpreter.settings.input_style = "interactive"
    interpreter.settings.output_style = "verbose"
    current_character = None

    while True:
        try:
            pos_before = interpreter.current_position
            repl_input = input(">> ")
            if repl_input in ["exit", "quit"]:
                sys.exit()
            elif repl_input == "continue":
                break
            elif repl_input == "next":
                if interpreter.play_over():
                    break
                interpreter.step_forward()
            elif repl_input == "state":
                print(str(interpreter.state))
            else:
                # TODO: make this not an awkward return value
                current_character = _run_repl_input(
                    interpreter, repl_input, current_character
                )

            if interpreter.current_position != pos_before:
                if interpreter.play_over():
                    break
                print("\n-----\n" + interpreter.next_operation_text() + "\n-----\n")
        except ShakespeareError as e:
            print(str(e), file=sys.stderr)

    interpreter.input_style = previous_input_style
    interpreter.output_style = previous_output_style


def _run_repl_input(interpreter, repl_input, current_character):
    ast = interpreter.parse(repl_input + "\n", "repl_input")

    event = ast.event
    sentences = ast.sentences

    # Events that are lines should be considered sets of sentences.
    if event and event.parseinfo.rule == "line":
        current_character = normalize_name(event.character)
        sentences = event.contents
        event = None

    if event:
        interpreter.run_event(event)
    elif sentences:
        if not current_character:
            print("Who's saying this?")
            return

        for sentence in sentences:
            interpreter.run_sentence(sentence, current_character)
    elif ast.value:
        if ast.expression_character:
            current_character = normalize_name(ast.expression_character)

        print(interpreter.evaluate_expression(ast.value, current_character))
    elif ast.display_character:
        print(
            interpreter.state.character_by_name(normalize_name(ast.display_character))
        )

    return current_character