[pypy-svn] r27497 - in pypy/dist/pypy/translator/js2: . test
fijal at codespeak.net
fijal at codespeak.net
Sat May 20 12:13:19 CEST 2006
Author: fijal
Date: Sat May 20 12:13:10 2006
New Revision: 27497
Added:
pypy/dist/pypy/translator/js2/
pypy/dist/pypy/translator/js2/__init__.py
pypy/dist/pypy/translator/js2/asmgen.py
pypy/dist/pypy/translator/js2/function.py
pypy/dist/pypy/translator/js2/jts.py
pypy/dist/pypy/translator/js2/log.py
pypy/dist/pypy/translator/js2/opcodes.py
pypy/dist/pypy/translator/js2/support.py
pypy/dist/pypy/translator/js2/test/
pypy/dist/pypy/translator/js2/test/__init__.py
pypy/dist/pypy/translator/js2/test/browsertest.py
pypy/dist/pypy/translator/js2/test/runtest.py
pypy/dist/pypy/translator/js2/test/test_runtest.py
Log:
Added preliminary version of genjs with ootypesystem support. Supports basic if/while detection.
Added: pypy/dist/pypy/translator/js2/__init__.py
==============================================================================
Added: pypy/dist/pypy/translator/js2/asmgen.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/js2/asmgen.py Sat May 20 12:13:10 2006
@@ -0,0 +1,153 @@
+
+""" backend generator routines
+"""
+
+from pypy.translator.js2.log import log
+
+from pypy.translator.squeak.node import LoopFinder
+
+from StringIO import StringIO
+
+class CodeGenerator(object):
+ def __init__(self, out, indentstep = 4, startblock = '{', endblock = '}'):
+ self._out = out
+ self._indent = 0
+ self._bol = True # begin of line
+ self._indentstep = indentstep
+ self._startblock = startblock
+ self._endblock = endblock
+
+ def write(self, s, indent = 0):
+ indent = self._indent + (indent * self._indentstep)
+
+ if self._bol:
+ self._out.write(' ' * indent)
+
+ self._out.write(s)
+ self._bol = (s and s[-1] == '\n')
+
+ def writeline(self, s=''):
+ self.write(s)
+ self.write('\n')
+
+ def openblock(self):
+ self.writeline(self._startblock)
+ self._indent += self._indentstep
+
+ def closeblock(self):
+ self._indent -= self._indentstep
+ self.writeline(self._endblock)
+
+class Queue ( object ):
+ def __init__ ( self , l , subst_table ):
+ self . l = l [:]
+ self . subst_table = subst_table
+
+ def pop ( self ):
+ el = self . l . pop ()
+ return self . subst_table . get ( el , el )
+
+ def __getattr__ ( self , attr ):
+ return getattr ( self . l , attr )
+
+ def __len__ ( self ):
+ return len(self.l)
+
+class AsmGen ( object ):
+ """ JS 'assembler' generator routines
+ """
+ def __init__ ( self , outfile , name ):
+ self . outfile = outfile
+ self . name = name
+ self . subst_table = {}
+ self . right_hand = Queue ( [] , self . subst_table )
+ self . codegenerator = CodeGenerator ( outfile )
+
+ def show_const ( self ):
+ return False
+
+ def begin_function ( self , name, arglist, returntype, is_entrypoint = False, *args ):
+ args = "," . join ( [ i [ 1 ] for i in arglist ] )
+ self . codegenerator . write ( "function %s (%s) " % ( name , args ) )
+ self . codegenerator . openblock ()
+
+ def end_function ( self ):
+ self . codegenerator . closeblock ()
+
+ def locals ( self , loc ):
+ self . codegenerator . writeline ( "var " + "," . join ( [ i [ 1 ] for i in loc ] ) + ";" )
+
+ def load_arg ( self , v ):
+ self . right_hand . append ( v.name )
+
+ def store_local ( self , v ):
+ name = self . subst_table . get ( v . name , v . name )
+ element = self . right_hand . pop ()
+ if element != name:
+ self . codegenerator . writeline ( "%s = %s;" % ( name , element ) )
+
+ def load_local ( self , v ):
+ self . right_hand . append ( v . name )
+
+ def load_const ( self , _type , v ):
+ self . right_hand . append ( str(v) )
+
+ def ret ( self ):
+ self . codegenerator . writeline ( "return ( %s );" % self . right_hand . pop () )
+
+ def begin_namespace ( self , namespace ):
+ pass
+
+ def end_namespace ( self ):
+ pass
+
+ def begin_class ( self , cl ):
+ pass
+
+ def end_class ( self ):
+ pass
+
+ def emit ( self , opcode , *args ):
+ v1 = self . right_hand . pop ()
+ v2 = self . right_hand . pop ()
+ self . right_hand . append ( "(%s%s%s)" % ( v2 , opcode , v1 ) )
+
+ def call ( self , func ):
+ func_name,args = func
+ real_args = "," . join ( [ self . right_hand . pop () for i in xrange(len(args)) ] )
+ self . right_hand . append ( "%s ( %s )" % ( func_name , real_args ) )
+
+ def branch_if ( self , arg , exitcase ):
+ arg_name = self . subst_table . get ( arg . name , arg . name )
+ self . codegenerator . write ( "if ( %s == %s )" % ( arg_name , exitcase ) )
+ self . codegenerator . openblock ()
+
+ def branch_while ( self , arg , exitcase ):
+ arg_name = self . subst_table . get ( arg . name , arg . name )
+ self . codegenerator . write ( "while ( %s == %s )" % ( arg_name , exitcase ) )
+ self . codegenerator . openblock ()
+
+ def branch_else ( self ):
+ self . codegenerator . closeblock ()
+ self . codegenerator . write ( "else" )
+ self . codegenerator . openblock ()
+
+ def close_branch ( self ):
+ self . codegenerator . closeblock ()
+
+ def label ( self , *args ):
+ self . codegenerator . openblock ()
+
+ def branch ( self , *args ):
+ #self . codegenerator . closeblock ()
+ pass
+
+ def change_name ( self , from_name , to_name ):
+ self . subst_table [ from_name.name ] = to_name.name
+ #pass
+
+ def cast_floor ( self ):
+ self . right_hand . append ( "Math.floor ( %s )" % self . right_hand . pop() )
+
+ #def finish ( self ):
+ # self . outfile . write ( "%r" % self . right_hand )
Added: pypy/dist/pypy/translator/js2/function.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/js2/function.py Sat May 20 12:13:10 2006
@@ -0,0 +1,443 @@
+try:
+ set
+except NameError:
+ from sets import Set as set
+
+from pypy.objspace.flow import model as flowmodel
+from pypy.rpython.lltypesystem.lltype import Signed, Unsigned, Void, Bool, Float
+from pypy.rpython.lltypesystem.lltype import SignedLongLong, UnsignedLongLong
+from pypy.rpython.ootypesystem import ootype
+from pypy.translator.cli.option import getoption
+from pypy.translator.cli.cts import CTS
+from pypy.translator.cli.opcodes import opcodes
+from pypy.translator.cli.metavm import Generator,InstructionList
+from pypy.translator.cli.node import Node
+from pypy.translator.cli.class_ import Class
+
+from pypy.tool.ansi_print import ansi_log
+import py
+log = py.log.Producer("cli")
+py.log.setconsumer("cli", ansi_log)
+
+class LoopFinder:
+
+ def __init__(self, startblock):
+ self.loops = {}
+ self.parents = {startblock: startblock}
+ self.temps = {}
+ self.seen = set ()
+ self.block_seeing_order = {}
+ self.visit_Block(startblock)
+
+ def visit_Block(self, block, switches=[]):
+ #self.temps.has_key()
+ self.seen.add(block)
+ self.block_seeing_order[block] = []
+ if block.exitswitch:
+ switches.append(block)
+ self.parents[block] = block
+ for link in block.exits:
+ self.block_seeing_order[block].append(link)
+ self.visit_Link(link, switches)
+
+ def visit_Link(self, link, switches):
+ if link.target in switches:
+ if len(self.block_seeing_order[link.target]) == 1:
+ self.loops[link.target] = self.block_seeing_order[link.target][0].exitcase
+ else:
+ self.loops[link.target] = self.block_seeing_order[link.target][1].exitcase
+
+ if not link.target in self.seen:
+ self.parents[link.target] = self.parents[link.prevblock]
+ self.visit_Block(link.target, switches)
+
+class Function(Node, Generator):
+ def __init__(self, db, graph, name = None, is_method = False, is_entrypoint = False ):
+ self.db = db
+ self.cts = db.type_system_class(db)
+ self.graph = graph
+ self.name = name or graph.name
+ self.is_method = is_method
+ self.is_entrypoint = is_entrypoint
+ self.blocknum = {}
+ self._set_args()
+ self._set_locals()
+
+ def get_name(self):
+ return self.name
+
+ def __hash__(self):
+ return hash(self.graph)
+
+ def __eq__(self, other):
+ return self.graph == other.graph
+
+ def _is_return_block(self, block):
+ return (not block.exits) and len(block.inputargs) == 1
+
+ def _is_raise_block(self, block):
+ return (not block.exits) and len(block.inputargs) == 2
+
+ def render_block ( self , block ):
+ for op in block.operations:
+ self._render_op(op)
+
+ def render_block ( self , block , stop_block = None ):
+ if block is stop_block:
+ return
+
+ for op in block.operations:
+ self._render_op(op)
+
+ if len ( block . exits ) == 0:
+ # return block
+ return_var = block.inputargs[0]
+ self . load ( return_var )
+ self . ilasm . ret ()
+ elif block . exitswitch is None:
+ # single exit block
+ assert ( len(block.exits) == 1 )
+ link = block . exits [ 0 ]
+ self . _setup_link ( link )
+ self . render_block ( link . target , stop_block )
+ elif block . exitswitch is flowmodel.c_last_exception:
+ raise NotImplementedError ( "Exception handling" )
+ else:
+ if self . loops . has_key ( block ):
+ # we've got loop
+ self . ilasm . branch_while ( block . exitswitch , self . loops [ block ] )
+ exit_case = block . exits [ self . loops [ block ] ]
+ self . _setup_link ( exit_case )
+ self . render_block ( exit_case . target , block )
+ for op in block . operations:
+ self._render_op ( op )
+ self . ilasm . close_branch ()
+ exit_case = block . exits [ not self . loops [ block ] ]
+ self . _setup_link ( exit_case )
+ #log ( )
+ self . render_block ( exit_case . target , block )
+ #raise NotImplementedError ( "loop" )
+ else:
+ # just a simple if
+ assert ( len ( block . exits ) == 2 )
+ self . ilasm . branch_if ( block . exitswitch , True )
+ self . _setup_link ( block . exits [ True ] )
+ self . render_block ( block . exits [ True ] . target , stop_block )
+ self . ilasm . branch_else ()
+ self . _setup_link ( block . exits [ False ] )
+ self . render_block ( block . exits [ False ] . target , stop_block )
+ self . ilasm . close_branch ()
+
+ def render ( self , ilasm ):
+ if self . db . graph_name ( self . graph ) is not None and not self . is_method:
+ return # already rendered
+
+ self . ilasm = ilasm
+
+ self . loops = LoopFinder ( self . graph . startblock ) . loops
+ self . ilasm . begin_function ( self . name , self . args , None , None , None )
+
+ self . render_block ( self . graph . startblock )
+## if self._is_return_block(block):
+## return_blocks.append(block)
+## continue
+##
+## for op in block.operations:
+## self._render_op(op)
+##
+## for link in block.exits:
+## target_label = self._get_block_name(link.target)
+## if link.exitcase is None:
+## pass
+## self.ilasm.branch(target_label)
+## else:
+## assert type(link.exitcase is bool)
+## assert block.exitswitch is not None
+## self.ilasm.branch_if( block.exitswitch, link.exitcase, target_label)
+## self._setup_link(link)
+
+## for block in return_blocks:
+## return_var = block.inputargs[0]
+## if return_var.concretetype is not Void:
+## self.load(return_var)
+## self.ilasm.ret()
+
+ self.ilasm.end_function()
+ if self.is_method:
+ pass # TODO
+ else:
+ self.db.record_function(self.graph, self.name)
+
+ def oldrender(self, ilasm):
+ if self.db.graph_name(self.graph) is not None and not self.is_method:
+ return # already rendered
+
+ loop_finder = LoopFinder ( self . graph . startblock )
+ # Work out it here
+
+ self.ilasm = ilasm
+ graph = self.graph
+ returntype, returnvar = self.cts.llvar_to_cts(graph.getreturnvar())
+
+ self.ilasm.begin_function(self.name, self.args, returntype, None , None )
+ self.ilasm.locals(self.locals)
+
+ return_blocks = []
+ for block in graph.iterblocks():
+ if self._is_return_block(block):
+ return_blocks.append(block)
+ continue
+
+
+ #self.ilasm.label(self._get_block_name(block))
+
+ handle_exc = (block.exitswitch == flowmodel.c_last_exception)
+ if handle_exc:
+ self.ilasm.begin_try()
+
+ for op in block.operations:
+ #self._search_for_classes(op)
+ self._render_op(op)
+
+ if self._is_raise_block(block):
+ exc = block.inputargs[1]
+ self.load(exc)
+ self.ilasm.throw()
+
+ if handle_exc:
+ # search for the "default" block to be executed when no exception is raised
+ for link in block.exits:
+ if link.exitcase is None:
+ self._setup_link(link)
+ target_label = self._get_block_name(link.target)
+ self.ilasm.leave(target_label)
+ self.ilasm.end_try()
+
+ # catch the exception and dispatch to the appropriate block
+ for link in block.exits:
+ if link.exitcase is None:
+ continue # see above
+
+ assert issubclass(link.exitcase, Exception)
+ #cts_exc = self.cts.pyexception_to_cts(link.exitcase)
+ #cts_exc = str(link.exitcase) # TODO: is it a bit hackish?
+ ll_meta_exc = link.llexitcase
+ self.db.record_const(ll_meta_exc)
+ ll_exc = ll_meta_exc._inst.class_._INSTANCE
+ cts_exc = self.cts.lltype_to_cts(ll_exc, False)
+ self.ilasm.begin_catch(cts_exc)
+
+ target = link.target
+ if self._is_raise_block(target):
+ # the exception value is on the stack, use it as the 2nd target arg
+ assert len(link.args) == 2
+ assert len(target.inputargs) == 2
+ self.store(link.target.inputargs[1])
+ else:
+ # pop the unused exception value
+ self.ilasm.pop()
+ self._setup_link(link)
+
+ target_label = self._get_block_name(target)
+ self.ilasm.leave(target_label)
+ self.ilasm.end_catch()
+
+ else:
+ # no exception handling, follow block links
+ for link in block.exits:
+ target_label = self._get_block_name(link.target)
+ if link.exitcase is None:
+ pass
+ #self.ilasm.branch(target_label)
+ else:
+ assert type(link.exitcase is bool)
+ assert block.exitswitch is not None
+ self.ilasm.branch_if( block.exitswitch, link.exitcase, target_label)
+ self._setup_link(link)
+ self.ilasm.close_branch()
+
+ # render return blocks at the end just to please the .NET
+ # runtime that seems to need a return statement at the end of
+ # the function
+ for block in return_blocks:
+ #self.ilasm.label(self._get_block_name(block))
+ return_var = block.inputargs[0]
+ if return_var.concretetype is not Void:
+ self.load(return_var)
+ self.ilasm.ret()
+
+ self.ilasm.end_function()
+ if self.is_method:
+ pass # TODO
+ else:
+ self.db.record_function(self.graph, self.name)
+
+ def _setup_link(self, link):
+ target = link.target
+ for to_load, to_store in zip(link.args, target.inputargs):
+ if to_load.concretetype is not Void:
+ self.load(to_load)
+ self.store(to_store)
+
+
+ def _set_locals(self):
+ # this code is partly borrowed from pypy.translator.c.funcgen.FunctionCodeGenerator
+ # TODO: refactoring to avoid code duplication
+
+ graph = self.graph
+ mix = [graph.getreturnvar()]
+ for block in graph.iterblocks():
+ self.blocknum[block] = len(self.blocknum)
+ mix.extend(block.inputargs)
+
+ for op in block.operations:
+ mix.extend(op.args)
+ mix.append(op.result)
+ if getattr(op, "cleanup", None) is not None:
+ cleanup_finally, cleanup_except = op.cleanup
+ for cleanupop in cleanup_finally + cleanup_except:
+ mix.extend(cleanupop.args)
+ mix.append(cleanupop.result)
+ for link in block.exits:
+ mix.extend(link.getextravars())
+ mix.extend(link.args)
+
+ # filter only locals variables, i.e.:
+ # - must be variables
+ # - must appear only once
+ # - must not be function parameters
+ # - must not have 'void' type
+
+ args = {}
+ for ctstype, name in self.args:
+ args[name] = True
+
+ locals = []
+ seen = {}
+ for v in mix:
+ is_var = isinstance(v, flowmodel.Variable)
+ if id(v) not in seen and is_var and v.name not in args and v.concretetype is not Void:
+ locals.append(self.cts.llvar_to_cts(v))
+ seen[id(v)] = True
+
+ self.locals = locals
+
+ def _set_args(self):
+ args = [arg for arg in self.graph.getargs() if arg.concretetype is not Void]
+ self.args = map(self.cts.llvar_to_cts, args)
+ self.argset = set([argname for argtype, argname in self.args])
+
+ def _get_block_name(self, block):
+ return 'block%s' % self.blocknum[block]
+
+ def _search_for_classes(self, op):
+ for arg in op.args:
+ lltype = None
+ if isinstance(arg, flowmodel.Variable):
+ lltype = arg.concretetype
+ elif isinstance(arg, flowmodel.Constant):
+ lltype = arg.value
+
+ if isinstance(lltype, ootype._view) and isinstance(lltype._inst, ootype._instance):
+ lltype = lltype._inst._TYPE
+
+ if isinstance(lltype, ootype.Instance):
+ self.db.pending_class(lltype)
+
+ def _render_op(self, op):
+ # FIXME: what to do here?
+ instr_list = self.db.opcode_dict.get(op.opname, None)
+ if instr_list is not None:
+ #assert isinstance(instr_list, InstructionList)
+ instr_list.render(self, op)
+ else:
+ if getoption('nostop'):
+ log.WARNING('Unknown opcode: %s ' % op)
+ self.ilasm.opcode(str(op))
+ else:
+ assert False, 'Unknown opcode: %s ' % op
+
+ def field_name(self, obj, field):
+ class_, type_ = obj._lookup_field(field)
+ assert type_ is not None, 'Cannot find the field %s in the object %s' % (field, obj)
+
+ class_name = self.class_name(class_)
+ field_type = self.cts.lltype_to_cts(type_)
+ return (field_type, class_name, field)
+
+ # following methods belongs to the Generator interface
+
+ def function_signature(self, graph):
+ return self.cts.graph_to_signature(graph, False)
+
+ def class_name(self, ooinstance):
+ return ooinstance._name
+
+ def emit(self, instr, *args):
+ self.ilasm.emit(instr, *args)
+
+ def call_graph(self, graph):
+ self.db.pending_function(graph)
+ func_sig = self.function_signature(graph)
+ self.ilasm.call(func_sig)
+
+ def call_signature(self, signature):
+ self.ilasm.call(signature)
+
+ def cast_to(self, lltype):
+ cts_type = self.cts.lltype_to_cts(lltype, False)
+ self.ilasm.castclass(cts_type)
+
+ def new(self, obj):
+ self.ilasm.new(self.cts.ctor_name(obj))
+
+ def set_field(self, obj, name):
+ self.ilasm.set_field(self.field_name(obj,name))
+
+ def get_field(self, obj, name):
+ self.ilasm.get_field(self.field_name(obj,name))
+
+ def call_method(self, obj, name):
+ # TODO: use callvirt only when strictly necessary
+ signature, virtual = self.cts.method_signature(obj, name)
+ self.ilasm.call_method(signature, virtual)
+
+ def load(self, v):
+ if isinstance(v, flowmodel.Variable):
+ if v.name in self.argset:
+ selftype, selfname = self.args[0]
+ if self.is_method and v.name == selfname:
+ self.ilasm.load_self()
+ else:
+ self.ilasm.load_arg(v)
+ else:
+ self.ilasm.load_local(v)
+
+ elif isinstance(v, flowmodel.Constant):
+ self._load_const(v)
+ else:
+ assert False
+
+ def _load_const(self, const):
+ type_ = const.concretetype
+ if type_ in [ Void , Bool , Float , Signed , Unsigned , SignedLongLong , UnsignedLongLong ]:
+ self.ilasm.load_const(type_,const.value)
+ else:
+ name = self.db.record_const(const.value)
+ cts_type = self.cts.lltype_to_cts(type_)
+ self.ilasm.load_set_field(cts_type,name)
+ #assert False, 'Unknown constant %s' % const
+
+ def store(self, v):
+ if isinstance(v, flowmodel.Variable):
+ if v.concretetype is not Void:
+ self.ilasm.store_local(v)
+ else:
+ assert False
+
+ def change_name(self, name, to_name):
+ self.ilasm.change_name(name, to_name)
+
+ def cast_floor(self):
+ self.ilasm.cast_floor()
+
Added: pypy/dist/pypy/translator/js2/jts.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/js2/jts.py Sat May 20 12:13:10 2006
@@ -0,0 +1,52 @@
+
+""" JavaScript type system
+"""
+
+from pypy.rpython.ootypesystem import ootype
+
+class JTS ( object ):
+ """ Class implementing JavaScript type system
+ calls with mapping similiar to cts
+ """
+ def __init__ ( self , db ):
+ self . db = db
+
+ def llvar_to_cts ( self , var ):
+ return 'var ',var.name
+
+ def graph_to_signature(self, graph, is_method = False, func_name = None):
+ ret_type, ret_var = self.llvar_to_cts(graph.getreturnvar())
+ func_name = func_name or graph.name
+
+ args = [arg for arg in graph.getargs() if arg.concretetype is not ootype.Void]
+ if is_method:
+ args = args[1:]
+
+ #arg_types = [self.lltype_to_cts(arg.concretetype) for arg in args]
+ #arg_list = ', '.join(arg_types)
+
+ return func_name,args
+
+ def lltype_to_cts(self, t, include_class=True):
+ return 'var'
+## if isinstance(t, ootype.Instance):
+## self.db.pending_class(t)
+## return self.__class(t._name, include_class)
+## elif isinstance(t, ootype.Record):
+## name = self.db.pending_record(t)
+## return self.__class(name, include_class)
+## elif isinstance(t, ootype.StaticMethod):
+## return 'void' # TODO: is it correct to ignore StaticMethod?
+## elif isinstance(t, ootype.List):
+## item_type = self.lltype_to_cts(t._ITEMTYPE)
+## return self.__class(PYPY_LIST % item_type, include_class)
+## elif isinstance(t, ootype.Dict):
+## key_type = self.lltype_to_cts(t._KEYTYPE)
+## value_type = self.lltype_to_cts(t._VALUETYPE)
+## return self.__class(PYPY_DICT % (key_type, value_type), include_class)
+## elif isinstance(t, ootype.DictItemsIterator):
+## key_type = self.lltype_to_cts(t._KEYTYPE)
+## value_type = self.lltype_to_cts(t._VALUETYPE)
+## return self.__class(PYPY_DICT_ITEMS_ITERATOR % (key_type, value_type), include_class)
+##
+## return _get_from_dict(_lltype_to_cts, t, 'Unknown type %s' % t)
Added: pypy/dist/pypy/translator/js2/log.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/js2/log.py Sat May 20 12:13:10 2006
@@ -0,0 +1,4 @@
+import py
+from pypy.tool.ansi_print import ansi_log
+log = py.log.Producer("js2")
+py.log.setconsumer("js2", ansi_log)
Added: pypy/dist/pypy/translator/js2/opcodes.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/js2/opcodes.py Sat May 20 12:13:10 2006
@@ -0,0 +1,108 @@
+
+""" opcode definitions
+"""
+
+from pypy.translator.cli.metavm import PushArg, PushAllArgs, StoreResult,\
+ InstructionList, New, SetField, GetField, CallMethod, RuntimeNew, Call, MicroInstruction
+
+DoNothing = [PushAllArgs]
+
+class _SameAs ( MicroInstruction ):
+ def render ( self , generator , op ):
+ generator.change_name(op.result,op.args[0])
+
+class _CastFloor ( MicroInstruction ):
+ def render ( self , generator , op ):
+ generator.cast_floor()
+
+CastFloor = [ PushAllArgs , _CastFloor() ]
+CopyName = [ PushAllArgs , _SameAs () ]
+SameAs = CopyName
+
+opcodes = {'int_mul': '*',
+ 'int_add': '+',
+ 'int_sub': '-',
+ 'int_floordiv': '/',
+ 'int_mod': '%',
+ 'int_and': '&',
+ 'int_or': '|',
+ 'int_xor': '^',
+ 'int_lshift': '<<',
+ 'int_rshift': '>>',
+ 'int_lt': '<',
+ 'int_le': '<=',
+ 'int_eq': '==',
+ 'int_ne': '!=',
+ 'int_ge': '>=',
+ 'int_gt': '>',
+
+ 'uint_mul': '*',
+ 'uint_add': '+',
+ 'uint_sub': '-',
+ 'uint_floordiv': '/',
+ 'uint_mod': '%',
+ 'uint_and': '&',
+ 'uint_or': '|',
+ 'uint_xor': '^',
+ 'uint_lshift': '<<',
+ 'uint_rshift': '>>',
+ 'uint_lt': '<',
+ 'uint_le': '<=',
+ 'uint_eq': '==',
+ 'uint_ne': '!=',
+ 'uint_ge': '>=',
+ 'uint_gt': '>',
+
+ 'unichar_lt': '<',
+ 'unichar_le': '<=',
+ 'unichar_eq': '==',
+ 'unichar_ne': '!=',
+ 'unichar_ge': '>=',
+ 'unichar_gt': '>',
+
+ 'float_mul': '*',
+ 'float_add': '+',
+ 'float_sub': '-',
+ 'float_truediv': '/',
+ 'float_mod': '%',
+ 'float_lt': '<',
+ 'float_le': '<=',
+ 'float_eq': '==',
+ 'float_ne': '!=',
+ 'float_ge': '>=',
+ 'float_gt': '>',
+
+ 'ptr_eq': '==',
+ 'ptr_ne': '!=',
+
+ 'direct_call' : [Call],
+ 'same_as' : SameAs,
+ # when casting from bool we want that every truth value is casted
+ # to 1: we can't simply DoNothing, because the CLI stack could
+ # contains a truth value not equal to 1, so we should use the !=0
+ # trick.
+ 'cast_bool_to_int': CopyName,
+ 'cast_bool_to_uint': CopyName,
+ 'cast_bool_to_float': CopyName,
+ 'cast_char_to_int': CopyName,
+ 'cast_unichar_to_int': CopyName,
+ 'cast_int_to_char': CopyName,
+ 'cast_int_to_unichar': CopyName,
+ 'cast_int_to_uint': CopyName,
+ 'cast_int_to_float': CopyName,
+ 'cast_int_to_longlong': CopyName,
+ 'cast_uint_to_int': CopyName,
+ 'cast_float_to_int': CastFloor,
+ 'cast_float_to_uint': CastFloor,
+ 'truncate_longlong_to_int': CopyName,
+}
+
+for key, value in opcodes.iteritems():
+ if type(value) is str:
+ value = InstructionList([PushAllArgs, value, StoreResult])
+ elif value is not None:
+ if StoreResult not in value:
+ value.append(StoreResult)
+ value = InstructionList(value)
+
+ opcodes[key] = value
Added: pypy/dist/pypy/translator/js2/support.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/js2/support.py Sat May 20 12:13:10 2006
@@ -0,0 +1,61 @@
+from pypy.translator.gensupp import NameManager
+#from pypy.translator.js2.optimize import is_optimized_function
+
+class JavascriptNameManager(NameManager):
+ def __init__(self, js):
+ NameManager.__init__(self)
+ self.js = js
+ self.reserved = {}
+
+ #http://javascript.about.com/library/blreserved.htm
+ reserved_words = '''
+ abstract as boolean break byte case catch
+ char class continue const debugger default delete
+ do double else enum export extends false
+ final finally float for function goto if implements
+ import in instanceof int interface is long
+ namespace native new null package private protected
+ public return short static super switch synchronized
+ this throw throws transient true try typeof
+ use var void volatile while with
+ '''
+ for name in reserved_words.split():
+ self.reserved[name] = True
+
+ #http://javascript.about.com/library/blclassobj.htm
+ predefined_classes_and_objects = '''
+ Anchor anchors Applet applets Area Array Body
+ Button Checkbox Date document Error EvalError FileUpload
+ Form forms frame frames Function Hidden History
+ history Image images Link links location Math
+ MimeType mimetypes navigator Number Object Option options
+ Password Plugin plugins Radio RangeError ReferenceError RegExp
+ Reset screen Script Select String Style StyleSheet
+ Submit SyntaxError Text Textarea TypeError URIError window
+ '''
+ for name in predefined_classes_and_objects.split():
+ self.reserved[name] = True
+
+ #http://javascript.about.com/library/blglobal.htm
+ global_properties_and_methods = '''
+ _content closed Components controllers crypto defaultstatus directories
+ document frames history innerHeight innerWidth length location
+ locationbar menubar name navigator opener outerHeight outerWidth
+ pageXOffset pageYOffset parent personalbar pkcs11 prompter screen
+ screenX screenY scrollbars scrollX scrollY self statusbar
+ toolbar top window
+ '''
+ for name in global_properties_and_methods.split():
+ self.reserved[name] = True
+
+ self.make_reserved_names(' '.join(self.reserved))
+
+ 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"):
+ # name = 'f'
+ return NameManager.uniquename(self, name)
+
+ def ensure_non_reserved(self, name):
+ while name in self.reserved:
+ name += '_'
+ return name
Added: pypy/dist/pypy/translator/js2/test/__init__.py
==============================================================================
Added: pypy/dist/pypy/translator/js2/test/browsertest.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/js2/test/browsertest.py Sat May 20 12:13:10 2006
@@ -0,0 +1,149 @@
+from BaseHTTPServer import HTTPServer, 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
+from pypy.translator.js2.log import log
+log = log.browsertest
+
+
+class config:
+ http_port = 10001
+
+ html_page = """<html>
+<head>
+<script type="text/javascript">
+%(jscode)s
+// code for running the unittest...
+
+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 || !in_browser) { // if valid result (no timeout)
+ handle_result(result);
+ }
+};
+
+function handle_result(result) {
+ var resultform = document.forms['resultform'];
+ if (typeof(result) == typeof({})) {
+ result = result.chars; //assume it's a rpystring
+ }
+ resultform.result.value = result;
+ resultform.submit();
+};
+</script>
+</head>
+<body onload="runTest()">
+ %(jsfilename)s
+ <form method="post" name="resultform" id="resultform">
+ <input name="result" type="hidden" value="UNKNOWN" />
+ </form>
+ <div id="logdiv"></div>
+</body>
+</html>"""
+
+ refresh_page = """<html>
+<head>
+<meta http-equiv="refresh" content="0">
+</head>
+<body>
+<pre>
+// testcase: %(jstestcase)s
+%(jscode)s
+</pre>
+</body>
+</html>"""
+
+
+class TestCase(object):
+ def __init__(self, jsfilename, jstestcase):
+ self.jsfilename = jsfilename
+ self.jscode = open(jsfilename).read()
+ self.jstestcase = jstestcase
+ self.result = None
+
+
+class TestHandler(BaseHTTPRequestHandler):
+ """The HTTP handler class that provides the tests and handles results"""
+
+ def do_GET(self):
+ global do_status
+ if self.path != "/test.html":
+ self.send_error(404, "File not found")
+ return
+ jsfilename = jstest.jsfilename
+ jstestcase = jstest.jstestcase
+ jscode = jstest.jscode
+ 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'
+
+ def do_POST(self):
+ global do_status
+ if self.path != "/test.html":
+ self.send_error(404, "File not found")
+ return
+ form = parse_qs(self.rfile.read(int(self.headers['content-length'])))
+ 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
+ jsfilename = jstest.jsfilename
+ jstestcase = jstest.jstestcase
+ jscode = jstest.jscode
+ refresh_page = config.refresh_page % locals()
+ self.serve_data('text/html', refresh_page)
+ do_status = 'do_POST'
+
+ def serve_data(self, content_type, data):
+ self.send_response(200)
+ self.send_header("Content-type", content_type)
+ self.send_header("Content-length", len(data))
+ self.end_headers()
+ self.wfile.write(data)
+
+
+class BrowserTest(object):
+ """The browser driver"""
+
+ def start_server(self, port):
+ server_address = ('', port)
+ self.httpd = HTTPServer(server_address, TestHandler)
+
+ def get_result(self):
+ global do_status
+ do_status = None
+ while do_status != 'do_GET':
+ self.httpd.handle_request()
+ while do_status != 'do_POST':
+ self.httpd.handle_request()
+ return jstest.result
+
+
+def jstest(jsfilename, jstestcase):
+ global driver, jstest
+ jstest = TestCase(str(jsfilename), str(jstestcase))
+
+ try:
+ driver
+ except:
+ driver = BrowserTest()
+ driver.start_server(config.http_port)
+ webbrowser_open('http://localhost:%d/test.html' % config.http_port)
+
+ result = driver.get_result()
+ return result
Added: pypy/dist/pypy/translator/js2/test/runtest.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/js2/test/runtest.py Sat May 20 12:13:10 2006
@@ -0,0 +1,81 @@
+'''
+ Skipped tests should still be fixed. (or only run with py.test --browser)
+ Sests with DONT in front of them will probably not be fixed for the time being.
+'''
+
+import py, os
+from pypy.translator.translator import TranslationContext
+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.log import log
+from pypy.conftest import option
+log = log.runtest
+use_browsertest = conftest.option.jsbrowser
+
+def _CLI_is_on_path():
+ try:
+ py.path.local.sysfind('js') #we recommend Spidermonkey
+ except py.error.ENOENT:
+ return False
+ return True
+
+class compile_function(object):
+ def __init__(self, function, annotation, stackless=False, view=False):
+ if not use_browsertest and not _CLI_is_on_path():
+ py.test.skip('Javascript CLI (js) not found')
+
+ t = TranslationContext()
+ t.buildannotator().build_types(function, annotation)
+
+ t.buildrtyper(type_system="ootype").specialize()
+ #print t.rtyper
+
+ #backend_optimizations(t, raisingop2direct_call_all=True, inline_threshold=0, mallocs=False)
+ #backend_optimizations(t)
+ if view or option.view:
+ t.view()
+ #self.js = JS(t, [function, callback_function], stackless)
+ self.js = JS(t, [function], stackless)
+ self.js.write_source()
+
+ def _conv(self, v):
+ if isinstance(v, str):
+ return "{hash:0, chars:'%s'}" % v
+ return str(v).lower()
+
+ def __call__(self, *kwds):
+ args = ', '.join([self._conv(kw) for kw in kwds]) #lowerstr for (py)False->(js)false, etc.
+
+ entry_function = self.js.translator.graphs[0].name
+ function_call = "%s(%s)" % (entry_function, args)
+ #if self.js.stackless:
+ # function_call = "slp_entry_point('%s')" % function_call
+
+ if use_browsertest:
+ output = jstest(self.js.filename, function_call)
+ else:
+ cmd = 'echo "load(\'%s\'); print(%s)" | js 2>&1' % (self.js.filename, function_call)
+ log(cmd)
+ output = os.popen(cmd).read().strip()
+ for s in output.split('\n'):
+ log(s)
+
+ if s == 'false':
+ res = False
+ elif s == 'true':
+ res = True
+ elif s == 'undefined':
+ res = None
+ elif s == 'inf':
+ res = 1e300 * 1e300
+ elif s == 'NaN':
+ res = (1e300 * 1e300) / (1e300 * 1e300)
+ else:
+ log('javascript result:', s)
+ try:
+ res = eval(s)
+ except:
+ res = str(s)
+ return res
Added: pypy/dist/pypy/translator/js2/test/test_runtest.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/js2/test/test_runtest.py Sat May 20 12:13:10 2006
@@ -0,0 +1,53 @@
+import py
+from pypy.translator.js2.test.runtest import compile_function
+
+#test returntypes
+##def test_bool_return():
+## def bool_return_False():
+## return False
+## def bool_return_True():
+## return True
+## f_false = compile_function(bool_return_False, [])
+## assert f_false() == bool_return_False()
+## f_true = compile_function(bool_return_True , [])
+## assert f_true() == bool_return_True()
+##
+##
+def test_int_return():
+ def int_return():
+ return 42
+ f = compile_function(int_return, [])
+ assert f() == int_return()
+
+def test_float_return():
+ def float_return():
+ return 42.5
+ f = compile_function(float_return, [])
+ assert f() == float_return()
+
+#test paramtypes
+def test_bool_param():
+ def bool_param(b):
+ return b
+ f = compile_function(bool_param, [bool])
+ assert f(False) == bool_param(False)
+ assert f(True ) == bool_param(True )
+
+def test_int_param():
+ def int_param(n):
+ return n * 2
+ f = compile_function(int_param, [int])
+ assert f(42) == int_param(42)
+
+def test_float_param():
+ def float_param(f):
+ return f * 3.0
+ f = compile_function(float_param, [float])
+ assert f(12.5) == float_param(12.5)
+
+def test_combined_params():
+ def combined_params(b, n, f):
+ return int(int(b) * 5 + n * 2 + f * 3.0)
+ f = compile_function(combined_params, [bool,int,float])
+ assert f(False, 13, 12.5) == combined_params(False, 13, 12.5)
+ assert f(True , 13, 12.5) == combined_params(True , 13, 12.5)
More information about the Pypy-commit
mailing list