aboutsummaryrefslogtreecommitdiff
path: root/lldb/source/Interpreter/embedded_interpreter.py
blob: a487592ef1aee5f3642fa0d316eecd895869251b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import sys

if sys.version_info[0] < 3:
    import __builtin__ as builtins
else:
    import builtins
import code
import lldb
import traceback

try:
    import readline
    import rlcompleter
except ImportError:
    have_readline = False
except AttributeError:
    # This exception gets hit by the rlcompleter when Linux is using
    # the readline suppression import.
    have_readline = False
else:
    have_readline = True
    if "libedit" in readline.__doc__:
        readline.parse_and_bind("bind ^I rl_complete")
    else:
        readline.parse_and_bind("tab: complete")

# When running one line, we might place the string to run in this string
# in case it would be hard to correctly escape a string's contents

g_run_one_line_str = None


def get_terminal_size(fd):
    try:
        import fcntl
        import termios
        import struct

        hw = struct.unpack("hh", fcntl.ioctl(fd, termios.TIOCGWINSZ, "1234"))
    except:
        hw = (0, 0)
    return hw


class LLDBExit(SystemExit):
    pass


def strip_and_check_exit(line):
    line = line.rstrip()
    if line in ("exit", "quit"):
        raise LLDBExit
    return line


def readfunc(prompt):
    line = input(prompt)
    return strip_and_check_exit(line)


def readfunc_stdio(prompt):
    sys.stdout.write(prompt)
    sys.stdout.flush()
    line = sys.stdin.readline()
    # Readline always includes a trailing newline character unless the file
    # ends with an incomplete line. An empty line indicates EOF.
    if not line:
        raise EOFError
    return strip_and_check_exit(line)


def run_python_interpreter(local_dict):
    # Pass in the dictionary, for continuity from one session to the next.
    try:
        fd = sys.stdin.fileno()
        interacted = False
        if get_terminal_size(fd)[1] == 0:
            try:
                import termios

                old = termios.tcgetattr(fd)
                if old[3] & termios.ECHO:
                    # Need to turn off echoing and restore
                    new = termios.tcgetattr(fd)
                    new[3] = new[3] & ~termios.ECHO
                    try:
                        termios.tcsetattr(fd, termios.TCSADRAIN, new)
                        interacted = True
                        code.interact(
                            banner="Python Interactive Interpreter. To exit, type 'quit()', 'exit()'.",
                            readfunc=readfunc_stdio,
                            local=local_dict,
                        )
                    finally:
                        termios.tcsetattr(fd, termios.TCSADRAIN, old)
            except:
                pass
            # Don't need to turn off echoing
            if not interacted:
                code.interact(
                    banner="Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D.",
                    readfunc=readfunc_stdio,
                    local=local_dict,
                )
        else:
            # We have a real interactive terminal
            code.interact(
                banner="Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D.",
                readfunc=readfunc,
                local=local_dict,
            )
    except LLDBExit:
        pass
    except SystemExit as e:
        if e.code:
            print("Script exited with code %s" % e.code)


def run_one_line(local_dict, input_string):
    global g_run_one_line_str
    try:
        input_string = strip_and_check_exit(input_string)
        repl = code.InteractiveConsole(local_dict)
        if input_string:
            # A newline is appended to support one-line statements containing
            # control flow. For example "if True: print(1)" silently does
            # nothing, but works with a newline: "if True: print(1)\n".
            input_string += "\n"
            repl.runsource(input_string)
        elif g_run_one_line_str:
            repl.runsource(g_run_one_line_str)
    except LLDBExit:
        pass
    except SystemExit as e:
        if e.code:
            print("Script exited with code %s" % e.code)