* Add a warning line to the output when copy.copy() throws an
[reinteract/rox.git] / lib / reinteract / statement.py
blobffc0deb4d1bb30adbf68fb518c0ff1967ffb2b09
1 #!/usr/bin/python
3 import copy
4 import sys
6 import rewrite
7 from custom_result import CustomResult
9 # A wrapper so we don't have to trap all exceptions when running statement.Execute
10 class ExecutionError(Exception):
11 def __init__(self, type, value, traceback):
12 self.type = type
13 self.value = value
14 self.traceback = traceback
16 def __str__(self):
17 return "ExecutionError: " + str(self.cause)
19 class WarningResult(object):
20 def __init__(self, message):
21 self.message = message
23 class Statement:
24 def __init__(self, text, worksheet, parent = None):
25 self.__text = text
26 self.__worksheet = worksheet
27 self.result_scope = None
28 self.results = None
30 # May raise SyntaxError
31 self.__compiled, self.__mutated = rewrite.rewrite_and_compile(self.__text)
33 self.set_parent(parent)
35 def set_parent(self, parent):
36 self.__parent = parent
38 def get_result_scope(self):
39 return self.result_scope
41 def do_output(self, *args):
42 if len(args) == 1:
43 arg = args[0]
45 if args[0] == None:
46 return
47 elif isinstance(args[0], CustomResult):
48 self.results.append(args[0])
49 else:
50 self.results.append(repr(args[0]))
51 self.result_scope['_'] = args[0]
52 else:
53 self.results.append(repr(args))
54 self.result_scope['_'] = args
56 def do_print(self, *args):
57 self.results.append(" ".join(map(str, args)))
59 def execute(self):
60 root_scope = self.__worksheet.global_scope
61 if self.__parent:
62 scope = copy.copy(self.__parent.result_scope)
63 else:
64 scope = copy.copy(root_scope)
66 self.results = []
67 self.result_scope = scope
69 for mutation in self.__mutated:
70 if isinstance(mutation, tuple):
71 variable, method = mutation
72 else:
73 variable = mutation
75 try:
76 scope[variable] = copy.copy(scope[variable])
77 except:
78 self.results.append(WarningResult("Variable '%s' apparently modified, but can't copy it" % variable))
80 root_scope['__reinteract_statement'] = self
81 try:
82 exec self.__compiled in scope, scope
83 except:
84 self.results = None
85 self.result_scope = None
86 type, value, traceback = sys.exc_info()
87 raise ExecutionError(type, value, traceback)
88 finally:
89 root_scope['__reinteract_statement'] = None
91 if __name__=='__main__':
92 def expect(actual,expected):
93 if actual != expected:
94 raise AssertionError("Got: '%s'; Expected: '%s'" % (actual, expected))
96 def expect_result(text, result):
97 s = Statement(text)
98 s.execute()
99 expect(s.results[0], result)
101 # A bare expression should give the repr of the expression
102 expect_result("'a'", repr('a'))
103 expect_result("1,2", repr((1,2)))
105 # Print, on the other hand, gives the string form of the expression
106 expect_result("print 'a'", 'a')
108 # Test that we copy a variable before mutating it (when we can detect
109 # the mutation)
110 s1 = Statement("b = [0]")
111 s1.execute()
112 s2 = Statement("b[0] = 1", parent=s1)
113 s2.execute()
114 s3 = Statement("b[0]", parent = s2)
115 s3.execute()
116 expect(s3.results[0], "1")
118 s2a = Statement("b[0]", parent=s1)
119 s2a.execute()
120 expect(s2a.results[0], "0")