Skip to content
Newer
Older
100644 165 lines (140 sloc) 4.11 KB
d4cb3c6 @bluepeppers Moved readline code into new clojure.repl module.
bluepeppers authored Mar 18, 2012
1 """
2 Contains enhancements to the REPL that do not belong in the core language.
3 """
4
8322e0f Printing Python version at REPL start. Fixes #82.
Eric Shull authored Mar 21, 2012
5 import atexit
6 import os
7 import sys
d844e18 @bluepeppers Moved repl main loop out of clojure.main into clojure.repl.
bluepeppers authored Mar 18, 2012
8 import traceback
9
10 from clojure.lang.globals import currentCompiler
11 from clojure.lang.compiler import Compiler
12 from clojure.lang.symbol import symbol
13 from clojure.lang.var import Var, intern as internVar
14 from clojure.lang.lispreader import read
15 from clojure.lang.fileseq import StringReader
4413292 Not printing version when running scripts.
Eric Shull authored Mar 21, 2012
16 from clojure.main import VERSION
d844e18 @bluepeppers Moved repl main loop out of clojure.main into clojure.repl.
bluepeppers authored Mar 18, 2012
17
18
d4cb3c6 @bluepeppers Moved readline code into new clojure.repl module.
bluepeppers authored Mar 18, 2012
19 def enable_readline():
20 """
21 Imports the `readline` module to enable advanced repl text manipulation,
22 and command history navigation.
23
24 Returns True if success, otherwise False.
25 """
26 try:
27 import readline
28 except ImportError:
29 return False
30
31 histfile = os.path.join(os.path.expanduser("~"), ".clojurepyhist")
32 if not os.path.isfile(histfile):
33 with open(histfile, 'a'):
34 os.utime(histfile, None)
35 os.chmod(histfile, int('640',8))
36 try:
37 readline.read_history_file(histfile)
38 except IOError:
39 # Pass here as there isn't any history file, so one will be
40 # written by atexit
41 pass
42 atexit.register(readline.write_history_file, histfile)
43 return True
d844e18 @bluepeppers Moved repl main loop out of clojure.main into clojure.repl.
bluepeppers authored Mar 18, 2012
44
45 def run_repl(comp=None):
46 """
47 Starts the repl. Assumes that RT.init has allready be called.
48 """
4413292 Not printing version when running scripts.
Eric Shull authored Mar 22, 2012
49 print "clojure-py", VERSION
8322e0f Printing Python version at REPL start. Fixes #82.
Eric Shull authored Mar 22, 2012
50 print "Python", sys.version
51
d844e18 @bluepeppers Moved repl main loop out of clojure.main into clojure.repl.
bluepeppers authored Mar 18, 2012
52 if comp is None:
53 curr = currentCompiler.get(lambda: None)
54 if curr == None:
55 comp = Compiler()
56 currentCompiler.set(comp)
57 else:
58 comp = curr
59 comp.setNS(symbol("user"))
60
61 last3 = [None, None, None]
62
63 def execute(string):
64 r = StringReader(string)
65 s = read(r, False, None, True)
66 res = comp.compile(s)
67 return comp.executeCode(res)
68
69 while 1:
70 for i, value in enumerate(last3, 1):
71 sym = symbol('*%s' % i)
72 v = internVar(comp.getNS(), sym)
73 v.setDynamic(True)
74 if isinstance(value, Var):
75 v.bindRoot(value.deref())
76 v.setMeta(value.meta())
77 else:
78 v.bindRoot(value)
79
80 try:
81 line = raw_input(comp.getNS().__name__ + "=> ")
82 except EOFError:
f8ad66e ^D gives newline before quitting.
Eric Shull authored Mar 21, 2012
83 print
d844e18 @bluepeppers Moved repl main loop out of clojure.main into clojure.repl.
bluepeppers authored Mar 18, 2012
84 break
85
86 if not line:
87 continue
88
34b4643 @bluepeppers Print "Invalid input" when parens are broken.
bluepeppers authored Mar 19, 2012
89 invalid = False
90 while 1:
91 unbalance = unbalanced(line)
92
93 if unbalance == -1:
94 invalid = True
95 break
96 elif unbalance is False:
97 break
98
d844e18 @bluepeppers Moved repl main loop out of clojure.main into clojure.repl.
bluepeppers authored Mar 18, 2012
99 try:
100 new_line = '\n' + raw_input('.' * len(comp.getNS().__name__) + '.. ')
101 except EOFError:
102 break
103
104 if not new_line.strip().startswith(';'):
105 line += new_line
106
34b4643 @bluepeppers Print "Invalid input" when parens are broken.
bluepeppers authored Mar 19, 2012
107 if invalid:
108 print "Invalid input"
109 continue
110
d844e18 @bluepeppers Moved repl main loop out of clojure.main into clojure.repl.
bluepeppers authored Mar 18, 2012
111 # Propogate break from above loop.
112 if unbalanced(line):
113 break
114
115 try:
116 out = execute(line)
117 except Exception:
118 traceback.print_exc()
119 else:
120 last3.pop()
121 last3.insert(0, out)
122 print out
123
124 def unbalanced(line):
125 """
126 Returns true if the parentheses in the line are unbalanced.
127 """
d35fabb @bluepeppers Rewrote unbalanced algorithm to be stack based.
bluepeppers authored Mar 19, 2012
128 open = ("(", "[", "{")
129 close = (")", "]", "}")
130 stack = []
131
132 open_ignore = ("\"", ";")
133 close_ignore = ("\"", "\n")
134 ignore = -1
d844e18 @bluepeppers Moved repl main loop out of clojure.main into clojure.repl.
bluepeppers authored Mar 18, 2012
135 for c in line:
d35fabb @bluepeppers Rewrote unbalanced algorithm to be stack based.
bluepeppers authored Mar 19, 2012
136 if ignore != -1:
137 if c == close_ignore[ignore]:
138 ignore = -1
139 else:
140 continue
141 else:
142 for i, o in enumerate(open_ignore):
143 if o == c:
144 ignore = i
145 if ignore != -1:
146 continue
147
148 found = False
149 for t in open:
150 if c == t:
151 stack.append(c)
152 found = True
153 if found:
154 continue
155
156 found = False
157 for i, t in enumerate(close):
158 if c == t:
159 if not stack or stack[-1] != open[i]:
160 # User error, return -1
161 return -1
162 else:
163 stack.pop()
164 return len(stack) != 0
Something went wrong with that request. Please try again.