def do_switch(source, start): start += 6 # pass switch code = 'while 1:\n' + indent('SWITCHED = False\nCONDITION = (%s)\n') # parse value of check val, start = pass_bracket(source, start, '()') if val is None: raise SyntaxError('Missing () after switch statement') if not val.strip(): raise SyntaxError('Missing content inside () after switch statement') code = code % exp_translator(val) bra, start = pass_bracket(source, start, '{}') if bra is None: raise SyntaxError('Missing block {} after switch statement') bra_pos = 0 bra = bra[1:-1] + ';' while True: case = except_keyword(bra, bra_pos, 'case') default = except_keyword(bra, bra_pos, 'default') assert not (case and default) if case or default: # this ?: expression makes things much harder.... case_code = None if case: case_code = 'if SWITCHED or PyJsStrictEq(CONDITION, %s):\n' # we are looking for a first : with count 1. ? gives -1 and : gives +1. count = 0 for pos, e in enumerate(bra[case:], case): if e == '?': count -= 1 elif e == ':': count += 1 if count == 1: break else: raise SyntaxError( 'Missing : token after case in switch statement') case_condition = exp_translator( bra[case:pos]) # switch {case CONDITION: statements} case_code = case_code % case_condition case = pos + 1 if default: case = except_token(bra, default, ':') case_code = 'if True:\n' # now parse case statements (things after ':' ) cand, case = do_statement(bra, case) while cand: case_code += indent(cand) cand, case = do_statement(bra, case) case_code += indent('SWITCHED = True\n') code += indent(case_code) bra_pos = case else: break # prevent infinite loop :) code += indent('break\n') return code, start
def do_return(source, start): start += 6 # pass return end = source.find(';', start)+1 if end==-1: end = len(source) trans = exp_translator(source[start:end].rstrip(';')) return 'return %s\n' % (trans if trans else "var.get('undefined')"), end
def do_expression(source, start): start = pass_white(source, start) end = pass_until(source, start, tokens=(';',)) if end==start+1: #empty statement return 'pass\n', end # AUTOMATIC SEMICOLON INSERTION FOLLOWS # Without ASI this function would end with: return exp_translator(source[start:end].rstrip(';'))+'\n', end # ASI makes things a bit more complicated: # we will try to parse as much as possible, inserting ; in place of last new line in case of error rev = False rpos = 0 while True: try: code = source[start:end].rstrip(';') cand = exp_translator(code)+'\n', end just_to_test = compile(cand[0], '', 'exec') return cand except Exception as e: if not rev: rev = source[start:end][::-1] lpos = rpos while True: rpos = pass_until(rev, rpos, LINE_TERMINATOR) if rpos>=len(rev): raise if filter(lambda x: x not in SPACE, rev[lpos:rpos]): break end = start + len(rev) - rpos + 1
def do_return(source, start): start += 6 # pass return end = source.find(';', start) + 1 if end == -1: end = len(source) trans = exp_translator(source[start:end].rstrip(';')) return 'return %s\n' % (trans if trans else "var.get('undefined')"), end
def do_expression(source, start): start = pass_white(source, start) end = pass_until(source, start, tokens=(';', )) if end == start + 1: #empty statement return 'pass\n', end # AUTOMATIC SEMICOLON INSERTION FOLLOWS # Without ASI this function would end with: return exp_translator(source[start:end].rstrip(';'))+'\n', end # ASI makes things a bit more complicated: # we will try to parse as much as possible, inserting ; in place of last new line in case of error rev = False rpos = 0 while True: try: code = source[start:end].rstrip(';') cand = exp_translator(code) + '\n', end just_to_test = compile(cand[0], '', 'exec') return cand except Exception as e: if not rev: rev = source[start:end][::-1] lpos = rpos while True: rpos = pass_until(rev, rpos, LINE_TERMINATOR) if rpos >= len(rev): raise if filter(lambda x: x not in SPACE, rev[lpos:rpos]): break end = start + len(rev) - rpos + 1
def do_switch(source, start): start += 6 # pass switch code = 'while 1:\n' + indent('SWITCHED = False\nCONDITION = (%s)\n') # parse value of check val, start = pass_bracket(source, start, '()') if val is None: raise SyntaxError('Missing () after switch statement') if not val.strip(): raise SyntaxError('Missing content inside () after switch statement') code = code % exp_translator(val) bra, start = pass_bracket(source, start, '{}') if bra is None: raise SyntaxError('Missing block {} after switch statement') bra_pos = 0 bra = bra[1:-1] + ';' while True: case = except_keyword(bra, bra_pos, 'case') default = except_keyword(bra, bra_pos, 'default') assert not (case and default) if case or default: # this ?: expression makes things much harder.... case_code = None if case: case_code = 'if SWITCHED or PyJsStrictEq(CONDITION, %s):\n' # we are looking for a first : with count 1. ? gives -1 and : gives +1. count = 0 for pos, e in enumerate(bra[case:], case): if e=='?': count -= 1 elif e==':': count += 1 if count==1: break else: raise SyntaxError('Missing : token after case in switch statement') case_condition = exp_translator(bra[case:pos]) # switch {case CONDITION: statements}
def translate_object(obj, lval, obj_count=1, arr_count=1): obj = obj[1:-1] # remove {} from both ends obj, obj_rep, obj_count = remove_objects(obj, obj_count) obj, arr_rep, arr_count = remove_arrays(obj, arr_count) # functions can be defined inside objects. exp translator cant translate them. # we have to remove them and translate with func translator # its better explained in translate_array function obj, hoisted, inline = functions.remove_functions(obj, all_inline=True) assert not hoisted gsetters_after = '' keys = argsplit(obj) res = [] for i, e in enumerate(keys, 1): e = e.strip() if e.startswith('set '): gsetters_after += translate_setter(lval, e) elif e.startswith('get '): gsetters_after += translate_getter(lval, e) elif ':' not in e: if i < len(keys ): # can happen legally only in the last element {3:2,} raise SyntaxError('Unexpected "," in Object literal') break else: #Not getter, setter or elision spl = argsplit(e, ':') if len(spl) < 2: raise SyntaxError('Invalid Object literal: ' + e) try: key, value = spl except: #len(spl)> 2 print 'Unusual case ' + repr(e) key = spl[0] value = ':'.join(spl[1:]) key = key.strip() if is_internal(key): key = '%s.to_string().value' % key else: key = repr(key) value = exp_translator(value) if not value: raise SyntaxError('Missing value in Object literal') res.append('%s:%s' % (key, value)) res = '%s = Js({%s})\n' % (lval, ','.join(res)) + gsetters_after # translate all the nested objects (including removed earlier functions) for nested_name, nested_info in inline.iteritems(): # functions nested_block, nested_args = nested_info new_def = FUNC_TRANSLATOR(nested_name, nested_block, nested_args) res = new_def + res for lval, obj in obj_rep.iteritems(): #objects new_def, obj_count, arr_count = translate_object( obj, lval, obj_count, arr_count) # add object definition BEFORE array definition res = new_def + res for lval, obj in arr_rep.iteritems(): # arrays new_def, obj_count, arr_count = translate_array( obj, lval, obj_count, arr_count) # add object definition BEFORE array definition res = new_def + res return res, obj_count, arr_count
def do_bracket_exp(source, start, throw=True): bra, cand = pass_bracket(source, start, '()') if throw and not bra: raise SyntaxError('Missing bracket expression') bra = exp_translator(bra[1:-1]) if throw and not bra: raise SyntaxError('Empty bracket condition') return bra, cand if bra else start
def do_throw(source, start): start += 5 # pass throw end = source.find(';', start)+1 if not end: end = len(source) trans = exp_translator(source[start:end].rstrip(';')) if not trans: raise SyntaxError('Invalid throw statement: nothing to throw') res = 'PyJsTempException = JsToPyException(%s)\nraise PyJsTempException\n' % trans return res, end
def do_throw(source, start): start += 5 # pass throw end = source.find(';', start) + 1 if not end: end = len(source) trans = exp_translator(source[start:end].rstrip(';')) if not trans: raise SyntaxError('Invalid throw statement: nothing to throw') res = 'PyJsTempException = JsToPyException(%s)\nraise PyJsTempException\n' % trans return res, end
def do_var(source, start): #todo auto ; insertion start += 3 #pass var end = pass_until(source, start, tokens=(';',)) defs = argsplit(source[start:end-1]) # defs is the list of defined vars with optional initializer code = '' for de in defs: var, var_end = parse_identifier(de, 0, True) TO_REGISTER.append(var) var_end = pass_white(de, var_end) if var_end<len(de): # we have something more to parse... It has to start with = if de[var_end] != '=': raise SyntaxError('Unexpected initializer in var statement. Expected "=", got "%s"'%de[var_end]) code += exp_translator(de) + '\n' if not code.strip(): code = 'pass\n' return code, end
def do_for(source, start): start += 3 # pass for entered = start bra, start = pass_bracket(source, start, '()') inside, start = do_statement(source, start) if inside is None: raise SyntaxError('Missing statement after for') bra = bra[1:-1] if ';' in bra: init = argsplit(bra, ';') if len(init) != 3: raise SyntaxError('Invalid for statement') args = [] for i, item in enumerate(init): end = pass_white(item, 0) if end == len(item): args.append('' if i != 1 else '1') continue if not i and except_keyword(item, end, 'var') is not None: # var statement args.append(do_var(item, end)[0]) continue args.append(do_expression(item, end)[0]) return '#for JS loop\n%swhile %s:\n%s%s\n' % ( args[0], args[1].strip(), indent(inside), indent(args[2])), start # iteration end = pass_white(bra, 0) register = False if bra[end:].startswith('var '): end += 3 end = pass_white(bra, end) register = True name, end = parse_identifier(bra, end) if register: TO_REGISTER.append(name) end = pass_white(bra, end) if bra[end:end + 2] != 'in' or bra[end + 2] in IDENTIFIER_PART: #print source[entered-10:entered+50] raise SyntaxError('Invalid "for x in y" statement') end += 2 # pass in exp = exp_translator(bra[end:]) res = 'for temp in %s:\n' % exp res += indent('var.put(%s, temp)\n' % name.__repr__()) + indent(inside) return res, start
def translate_array(array, lval, obj_count=1, arr_count=1): """array has to be any js array for example [1,2,3] lval has to be name of this array. Returns python code that adds lval to the PY scope it should be put before lval""" array = array[1:-1] array, obj_rep, obj_count = remove_objects(array, obj_count) array, arr_rep, arr_count = remove_arrays(array, arr_count) #functions can be also defined in arrays, this caused many problems since in Python # functions cant be defined inside literal # remove functions (they dont contain arrays or objects so can be translated easily) # hoisted functions are treated like inline array, hoisted, inline = functions.remove_functions(array, all_inline=True) assert not hoisted arr = [] # separate elements in array for e in argsplit(array, ','): # translate expressions in array PyJsLvalInline will not be translated! e = exp_translator(e.replace('\n', '')) arr.append(e if e else 'None') arr = '%s = Js([%s])\n' % (lval, ','.join(arr)) #But we can have more code to add to define arrays/objects/functions defined inside this array # translate nested objects: # functions: for nested_name, nested_info in inline.iteritems(): nested_block, nested_args = nested_info new_def = FUNC_TRANSLATOR(nested_name, nested_block, nested_args) arr = new_def + arr for lval, obj in obj_rep.iteritems(): new_def, obj_count, arr_count = translate_object( obj, lval, obj_count, arr_count) # add object definition BEFORE array definition arr = new_def + arr for lval, obj in arr_rep.iteritems(): new_def, obj_count, arr_count = translate_array( obj, lval, obj_count, arr_count) # add object definition BEFORE array definition arr = new_def + arr return arr, obj_count, arr_count