from . code import Code
from . simplex import MakeError
from . opcodes import *
from . operations import *
from . trans_utils import *
SPECIAL_IDENTIFIERS = { ' true ' , ' false ' , ' this ' }
class ByteCodeGenerator :
def __init__ ( self , exe ) :
self . exe = exe
self . declared_continue_labels = { }
self . declared_break_labels = { }
self . implicit_breaks = [ ]
self . implicit_continues = [ ]
self . declared_vars = [ ]
self . function_declaration_tape = [ ]
self . states = [ ]
def record_state ( self ) :
self . states . append (
( self . declared_continue_labels , self . declared_break_labels ,
self . implicit_breaks , self . implicit_continues , self . declared_vars ,
self . function_declaration_tape ) )
self . declared_continue_labels , self . declared_break_labels , \
self . implicit_breaks , self . implicit_continues , \
self . declared_vars , self . function_declaration_tape = { } , { } , [ ] , [ ] , [ ] , [ ]
def restore_state ( self ) :
self . declared_continue_labels , self . declared_break_labels , \
self . implicit_breaks , self . implicit_continues , \
self . declared_vars , self . function_declaration_tape = self . states . pop ( )
def ArrayExpression ( self , elements , * * kwargs ) :
for e in elements :
if e is None :
self . emit ( ' LOAD_NONE ' )
else :
self . emit ( e )
self . emit ( ' LOAD_ARRAY ' , len ( elements ) )
def AssignmentExpression ( self , operator , left , right , * * kwargs ) :
operator = operator [ : - 1 ]
if left [ ' type ' ] == ' MemberExpression ' :
self . emit ( left [ ' object ' ] )
if left [ ' computed ' ] :
self . emit ( left [ ' property ' ] )
self . emit ( right )
if operator :
self . emit ( ' STORE_MEMBER_OP ' , operator )
else :
self . emit ( ' STORE_MEMBER ' )
else :
self . emit ( right )
if operator :
self . emit ( ' STORE_MEMBER_DOT_OP ' , left [ ' property ' ] [ ' name ' ] ,
operator )
else :
self . emit ( ' STORE_MEMBER_DOT ' , left [ ' property ' ] [ ' name ' ] )
elif left [ ' type ' ] == ' Identifier ' :
if left [ ' name ' ] in SPECIAL_IDENTIFIERS :
raise MakeError ( ' SyntaxError ' ,
' Invalid left-hand side in assignment ' )
self . emit ( right )
if operator :
self . emit ( ' STORE_OP ' , left [ ' name ' ] , operator )
else :
self . emit ( ' STORE ' , left [ ' name ' ] )
else :
raise MakeError ( ' SyntaxError ' ,
' Invalid left-hand side in assignment ' )
def BinaryExpression ( self , operator , left , right , * * kwargs ) :
self . emit ( left )
self . emit ( right )
self . emit ( ' BINARY_OP ' , operator )
def BlockStatement ( self , body , * * kwargs ) :
self . _emit_statement_list ( body )
def BreakStatement ( self , label , * * kwargs ) :
if label is None :
self . emit ( ' JUMP ' , self . implicit_breaks [ - 1 ] )
else :
label = label . get ( ' name ' )
if label not in self . declared_break_labels :
raise MakeError ( ' SyntaxError ' ,
' Undefined label \' %s \' ' % label )
else :
self . emit ( ' JUMP ' , self . declared_break_labels [ label ] )
def CallExpression ( self , callee , arguments , * * kwargs ) :
if callee [ ' type ' ] == ' MemberExpression ' :
self . emit ( callee [ ' object ' ] )
if callee [ ' computed ' ] :
self . emit ( callee [ ' property ' ] )
if arguments :
for e in arguments :
self . emit ( e )
self . emit ( ' LOAD_N_TUPLE ' , len ( arguments ) )
self . emit ( ' CALL_METHOD ' )
else :
self . emit ( ' CALL_METHOD_NO_ARGS ' )
else :
prop_name = to_key ( callee [ ' property ' ] )
if arguments :
for e in arguments :
self . emit ( e )
self . emit ( ' LOAD_N_TUPLE ' , len ( arguments ) )
self . emit ( ' CALL_METHOD_DOT ' , prop_name )
else :
self . emit ( ' CALL_METHOD_DOT_NO_ARGS ' , prop_name )
else :
self . emit ( callee )
if arguments :
for e in arguments :
self . emit ( e )
self . emit ( ' LOAD_N_TUPLE ' , len ( arguments ) )
self . emit ( ' CALL ' )
else :
self . emit ( ' CALL_NO_ARGS ' )
def ClassBody ( self , body , * * kwargs ) :
raise NotImplementedError ( ' Not available in ECMA 5.1 ' )
def ClassDeclaration ( self , id , superClass , body , * * kwargs ) :
raise NotImplementedError ( ' Not available in ECMA 5.1 ' )
def ClassExpression ( self , id , superClass , body , * * kwargs ) :
raise NotImplementedError ( ' Classes not available in ECMA 5.1 ' )
def ConditionalExpression ( self , test , consequent , alternate , * * kwargs ) :
alt = self . exe . get_new_label ( )
end = self . exe . get_new_label ( )
# ?
self . emit ( test )
self . emit ( ' JUMP_IF_FALSE ' , alt )
# first val
self . emit ( consequent )
self . emit ( ' JUMP ' , end )
# second val
self . emit ( ' LABEL ' , alt )
self . emit ( alternate )
# end of ?: statement
self . emit ( ' LABEL ' , end )
def ContinueStatement ( self , label , * * kwargs ) :
if label is None :
self . emit ( ' JUMP ' , self . implicit_continues [ - 1 ] )
else :
label = label . get ( ' name ' )
if label not in self . declared_continue_labels :
raise MakeError ( ' SyntaxError ' ,
' Undefined label \' %s \' ' % label )
else :
self . emit ( ' JUMP ' , self . declared_continue_labels [ label ] )
def DebuggerStatement ( self , * * kwargs ) :
self . EmptyStatement ( * * kwargs )
def DoWhileStatement ( self , body , test , * * kwargs ) :
continue_label = self . exe . get_new_label ( )
break_label = self . exe . get_new_label ( )
initial_do = self . exe . get_new_label ( )
self . emit ( ' JUMP ' , initial_do )
self . emit ( ' LABEL ' , continue_label )
self . emit ( test )
self . emit ( ' JUMP_IF_FALSE ' , break_label )
self . emit ( ' LABEL ' , initial_do )
# translate the body, remember to add and afterwards remove implicit break/continue labels
self . implicit_continues . append ( continue_label )
self . implicit_breaks . append ( break_label )
self . emit ( body )
self . implicit_continues . pop ( )
self . implicit_breaks . pop ( )
self . emit ( ' JUMP ' , continue_label ) # loop back
self . emit ( ' LABEL ' , break_label )
def EmptyStatement ( self , * * kwargs ) :
# do nothing
pass
def ExpressionStatement ( self , expression , * * kwargs ) :
# change the final stack value
# pop the previous value and execute expression
self . emit ( ' POP ' )
self . emit ( expression )
def ForStatement ( self , init , test , update , body , * * kwargs ) :
continue_label = self . exe . get_new_label ( )
break_label = self . exe . get_new_label ( )
first_start = self . exe . get_new_label ( )
if init is not None :
self . emit ( init )
if init [ ' type ' ] != ' VariableDeclaration ' :
self . emit ( ' POP ' )
# skip first update and go straight to test
self . emit ( ' JUMP ' , first_start )
self . emit ( ' LABEL ' , continue_label )
if update :
self . emit ( update )
self . emit ( ' POP ' )
self . emit ( ' LABEL ' , first_start )
if test :
self . emit ( test )
self . emit ( ' JUMP_IF_FALSE ' , break_label )
# translate the body, remember to add and afterwards to remove implicit break/continue labels
self . implicit_continues . append ( continue_label )
self . implicit_breaks . append ( break_label )
self . emit ( body )
self . implicit_continues . pop ( )
self . implicit_breaks . pop ( )
self . emit ( ' JUMP ' , continue_label ) # loop back
self . emit ( ' LABEL ' , break_label )
def ForInStatement ( self , left , right , body , * * kwargs ) :
# prepare the needed labels
body_start_label = self . exe . get_new_label ( )
continue_label = self . exe . get_new_label ( )
break_label = self . exe . get_new_label ( )
# prepare the name
if left [ ' type ' ] == ' VariableDeclaration ' :
if len ( left [ ' declarations ' ] ) != 1 :
raise MakeError (
' SyntaxError ' ,
' Invalid left-hand side in for-in loop: Must have a single binding. '
)
self . emit ( left )
name = left [ ' declarations ' ] [ 0 ] [ ' id ' ] [ ' name ' ]
elif left [ ' type ' ] == ' Identifier ' :
name = left [ ' name ' ]
else :
raise MakeError ( ' SyntaxError ' ,
' Invalid left-hand side in for-loop ' )
# prepare the iterable
self . emit ( right )
# emit ForIn Opcode
self . emit ( ' FOR_IN ' , name , body_start_label , continue_label ,
break_label )
# a special continue position
self . emit ( ' LABEL ' , continue_label )
self . emit ( ' NOP ' )
self . emit ( ' LABEL ' , body_start_label )
self . implicit_continues . append ( continue_label )
self . implicit_breaks . append ( break_label )
self . emit ( ' LOAD_UNDEFINED ' )
self . emit ( body )
self . implicit_continues . pop ( )
self . implicit_breaks . pop ( )
self . emit ( ' NOP ' )
self . emit ( ' LABEL ' , break_label )
self . emit ( ' NOP ' )
def FunctionDeclaration ( self , id , params , defaults , body , * * kwargs ) :
if defaults :
raise NotImplementedError ( ' Defaults not available in ECMA 5.1 ' )
# compile function
self . record_state (
) # cleans translator state and appends it to the stack so that it can be later restored
function_start = self . exe . get_new_label ( )
function_declarations = self . exe . get_new_label ( )
declarations_done = self . exe . get_new_label (
) # put jump to this place at the and of function tape!
function_end = self . exe . get_new_label ( )
# skip the function if encountered externally
self . emit ( ' JUMP ' , function_end )
self . emit ( ' LABEL ' , function_start )
# call is made with empty stack so load undefined to fill it
self . emit ( ' LOAD_UNDEFINED ' )
# declare all functions
self . emit ( ' JUMP ' , function_declarations )
self . emit ( ' LABEL ' , declarations_done )
self . function_declaration_tape . append ( LABEL ( function_declarations ) )
self . emit ( body )
self . ReturnStatement ( None )
self . function_declaration_tape . append ( JUMP ( declarations_done ) )
self . exe . tape . extend ( self . function_declaration_tape )
self . emit ( ' LABEL ' , function_end )
declared_vars = self . declared_vars
self . restore_state ( )
# create function object and append to stack
name = id . get ( ' name ' )
assert name is not None
self . declared_vars . append ( name )
self . function_declaration_tape . append (
LOAD_FUNCTION ( function_start , tuple ( p [ ' name ' ] for p in params ) ,
name , True , tuple ( declared_vars ) ) )
self . function_declaration_tape . append ( STORE ( name ) )
self . function_declaration_tape . append ( POP ( ) )
def FunctionExpression ( self , id , params , defaults , body , * * kwargs ) :
if defaults :
raise NotImplementedError ( ' Defaults not available in ECMA 5.1 ' )
# compile function
self . record_state (
) # cleans translator state and appends it to the stack so that it can be later restored
function_start = self . exe . get_new_label ( )
function_declarations = self . exe . get_new_label ( )
declarations_done = self . exe . get_new_label (
) # put jump to this place at the and of function tape!
function_end = self . exe . get_new_label ( )
# skip the function if encountered externally
self . emit ( ' JUMP ' , function_end )
self . emit ( ' LABEL ' , function_start )
# call is made with empty stack so load undefined to fill it
self . emit ( ' LOAD_UNDEFINED ' )
# declare all functions
self . emit ( ' JUMP ' , function_declarations )
self . emit ( ' LABEL ' , declarations_done )
self . function_declaration_tape . append ( LABEL ( function_declarations ) )
self . emit ( body )
self . ReturnStatement ( None )
self . function_declaration_tape . append ( JUMP ( declarations_done ) )
self . exe . tape . extend ( self . function_declaration_tape )
self . emit ( ' LABEL ' , function_end )
declared_vars = self . declared_vars
self . restore_state ( )
# create function object and append to stack
name = id . get ( ' name ' ) if id else None
self . emit ( ' LOAD_FUNCTION ' , function_start ,
tuple ( p [ ' name ' ] for p in params ) , name , False ,
tuple ( declared_vars ) )
def Identifier ( self , name , * * kwargs ) :
if name == ' true ' :
self . emit ( ' LOAD_BOOLEAN ' , 1 )
elif name == ' false ' :
self . emit ( ' LOAD_BOOLEAN ' , 0 )
elif name == ' undefined ' :
self . emit ( ' LOAD_UNDEFINED ' )
else :
self . emit ( ' LOAD ' , name )
def IfStatement ( self , test , consequent , alternate , * * kwargs ) :
alt = self . exe . get_new_label ( )
end = self . exe . get_new_label ( )
# if
self . emit ( test )
self . emit ( ' JUMP_IF_FALSE ' , alt )
# consequent
self . emit ( consequent )
self . emit ( ' JUMP ' , end )
# alternate
self . emit ( ' LABEL ' , alt )
if alternate is not None :
self . emit ( alternate )
# end of if statement
self . emit ( ' LABEL ' , end )
def LabeledStatement ( self , label , body , * * kwargs ) :
label = label [ ' name ' ]
if body [ ' type ' ] in ( ' WhileStatement ' , ' DoWhileStatement ' ,
' ForStatement ' , ' ForInStatement ' ) :
# Continue label available... Simply take labels defined by the loop.
# It is important that they request continue label first
self . declared_continue_labels [ label ] = self . exe . _label_count + 1
self . declared_break_labels [ label ] = self . exe . _label_count + 2
self . emit ( body )
del self . declared_break_labels [ label ]
del self . declared_continue_labels [ label ]
else :
# only break label available
lbl = self . exe . get_new_label ( )
self . declared_break_labels [ label ] = lbl
self . emit ( body )
self . emit ( ' LABEL ' , lbl )
del self . declared_break_labels [ label ]
def Literal ( self , value , * * kwargs ) :
if value is None :
self . emit ( ' LOAD_NULL ' )
elif isinstance ( value , bool ) :
self . emit ( ' LOAD_BOOLEAN ' , int ( value ) )
elif isinstance ( value , basestring ) :
self . emit ( ' LOAD_STRING ' , unicode ( value ) )
elif isinstance ( value , ( float , int , long ) ) :
self . emit ( ' LOAD_NUMBER ' , float ( value ) )
elif isinstance ( value , tuple ) :
self . emit ( ' LOAD_REGEXP ' , * value )
else :
raise RuntimeError ( ' Unsupported literal ' )
def LogicalExpression ( self , left , right , operator , * * kwargs ) :
end = self . exe . get_new_label ( )
if operator == ' && ' :
# AND
self . emit ( left )
self . emit ( ' JUMP_IF_FALSE_WITHOUT_POP ' , end )
self . emit ( ' POP ' )
self . emit ( right )
self . emit ( ' LABEL ' , end )
elif operator == ' || ' :
# OR
self . emit ( left )
self . emit ( ' JUMP_IF_TRUE_WITHOUT_POP ' , end )
self . emit ( ' POP ' )
self . emit ( right )
self . emit ( ' LABEL ' , end )
else :
raise RuntimeError ( " Unknown logical expression: %s " % operator )
def MemberExpression ( self , computed , object , property , * * kwargs ) :
if computed :
self . emit ( object )
self . emit ( property )
self . emit ( ' LOAD_MEMBER ' )
else :
self . emit ( object )
self . emit ( ' LOAD_MEMBER_DOT ' , property [ ' name ' ] )
def NewExpression ( self , callee , arguments , * * kwargs ) :
self . emit ( callee )
if arguments :
n = len ( arguments )
for e in arguments :
self . emit ( e )
self . emit ( ' LOAD_N_TUPLE ' , n )
self . emit ( ' NEW ' )
else :
self . emit ( ' NEW_NO_ARGS ' )
def ObjectExpression ( self , properties , * * kwargs ) :
data = [ ]
for prop in properties :
self . emit ( prop [ ' value ' ] )
if prop [ ' computed ' ] :
raise NotImplementedError (
' ECMA 5.1 does not support computed object properties! ' )
data . append ( ( to_key ( prop [ ' key ' ] ) , prop [ ' kind ' ] [ 0 ] ) )
self . emit ( ' LOAD_OBJECT ' , tuple ( data ) )
def Program ( self , body , * * kwargs ) :
old_tape_len = len ( self . exe . tape )
self . emit ( ' LOAD_UNDEFINED ' )
self . emit ( body )
# add function tape !
self . exe . tape = self . exe . tape [ : old_tape_len ] + self . function_declaration_tape + self . exe . tape [ old_tape_len : ]
def Pyimport ( self , imp , * * kwargs ) :
raise NotImplementedError (
' Not available for bytecode interpreter yet, use the Js2Py translator. '
)
def Property ( self , kind , key , computed , value , method , shorthand ,
* * kwargs ) :
raise NotImplementedError ( ' Not available in ECMA 5.1 ' )
def RestElement ( self , argument , * * kwargs ) :
raise NotImplementedError ( ' Not available in ECMA 5.1 ' )
def ReturnStatement ( self , argument , * * kwargs ) :
self . emit ( ' POP ' ) # pop result of expression statements
if argument is None :
self . emit ( ' LOAD_UNDEFINED ' )
else :
self . emit ( argument )
self . emit ( ' RETURN ' )
def SequenceExpression ( self , expressions , * * kwargs ) :
for e in expressions :
self . emit ( e )
self . emit ( ' POP ' )
del self . exe . tape [ - 1 ]
def SwitchCase ( self , test , consequent , * * kwargs ) :
raise NotImplementedError ( ' Already implemented in SwitchStatement ' )
def SwitchStatement ( self , discriminant , cases , * * kwargs ) :
self . emit ( discriminant )
labels = [ self . exe . get_new_label ( ) for case in cases ]
tests = [ case [ ' test ' ] for case in cases ]
consequents = [ case [ ' consequent ' ] for case in cases ]
end_of_switch = self . exe . get_new_label ( )
# translate test cases
for test , label in zip ( tests , labels ) :
if test is not None :
self . emit ( test )
self . emit ( ' JUMP_IF_EQ ' , label )
else :
self . emit ( ' POP ' )
self . emit ( ' JUMP ' , label )
# this will be executed if none of the cases worked
self . emit ( ' POP ' )
self . emit ( ' JUMP ' , end_of_switch )
# translate consequents
self . implicit_breaks . append ( end_of_switch )
for consequent , label in zip ( consequents , labels ) :
self . emit ( ' LABEL ' , label )
self . _emit_statement_list ( consequent )
self . implicit_breaks . pop ( )
self . emit ( ' LABEL ' , end_of_switch )
def ThisExpression ( self , * * kwargs ) :
self . emit ( ' LOAD_THIS ' )
def ThrowStatement ( self , argument , * * kwargs ) :
# throw with the empty stack
self . emit ( ' POP ' )
self . emit ( argument )
self . emit ( ' THROW ' )
def TryStatement ( self , block , handler , finalizer , * * kwargs ) :
try_label = self . exe . get_new_label ( )
catch_label = self . exe . get_new_label ( )
finally_label = self . exe . get_new_label ( )
end_label = self . exe . get_new_label ( )
self . emit ( ' JUMP ' , end_label )
# try block
self . emit ( ' LABEL ' , try_label )
self . emit ( ' LOAD_UNDEFINED ' )
self . emit ( block )
self . emit (
' NOP '
) # needed to distinguish from break/continue vs some internal jumps
# catch block
self . emit ( ' LABEL ' , catch_label )
self . emit ( ' LOAD_UNDEFINED ' )
if handler :
self . emit ( handler [ ' body ' ] )
self . emit ( ' NOP ' )
# finally block
self . emit ( ' LABEL ' , finally_label )
self . emit ( ' LOAD_UNDEFINED ' )
if finalizer :
self . emit ( finalizer )
self . emit ( ' NOP ' )
self . emit ( ' LABEL ' , end_label )
# give life to the code
self . emit ( ' TRY_CATCH_FINALLY ' , try_label , catch_label ,
handler [ ' param ' ] [ ' name ' ] if handler else None , finally_label ,
bool ( finalizer ) , end_label )
def UnaryExpression ( self , operator , argument , * * kwargs ) :
if operator == ' typeof ' and argument [
' type ' ] == ' Identifier ' : # todo fix typeof
self . emit ( ' TYPEOF ' , argument [ ' name ' ] )
elif operator == ' delete ' :
if argument [ ' type ' ] == ' MemberExpression ' :
self . emit ( argument [ ' object ' ] )
if argument [ ' property ' ] [ ' type ' ] == ' Identifier ' :
self . emit ( ' LOAD_STRING ' ,
unicode ( argument [ ' property ' ] [ ' name ' ] ) )
else :
self . emit ( argument [ ' property ' ] )
self . emit ( ' DELETE_MEMBER ' )
elif argument [ ' type ' ] == ' Identifier ' :
self . emit ( ' DELETE ' , argument [ ' name ' ] )
else :
self . emit ( ' LOAD_BOOLEAN ' , 1 )
elif operator in UNARY_OPERATIONS :
self . emit ( argument )
self . emit ( ' UNARY_OP ' , operator )
else :
raise MakeError ( ' SyntaxError ' ,
' Unknown unary operator %s ' % operator )
def UpdateExpression ( self , operator , argument , prefix , * * kwargs ) :
incr = int ( operator == " ++ " )
post = int ( not prefix )
if argument [ ' type ' ] == ' MemberExpression ' :
if argument [ ' computed ' ] :
self . emit ( argument [ ' object ' ] )
self . emit ( argument [ ' property ' ] )
self . emit ( ' POSTFIX_MEMBER ' , post , incr )
else :
self . emit ( argument [ ' object ' ] )
name = to_key ( argument [ ' property ' ] )
self . emit ( ' POSTFIX_MEMBER_DOT ' , post , incr , name )
elif argument [ ' type ' ] == ' Identifier ' :
name = to_key ( argument )
self . emit ( ' POSTFIX ' , post , incr , name )
else :
raise MakeError ( ' SyntaxError ' ,
' Invalid left-hand side in assignment ' )
def VariableDeclaration ( self , declarations , kind , * * kwargs ) :
if kind != ' var ' :
raise NotImplementedError (
' Only var variable declaration is supported by ECMA 5.1 ' )
for d in declarations :
self . emit ( d )
def LexicalDeclaration ( self , declarations , kind , * * kwargs ) :
raise NotImplementedError ( ' Not supported by ECMA 5.1 ' )
def VariableDeclarator ( self , id , init , * * kwargs ) :
name = id [ ' name ' ]
if name in SPECIAL_IDENTIFIERS :
raise MakeError ( ' Invalid left-hand side in assignment ' )
self . declared_vars . append ( name )
if init is not None :
self . emit ( init )
self . emit ( ' STORE ' , name )
self . emit ( ' POP ' )
def WhileStatement ( self , test , body , * * kwargs ) :
continue_label = self . exe . get_new_label ( )
break_label = self . exe . get_new_label ( )
self . emit ( ' LABEL ' , continue_label )
self . emit ( test )
self . emit ( ' JUMP_IF_FALSE ' , break_label )
# translate the body, remember to add and afterwards remove implicit break/continue labels
self . implicit_continues . append ( continue_label )
self . implicit_breaks . append ( break_label )
self . emit ( body )
self . implicit_continues . pop ( )
self . implicit_breaks . pop ( )
self . emit ( ' JUMP ' , continue_label ) # loop back
self . emit ( ' LABEL ' , break_label )
def WithStatement ( self , object , body , * * kwargs ) :
beg_label = self . exe . get_new_label ( )
end_label = self . exe . get_new_label ( )
# scope
self . emit ( object )
# now the body
self . emit ( ' JUMP ' , end_label )
self . emit ( ' LABEL ' , beg_label )
self . emit ( ' LOAD_UNDEFINED ' )
self . emit ( body )
self . emit ( ' NOP ' )
self . emit ( ' LABEL ' , end_label )
# with statement implementation
self . emit ( ' WITH ' , beg_label , end_label )
def _emit_statement_list ( self , statements ) :
for statement in statements :
self . emit ( statement )
def emit ( self , what , * args ) :
''' what can be either name of the op, or node, or a list of statements. '''
if isinstance ( what , basestring ) :
return self . exe . emit ( what , * args )
elif isinstance ( what , list ) :
self . _emit_statement_list ( what )
else :
return getattr ( self , what [ ' type ' ] ) ( * * what )
import os , codecs
def path_as_local ( path ) :
if os . path . isabs ( path ) :
return path
# relative to cwd
return os . path . join ( os . getcwd ( ) , path )
def get_file_contents ( path_or_file ) :
if hasattr ( path_or_file , ' read ' ) :
js = path_or_file . read ( )
else :
with codecs . open ( path_as_local ( path_or_file ) , " r " , " utf-8 " ) as f :
js = f . read ( )
return js
def main ( ) :
from space import Space
import fill_space
from pyjsparser import parse
import json
a = ByteCodeGenerator ( Code ( ) )
s = Space ( )
fill_space . fill_space ( s , a )
a . exe . space = s
s . exe = a . exe
con = get_file_contents ( ' internals/esprima.js ' )
d = parse ( con + (
''' ;JSON.stringify(exports.parse( %s ), 4, 4) ''' % json . dumps ( con ) ) )
# d = parse('''
# function x(n) {
# log(n)
# return x(n+1)
# }
# x(0)
# ''')
# var v = 333333;
# while (v) {
# v--
#
# }
a . emit ( d )
print ( a . declared_vars )
print ( a . exe . tape )
print ( len ( a . exe . tape ) )
a . exe . compile ( )
def log ( this , args ) :
print ( args [ 0 ] )
return 999
print ( a . exe . run ( a . exe . space . GlobalObj ) )
if __name__ == ' __main__ ' :
main ( )