Actualizados
- allcalidad: Cambio de dominio - animeflv: Correción - streamcloud - Actualización interna
This commit is contained in:
@@ -0,0 +1,752 @@
|
||||
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):
|
||||
self.emit('LOAD_UNDEFINED')
|
||||
self.emit(body)
|
||||
# add function tape !
|
||||
self.exe.tape = self.function_declaration_tape + self.exe.tape
|
||||
|
||||
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()
|
||||
Reference in New Issue
Block a user