[pypy-svn] r28282 - in pypy/dist/pypy/translator/js2: . modules test test/html

fijal at codespeak.net fijal at codespeak.net
Sun Jun 4 18:19:42 CEST 2006


Author: fijal
Date: Sun Jun  4 18:19:37 2006
New Revision: 28282

Added:
   pypy/dist/pypy/translator/js2/modules/
   pypy/dist/pypy/translator/js2/modules/__init__.py
   pypy/dist/pypy/translator/js2/modules/dom.py
   pypy/dist/pypy/translator/js2/test/html/
   pypy/dist/pypy/translator/js2/test/html/test.html
   pypy/dist/pypy/translator/js2/test/test_dom.py
Modified:
   pypy/dist/pypy/translator/js2/_builtin.py
   pypy/dist/pypy/translator/js2/database.py
   pypy/dist/pypy/translator/js2/function.py
   pypy/dist/pypy/translator/js2/opcodes.py
   pypy/dist/pypy/translator/js2/support.py
   pypy/dist/pypy/translator/js2/test/browsertest.py
   pypy/dist/pypy/translator/js2/test/runtest.py
   pypy/dist/pypy/translator/js2/test/test_jseval.py
Log:
Preliminary DOM support.


Modified: pypy/dist/pypy/translator/js2/_builtin.py
==============================================================================
--- pypy/dist/pypy/translator/js2/_builtin.py	(original)
+++ pypy/dist/pypy/translator/js2/_builtin.py	Sun Jun  4 18:19:37 2006
@@ -2,7 +2,7 @@
 """ several builtins mapping
 """
 
-from pypy.rpython.ootypesystem.ootype import List, Meth, Void, String
+from pypy.rpython.ootypesystem.ootype import List, Meth, Void, String, Instance
 
 from pypy.translator.js2.log import log
 
@@ -11,45 +11,49 @@
 SETITEM = 1
 
 class _Builtins(object):
+    # Returns builtin function mapping + property flag or attribute to call (plain string)
     BUILTIN_MAP = {
-        'js_jseval' : ('eval', False),
-        'newlist' : ('[]', True),
-        'alloc_and_set' : ('alloc_and_set', False),
-        'strconcat' : ('strconcat', False),
-        'stritem' : ('stritem', False),
-        'delitem_nonneg' : ('delitem', False),
-        'streq' : 'equal',
-        'strcmp' : ('strcmp', False),
-        'startswith' : ('startswith', False),
-        'endswith' : ('endswith', False),
+        'll_js_jseval' : ('eval', False),
+        'll_newlist' : ('[]', True),
+        'll_alloc_and_set' : ('alloc_and_set', False),
+        'll_strconcat' : ('strconcat', False),
+        'll_stritem' : ('stritem', False),
+        'll_delitem_nonneg' : ('delitem', False),
+        'll_streq' : ['equal'],
+        'll_strcmp' : ('strcmp', False),
+        'll_startswith' : ('startswith', False),
+        'll_endswith' : ('endswith', False),
+        'll_int' : ('parseInt', False),
+        'get_document' : ('document', True),
     }
 
     BUILTIN_METHOD_MAP = {
         List: {
-            'll_setitem_fast' : 'list_ll_setitem',
-            'll_getitem_fast' : 'list_ll_getitem',
-            '_ll_resize' : 'list_ll_resize',
-            '_ll_resize_ge' : 'list_ll_resize',
-            '_ll_resize_le' : 'list_ll_resize',
+            'll_setitem_fast' : ['list_ll_setitem'],
+            'll_getitem_fast' : ['list_ll_getitem'],
+            '_ll_resize' : ['list_ll_resize'],
+            '_ll_resize_ge' : ['list_ll_resize'],
+            '_ll_resize_le' : ['list_ll_resize'],
             'll_length' : ('length', True),
         },
         String.__class__: {
             'll_strlen' : ('length', True),
-            'll_stritem_nonneg' : 'list_ll_getitem',
+            'll_stritem_nonneg' : ['list_ll_getitem'],
+        }
+    }
+    
+    # Return builtin class/method property mapping + getter/setter flag
+    BUILTINS_METHOD_PROPERTY_MAP = {
+        'dom.Node': {
+            'setInnerHTML' : ('innerHTML', True),
         }
     }
     
     def real_name(self, _name):
-        name = _name.split('__')[0]
-        m = re.match("^ll_(.*)$", name)
-        if not m:
-            return None
-        return m.group(1)
+        return _name.split('__')[0]
 
     def map_builtin_function(self, const, inst, args, generator):
         name = self.real_name(const.value._name)
-        if name is None:
-            return None
         
         if getattr(const.value, 'suggested_primitive', False):
             log("Suggested primitive %r"%const)
@@ -58,20 +62,38 @@
             if isinstance(model, tuple):
                 return model
             else:
-                getattr(inst, model)(None, args, generator)
+                getattr(inst, model[0])(None, args, generator, *model[1:])
                 return False
         except KeyError:
             return None
 
+    def is_builtin_object(self, _class, obj, method, args):
+        if not _class is Instance:
+            return None
+        m = re.search("js2\.modules\.(.*)", obj.concretetype._name)
+        if m:
+            real_name = obj.concretetype._methods[method]._name[1:]
+            try:
+                # We define property and property setters here
+                name,val = self.BUILTINS_METHOD_PROPERTY_MAP[m.group(1)][real_name]
+                if val:
+                    return ['setitem',name]
+                return name, True
+            except KeyError:
+                return real_name, False
+        return None
+
     def map_builtin_method(self, base_obj, method, args, inst, generator):
         try:
             log("Baseobj: %r, method: %r"%(base_obj.concretetype, method))
-            model = self.BUILTIN_METHOD_MAP[base_obj.concretetype.__class__][method]
+            model = self.is_builtin_object(base_obj.concretetype.__class__, base_obj, method, args)
+            if not model:
+                model = self.BUILTIN_METHOD_MAP[base_obj.concretetype.__class__][method]
             if isinstance(model,tuple):
                 log("Suggested simple mapping %r"%(model,))
                 return model
             else:
-                getattr(inst, model)(base_obj, args, generator)
+                getattr(inst, model[0])(base_obj, args, generator, *model[1:])
             return False
         except KeyError:
             return None

Modified: pypy/dist/pypy/translator/js2/database.py
==============================================================================
--- pypy/dist/pypy/translator/js2/database.py	(original)
+++ pypy/dist/pypy/translator/js2/database.py	Sun Jun  4 18:19:37 2006
@@ -16,6 +16,7 @@
 from pypy.rpython.ootypesystem import ootype
 
 from pypy.objspace.flow.model import Variable, Constant
+from pypy.translator.js2.modules import dom
 
 try:
     set
@@ -39,6 +40,16 @@
         self.name_manager = JavascriptNameManager(self)
         self.pending_consts = []
         self.cts = type_system_class(self)
+        self.prepare_builtins()
+    
+    def prepare_builtins(self):
+        # Document Object Model elements
+        #for module in [dom]:
+        #    for i in dir(module):
+        #        if not i.startswith('__'):
+        #            # FIXME: shit, strange way of doing it
+        #            self.consts[BuiltinConst(module[i])] = i
+        return
 
     def is_primitive(self, type_):
         if type_ in [Void, Bool, Float, Signed, Unsigned, SignedLongLong, UnsignedLongLong, Char, UniChar] or \
@@ -153,9 +164,12 @@
         if self.is_primitive(type_):
             ilasm.load_const(self.cts.primitive_repr(type_, value))
         else:
-            name = self.record_const(value)
-            ilasm.load_local(self.const_var)
-            ilasm.get_field(name)
+            try:
+                return self.consts[BuiltinConst(value)]
+            except KeyError:
+                name = self.record_const(value)
+                ilasm.load_local(self.const_var)
+                ilasm.get_field(name)
             #assert False, 'Unknown constant %s' % const
 
 
@@ -322,3 +336,21 @@
     def init_fields(self, ilasm, const_var, name):
         pass
 
+class BuiltinConst(AbstractConst):
+    def __init__(self, name):
+        self.name = name
+    
+    def __hash__(self):
+        return hash(self.name)
+    
+    def __eq__(self, other):
+        return self.name == other.name
+    
+    def get_name(self):
+        return self.name
+    
+    def init_fields(self, *args):
+        pass
+    
+    def init(self, ilasm):
+        ilasm.load_str(self.name)

Modified: pypy/dist/pypy/translator/js2/function.py
==============================================================================
--- pypy/dist/pypy/translator/js2/function.py	(original)
+++ pypy/dist/pypy/translator/js2/function.py	Sun Jun  4 18:19:37 2006
@@ -14,6 +14,8 @@
 from pypy.translator.cli.node import Node
 from pypy.translator.cli.class_ import Class
 
+from pypy.translator.js2._builtin import Builtins
+
 from pypy.translator.js2.log import log
 
 import re

Added: pypy/dist/pypy/translator/js2/modules/__init__.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/js2/modules/__init__.py	Sun Jun  4 18:19:37 2006
@@ -0,0 +1,3 @@
+
+""" Support classes needed for javascript to translate
+"""

Added: pypy/dist/pypy/translator/js2/modules/dom.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/js2/modules/dom.py	Sun Jun  4 18:19:37 2006
@@ -0,0 +1,20 @@
+
+""" Document Object Model support
+http://www.w3.org/DOM/ - main standart
+http://www.w3schools.com/dhtml/dhtml_dom.asp - more informal stuff
+"""
+
+# FIXME: this should map somehow to xml.dom interface, or something else
+
+class Node(object):
+    def __init__(self):
+        self.innerHTML = ""
+    
+    def getElementById(self, id):
+        return Node()
+    
+    def setInnerHTML(self, data):
+        self.innerHTML = data
+
+def get_document():
+    return Node()

Modified: pypy/dist/pypy/translator/js2/opcodes.py
==============================================================================
--- pypy/dist/pypy/translator/js2/opcodes.py	(original)
+++ pypy/dist/pypy/translator/js2/opcodes.py	Sun Jun  4 18:19:37 2006
@@ -58,7 +58,10 @@
         graph = op.args[0].value.graph
         #method_name = oopspec.get_method_name(graph, op)
         #if method_name is None:
-        bt = Builtins.map_builtin_function(op.args[0], self, op.args, generator)
+        if op.args[0] in generator.db.name_manager.predefined:
+            bt = op.args[0], False
+        else:
+            bt = Builtins.map_builtin_function(op.args[0], self, op.args, generator)
         if bt:
             builtin, is_property = bt
             self._render_builtin(generator, builtin, op.args, is_property)
@@ -105,6 +108,11 @@
     def do_nothing(self, base_obj, args, generator):
         generator.load_void()
     
+    def setitem(self, base_obj, args, generator, real_name):
+        generator.load(base_obj)
+        generator.load(args[1])
+        generator.set_field(None, real_name)
+    
     def equal(self, base_obj, args, generator):
         generator.load(args[1])
         generator.load(args[2])

Modified: pypy/dist/pypy/translator/js2/support.py
==============================================================================
--- pypy/dist/pypy/translator/js2/support.py	(original)
+++ pypy/dist/pypy/translator/js2/support.py	Sun Jun  4 18:19:37 2006
@@ -49,6 +49,8 @@
             self.reserved[name] = True
 
         self.make_reserved_names(' '.join(self.reserved))
+        
+        self.predefined = set(predefined_classes_and_objects)
 
     def uniquename(self, name):
         #if self.js.compress and name != self.js.functions[0].func_name and is_optimized_function(name) and name.startswith("ll_issubclass__object_vtablePtr_object_vtablePtr"):

Modified: pypy/dist/pypy/translator/js2/test/browsertest.py
==============================================================================
--- pypy/dist/pypy/translator/js2/test/browsertest.py	(original)
+++ pypy/dist/pypy/translator/js2/test/browsertest.py	Sun Jun  4 18:19:37 2006
@@ -1,13 +1,15 @@
-from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
+from BaseHTTPServer import HTTPServer as BaseHTTPServer, BaseHTTPRequestHandler
 import py
 from os   import system
 from cgi  import parse_qs
 from sys  import platform
 from time import sleep
-from webbrowser import open as webbrowser_open
+import webbrowser
 from pypy.translator.js2.log import log
 log = log.browsertest
 
+class HTTPServer(BaseHTTPServer):
+    allow_reuse_address = True
 
 class config:
     http_port = 10001
@@ -86,7 +88,15 @@
         jsfilename = jstest.jsfilename
         jstestcase = jstest.jstestcase
         jscode     = jstest.jscode
-        html_page  = config.html_page % locals()
+        if self.server.html_page:
+            if self.server.is_interactive:
+                isinteractive = ''
+            else:
+                isinteractive = 'resultform.submit();'
+            html_page  = open(self.server.html_page).read() % locals()
+        else:
+            html_page = config.html_page % locals()
+        
         open("html_page.html", "w").write(html_page)
         self.serve_data('text/html', html_page)
         do_status = 'do_GET'
@@ -97,8 +107,15 @@
             self.send_error(404, "File not found")
             return
         form = parse_qs(self.rfile.read(int(self.headers['content-length'])))
-        jstest.result = form['result'][0]
-
+        if self.server.is_interactive:
+            if not form.has_key('ok'):
+                jstest.result = 'Not clicked OK'
+            else:
+                jstest.result = 'OK'
+                #assert False, "Clicked not ok"
+        else:
+            jstest.result = form['result'][0]
+        
         #we force a page refresh here because of two reason:
         # 1. we don't have the next testcase ready yet
         # 2. browser should ask again when we do have a test
@@ -120,9 +137,11 @@
 class BrowserTest(object):
     """The browser driver"""
 
-    def start_server(self, port):
+    def start_server(self, port, html_page, is_interactive):
         server_address = ('', port)
         self.httpd = HTTPServer(server_address, TestHandler)
+        self.httpd.is_interactive = is_interactive
+        self.httpd.html_page = html_page
 
     def get_result(self):
         global do_status
@@ -134,16 +153,20 @@
         return jstest.result
 
 
-def jstest(jsfilename, jstestcase):
+def jstest(jsfilename, jstestcase, browser_to_use, html_page = None, is_interactive = False):
     global driver, jstest
     jstest = TestCase(str(jsfilename), str(jstestcase))
 
     try:
-        driver
+        driver.httpd.html_page = html_page
+        driver.httpd.is_interactive = is_interactive
     except:
         driver = BrowserTest()
-        driver.start_server(config.http_port)
-        webbrowser_open('http://localhost:%d/test.html' % config.http_port)
+        driver.start_server(config.http_port, html_page, is_interactive)
+        if browser_to_use == 'default':
+            browser_to_use = None
+        if browser_to_use != 'none':
+            webbrowser.get(browser_to_use).open('http://localhost:%d/test.html' % config.http_port)
 
     result = driver.get_result()
     return result

Added: pypy/dist/pypy/translator/js2/test/html/test.html
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/js2/test/html/test.html	Sun Jun  4 18:19:37 2006
@@ -0,0 +1,35 @@
+<html>
+<head>
+<script type="text/javascript">
+%(jscode)s
+function runTest() {
+    var result = undefined;
+    try {
+        result = %(jstestcase)s;
+    } catch (e) {
+        try {
+            result = "throw '" + e.toSource() + "'";
+        } catch (dummy) {
+            result = "throw 'unknown javascript exception'";
+        }
+    }
+
+   if (result != undefined) {  // if valid result (no timeout)
+        handle_result(result);
+   }
+}
+function handle_result(result) {
+   var resultform = document.forms['resultform'];
+   resultform.result.value = result;
+   %(isinteractive)s
+};
+</script>
+</head>
+<body onLoad="runTest()">
+<h1 id="dupa">Blah</h1>
+    <form method="post" name="resultform" id="resultform">
+        <input name="result" type="test" value="UNKNOWN" />
+        <input name="ok" value="OK" type="submit"/> <input name="notok" value="Not OK" type="submit"/>
+    </form>
+</body>
+</html>

Modified: pypy/dist/pypy/translator/js2/test/runtest.py
==============================================================================
--- pypy/dist/pypy/translator/js2/test/runtest.py	(original)
+++ pypy/dist/pypy/translator/js2/test/runtest.py	Sun Jun  4 18:19:37 2006
@@ -8,11 +8,11 @@
 from pypy.translator.backendopt.all import backend_optimizations
 from pypy.translator.js2.js import JS
 from pypy.translator.js2.test.browsertest import jstest
-from pypy.translator.js import conftest
+from pypy.translator.js2 import conftest
 from pypy.translator.js2.log import log
 from pypy.conftest import option
 log = log.runtest
-use_browsertest = conftest.option.jsbrowser
+use_browsertest = conftest.option.browser
 
 def _CLI_is_on_path():
     try:
@@ -22,10 +22,12 @@
     return True
 
 class compile_function(object):
-    def __init__(self, function, annotation, stackless=False, view=False):
+    def __init__(self, function, annotation, stackless=False, view=False, html=None, is_interactive=False):
         if not use_browsertest and not _CLI_is_on_path():
             py.test.skip('Javascript CLI (js) not found')
 
+        self.html = html
+        self.is_interactive = is_interactive
         t = TranslationContext()
         t.buildannotator().build_types(function, annotation)
 
@@ -54,7 +56,8 @@
         #    function_call = "slp_entry_point('%s')" % function_call
 
         if use_browsertest:
-            output = jstest(self.js.filename, function_call)
+            log("Used html: %r" % self.html)
+            output = jstest(self.js.filename, function_call, use_browsertest, self.html, self.is_interactive)
         else:
             cmd = 'echo "load(\'%s\'); print(%s)" | js 2>&1' % (self.js.filename, function_call)
             log(cmd)

Added: pypy/dist/pypy/translator/js2/test/test_dom.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/js2/test/test_dom.py	Sun Jun  4 18:19:37 2006
@@ -0,0 +1,23 @@
+
+""" test of DOM related functions
+"""
+
+import py
+
+from pypy.translator.js2.test.runtest import compile_function
+from pypy.translator.js2.modules.dom import get_document
+from pypy.translator.js2 import conftest
+
+import time
+
+if not conftest.option.browser:
+    py.test.skip("Works only in browser (right now?)")
+
+class TestDOM(object):
+    def test_document_base(self):
+        def f():
+            get_document().getElementById("dupa").setInnerHTML("<h1>Fire!</h1>")
+            return get_document().getElementById("dupa")
+        
+        fn = compile_function(f, [], html = 'html/test.html')
+        assert fn() == '[object HTMLHeadingElement]'

Modified: pypy/dist/pypy/translator/js2/test/test_jseval.py
==============================================================================
--- pypy/dist/pypy/translator/js2/test/test_jseval.py	(original)
+++ pypy/dist/pypy/translator/js2/test/test_jseval.py	Sun Jun  4 18:19:37 2006
@@ -4,7 +4,7 @@
 from pypy.translator.js2.test.runtest import compile_function
 from pypy.rpython.lltypesystem import lltype 
 from pypy.rpython.rjs import jseval
-from pypy.translator.js import conftest
+from pypy.translator.js2 import conftest
 
 def jsnative(cmd):
     def do():
@@ -34,7 +34,8 @@
     assert jsnative1_fn() == localtime()[2]
 
 callbacks = []
-n_times_called = lltype.malloc(lltype.GcArray(lltype.Signed), 1) 
+#n_times_called = lltype.malloc(lltype.GcArray(lltype.Signed), 1) 
+n_times_called = [0]
 
 def callback_function():
     n_times_called[0] += 1
@@ -42,7 +43,8 @@
     jseval("setTimeout('callback_function()', 100)")
 
 def test_register_callback():
-    if not conftest.option.jsbrowser:
+    py.test.skip("Hangs")
+    if not conftest.option.browser:
         py.test.skip("works only in a browser (use py.test --browser)")
 
     def register_callback():



More information about the Pypy-commit mailing list