[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