[pypy-svn] r44833 - in pypy/dist/pypy/lang/js: . test
santagada at codespeak.net
santagada at codespeak.net
Sat Jul 7 21:31:42 CEST 2007
Author: santagada
Date: Sat Jul 7 21:31:40 2007
New Revision: 44833
Modified:
pypy/dist/pypy/lang/js/astbuilder.py
pypy/dist/pypy/lang/js/js_interactive.py
pypy/dist/pypy/lang/js/test/test_astbuilder.py
pypy/dist/pypy/lang/js/test/test_interactive.py
Log:
after a long hiatus, fixed a problem discovered by arigo with multiple calls happening one after the other and a new js_interactive contributed by Nilton
Volpato <nilton.volpato at gmail.com>
Modified: pypy/dist/pypy/lang/js/astbuilder.py
==============================================================================
--- pypy/dist/pypy/lang/js/astbuilder.py (original)
+++ pypy/dist/pypy/lang/js/astbuilder.py Sat Jul 7 21:31:40 2007
@@ -260,8 +260,11 @@
def visit_callexpression(self, node):
pos = self.get_pos(node)
left = self.dispatch(node.children[0])
- right = self.dispatch(node.children[1])
- return operations.Call(pos, left, right)
+ for rightnode in node.children[1:]:
+ right = self.dispatch(rightnode)
+ left = operations.Call(pos, left, right)
+
+ return left
def visit_assignmentexpression(self, node):
pos = self.get_pos(node)
Modified: pypy/dist/pypy/lang/js/js_interactive.py
==============================================================================
--- pypy/dist/pypy/lang/js/js_interactive.py (original)
+++ pypy/dist/pypy/lang/js/js_interactive.py Sat Jul 7 21:31:40 2007
@@ -7,11 +7,10 @@
import autopath
import sys
import getopt
-from pypy.lang.js.interpreter import *
+from pypy.lang.js.interpreter import load_source, Interpreter, load_file
+from pypy.lang.js.jsparser import parse, ParseError
from pypy.lang.js.jsobj import W_Builtin, W_String, ThrowException, w_Undefined
-from pypy.lang.js import jsparser
-import os
-import cmd
+from pypy.rlib.streamio import open_file_as_stream
help_message = """
PyPy's JavaScript Interpreter:
@@ -20,10 +19,12 @@
-h show this help message
-d jump to a pdb in case of failure
"""
+import code
+sys.ps1 = 'js> '
+sys.ps2 = '... '
-interactive = True
-
-def setup_readline():
+try:
+ # Setup Readline
import readline
import os
histfile = os.path.join(os.environ["HOME"], ".jspypyhist")
@@ -34,14 +35,13 @@
pass
import atexit
atexit.register(readline.write_history_file, histfile)
+except ImportError:
+ pass
-class Usage(Exception):
- def __init__(self, msg):
- self.msg = msg
def loadjs(ctx, args, this):
- filename = args[0]
- t = load_file(filename.ToString())
+ filename = args[0].ToString()
+ t = load_file(filename)
return t.execute(ctx)
def tracejs(ctx, args, this):
@@ -52,124 +52,99 @@
def quitjs(ctx, args, this):
sys.exit(0)
-
-def main(argv=None):
- # XXX: note. This will not work when translated, because
- # globals cannot be modified (ie. interactive is always True).
- # so I'm adding support which will not be translated, probably
- # for further consideration
- global interactive
- debug = False
- if argv is None:
- argv = sys.argv
- try:
+class JSInterpreter(code.InteractiveConsole):
+ def __init__(self, locals=None, filename="<console>"):
+ code.InteractiveConsole.__init__(self, locals, filename)
+ self.interpreter = Interpreter()
+ self.interpreter.w_Global.Put('quit', W_Builtin(quitjs))
+ self.interpreter.w_Global.Put('load', W_Builtin(loadjs))
+ self.interpreter.w_Global.Put('trace', W_Builtin(tracejs))
+
+
+ def runcodefromfile(self, filename):
+ f = open_file_as_stream(filename)
+ self.runsource(f.readall())
+ f.close()
+
+ def runcode(self, ast):
+ """Run the javascript code in the AST. All exceptions raised
+ by javascript code must be caught and handled here. When an
+ exception occurs, self.showtraceback() is called to display a
+ traceback.
+ """
try:
- opts, args = getopt.getopt(argv[1:], "hdnf:", ["help",])
- except getopt.error, msg:
- raise Usage(msg)
-
- # option processing
- filenames = []
- for option, value in opts:
- if option == "-f":
- filenames.append(value)
- if option == "-n":
- interactive = False
- if option in ("-h", "--help"):
- raise Usage(help_message)
- if option == '-d':
- debug = True
-
- except Usage, err:
- print >> sys.stderr, sys.argv[0].split("/")[-1] + ": " + str(err.msg)
- print >> sys.stderr, "\t for help use --help"
- return 2
-
- interp = Interpreter()
-
- interp.w_Global.Put('quit', W_Builtin(quitjs))
- interp.w_Global.Put('load', W_Builtin(loadjs))
- interp.w_Global.Put('trace', W_Builtin(tracejs))
- for filename in filenames:
+ res = self.interpreter.run(ast)
+ if res not in (None, w_Undefined):
+ try:
+ print res.GetValue().ToString(self.interpreter.w_Global)
+ except ThrowException, exc:
+ print exc.exception.ToString(self.interpreter.w_Global)
+ except SystemExit:
+ raise
+ except ThrowException, exc:
+ self.showtraceback(exc)
+ else:
+ if code.softspace(sys.stdout, 0):
+ print
+
+ def runsource(self, source, filename="<input>"):
+ """Parse and run source in the interpreter.
+
+ One of these cases can happen:
+ 1) The input is incorrect. Prints a nice syntax error message.
+ 2) The input in incomplete. More input is required. Returns None.
+ 3) The input is complete. Executes the source code.
+ """
try:
- loadjs(interp.global_context, [W_String(filename)], None)
- # XXX we should catch more stuff here, like not implemented
- # and such
- except (jsparser.ParseError, ThrowException), e:
- if isinstance(e, jsparser.ParseError):
- print "\nSyntax error!"
- raise
- elif isinstance(e, ThrowException):
- print "\nJS Exception thrown!"
- return
-
- #while interactive:
- # res = interp.run(load_source(raw_input("js-pypy> ")))
- # if res is not None:
- # print res
- if interactive:
- MyCmd(interp, debug).cmdloop()
-
-class MyCmd(cmd.Cmd):
- prompt = "js-pypy> "
- def __init__(self, interp, debug):
- cmd.Cmd.__init__(self)
- setup_readline()
- self.debug = debug
- self.interp = interp
- self.reset()
-
- def reset(self):
- self.prompt = self.__class__.prompt
- self.lines = []
- self.level = 0
-
- def emptyline(self):
- pass
-
- def default(self, line):
- # let's count lines and continue till matching proper nr of {
- # XXX: '{' will count as well
- # we can avoid this by using our own's tokeniser, when we possess one
- if line == 'EOF':
- print "\nQuitting"
- sys.exit()
- opens = line.count('{')
- closes = line.count('}')
- self.level += opens - closes
- self.lines.append(line)
- if self.level > 0:
- self.prompt = ' ... '
- return
- elif self.level < 0:
- print "\nError!!! Too many closing braces"
- self.level = 0
- return
- try:
- try:
- res = self.interp.run(load_source("\n".join(self.lines)))
- # XXX we should catch more stuff here, like not implemented
- # and such
- except (jsparser.ParseError, ThrowException), e:
- e_info = sys.exc_info()
- if self.debug:
- import pdb
- pdb.post_mortem(e_info[2])
- else:
- if isinstance(e, jsparser.ParseError):
- print "\nSyntax error!"
- elif isinstance(e, ThrowException):
- print e.exception.ToString()
- return
- finally:
- self.reset()
- if (res is not None) and (res is not w_Undefined):
- try:
- print res.GetValue().ToString(self.interp.w_Global)
- except ThrowException, e:
- print e.exception.ToString(self.interp.w_Global)
-
-if __name__ == "__main__":
- import py
- py.test.config.parse([])
- sys.exit(main())
+ ast = load_source(source)
+ except ParseError, exc:
+ if exc.source_pos.i == len(source):
+ # Case 2
+ return True # True means that more input is needed
+ else:
+ # Case 1
+ self.showsyntaxerror(filename, exc)
+ return False
+
+ # Case 3
+ self.runcode(ast)
+ return False
+
+ def showtraceback(self, exc):
+ # XXX format exceptions nicier
+ print exc.exception.ToString()
+
+ def showsyntaxerror(self, filename, exc):
+ # XXX format syntax errors nicier
+ print ' '*4 + \
+ ' '*exc.source_pos.columnno + \
+ '^'
+ print 'Syntax Error'
+
+ def interact(self, banner=None):
+ if banner is None:
+ banner = 'PyPy JavaScript Interpreter'
+ code.InteractiveConsole.interact(self, banner)
+
+def main(inspect=False, filename=None, args=[]):
+ jsi = JSInterpreter()
+ if filename is not None:
+ jsi.runcodefromfile(filename)
+ if (filename is None) or inspect:
+ jsi.interact()
+
+if __name__ == '__main__':
+ from optparse import OptionParser
+ parser = OptionParser(usage='%prog [options] [file] [arg] ...',
+ description='PyPy JavaScript Interpreter')
+ parser.add_option('-i', dest='inspect',
+ action='store_true', default=False,
+ help='inspect interactively after running script')
+ # ... (add other options)
+ opts, args = parser.parse_args()
+
+ if args:
+ main(inspect=opts.inspect, filename=args[0], args=args[1:])
+ else:
+ main(inspect=opts.inspect)
+ sys.exit(0)
Modified: pypy/dist/pypy/lang/js/test/test_astbuilder.py
==============================================================================
--- pypy/dist/pypy/lang/js/test/test_astbuilder.py (original)
+++ pypy/dist/pypy/lang/js/test/test_astbuilder.py Sat Jul 7 21:31:40 2007
@@ -1,12 +1,13 @@
from pypy.lang.js.jsparser import parse
from pypy.lang.js.astbuilder import ASTBuilder
from pypy.lang.js import operations
+from pypy.lang.js.operations import Call
def to_ast(s):
print s
tp = parse(s)
print tp
- ASTBuilder().dispatch(tp)
+ return ASTBuilder().dispatch(tp)
def test_simple():
yield to_ast, "1;"
@@ -25,3 +26,8 @@
def test_funcvarfinder():
pos = operations.Position()
+def test_callcall():
+ p = to_ast('x()()')
+ c1 = p.body.nodes[0]
+ assert isinstance(c1, Call)
+ assert isinstance(c1.left, Call)
Modified: pypy/dist/pypy/lang/js/test/test_interactive.py
==============================================================================
--- pypy/dist/pypy/lang/js/test/test_interactive.py (original)
+++ pypy/dist/pypy/lang/js/test/test_interactive.py Sat Jul 7 21:31:40 2007
@@ -1,6 +1,7 @@
import py
import sys
+py.test.skip("problems to run those on pypy test server")
class TestInteraction:
"""
These tests require pexpect (UNIX-only).
More information about the Pypy-commit
mailing list