11
|
1 #! /usr/bin/env python
|
|
2
|
10
|
3 import sys
|
|
4 import time
|
|
5 import threading
|
|
6 import traceback
|
|
7 import pydermonkey
|
|
8
|
11
|
9 class InternalError(BaseException):
|
|
10 def __init__(self):
|
|
11 BaseException.__init__(self)
|
|
12 self.exc_info = sys.exc_info()
|
|
13
|
10
|
14 rt = pydermonkey.Runtime()
|
|
15 cx = rt.new_context()
|
|
16 globalobj = cx.new_object()
|
|
17 cx.init_standard_classes(globalobj)
|
|
18
|
11
|
19 def safejsfunc(cx, on_obj, name=None):
|
|
20 def make_wrapper(func):
|
|
21 if name is None:
|
|
22 func_name = func.__name__
|
|
23 else:
|
|
24 func_name = name
|
|
25 def wrapper(func_cx, this, args):
|
|
26 try:
|
|
27 return func(func_cx, this, args)
|
|
28 except pydermonkey.error:
|
|
29 raise
|
|
30 except Exception:
|
|
31 raise InternalError()
|
|
32 cx.define_property(
|
|
33 on_obj,
|
|
34 func_name,
|
|
35 cx.new_function(wrapper, func_name)
|
|
36 )
|
|
37 return func
|
|
38 return make_wrapper
|
|
39
|
|
40 @safejsfunc(cx, globalobj)
|
10
|
41 def foo(cx, this, args):
|
|
42 return cx.call_function(this, args[0], ())
|
|
43
|
11
|
44 @safejsfunc(cx, globalobj, 'print')
|
10
|
45 def jsprint(cx, this, args):
|
|
46 if len(args) > 0:
|
|
47 print args[0]
|
|
48
|
|
49 def opcb(cx):
|
|
50 # Don't do anything; if a keyboard interrupt was triggered,
|
|
51 # it'll get raised here automatically.
|
|
52 pass
|
|
53
|
|
54 cx.set_operation_callback(opcb)
|
|
55
|
|
56 class State(object):
|
|
57 def __init__(self):
|
|
58 self.curr_exc = None
|
|
59 self.curr_tb = None
|
|
60 self.curr_js_stack = None
|
|
61
|
|
62 state = State()
|
|
63
|
|
64 def throwhook(cx):
|
|
65 curr_exc = cx.get_pending_exception()
|
|
66 if state.curr_exc != curr_exc:
|
|
67 state.curr_exc = curr_exc
|
|
68 state.py_stack = traceback.extract_stack()
|
|
69 state.js_stack = cx.get_stack()
|
|
70
|
|
71 cx.set_throw_hook(throwhook)
|
|
72
|
|
73 def watchdog():
|
|
74 while 1:
|
|
75 time.sleep(0.25)
|
|
76 cx.trigger_operation_callback()
|
|
77
|
|
78 thread = threading.Thread(target=watchdog)
|
|
79 thread.setDaemon(True)
|
|
80 thread.start()
|
|
81
|
|
82 filename = 'test.js'
|
|
83
|
|
84 def make_stack(js_stack):
|
|
85 lines = []
|
|
86 while js_stack:
|
|
87 if js_stack['script']:
|
|
88 script = js_stack['script']
|
|
89 thing = dict(filename = script.filename,
|
|
90 lineno = js_stack['lineno'],
|
|
91 name = '<module>')
|
|
92 elif js_stack['function'] and not js_stack['function'].is_python:
|
|
93 func = js_stack['function']
|
|
94 thing = dict(filename = func.filename,
|
|
95 lineno = js_stack['lineno'],
|
|
96 name = func.name)
|
|
97 else:
|
|
98 thing = None
|
|
99 if thing:
|
|
100 lines.insert(0, " File \"%(filename)s\", line %(lineno)d, in %(name)s" % thing)
|
|
101 js_stack = js_stack['caller']
|
|
102 lines.insert(0, "Traceback (most recent call last):")
|
|
103 return '\n'.join(lines)
|
|
104
|
|
105 try:
|
|
106 cx.evaluate_script(globalobj, open(filename).read(), filename, 1)
|
|
107 except pydermonkey.error, e:
|
|
108 print make_stack(state.js_stack)
|
|
109 print e.args[1]
|
11
|
110 except InternalError, e:
|
|
111 print "An internal error occurred."
|
|
112 traceback.print_tb(e.exc_info[2])
|
|
113 print e.exc_info[1]
|