kopia lustrzana https://github.com/ytdl-org/youtube-dl
				
				
				
			[JSInterp] Add `_separate_at_op()`
							rodzic
							
								
									d21717978c
								
							
						
					
					
						commit
						16b7e97afa
					
				|  | @ -704,6 +704,68 @@ class JSInterpreter(object): | ||||||
|                 _SC_OPERATORS, _LOG_OPERATORS, _COMP_OPERATORS, _OPERATORS, _UNARY_OPERATORS_X)) |                 _SC_OPERATORS, _LOG_OPERATORS, _COMP_OPERATORS, _OPERATORS, _UNARY_OPERATORS_X)) | ||||||
|         return _cached |         return _cached | ||||||
| 
 | 
 | ||||||
|  |     def _separate_at_op(self, expr, max_split=None): | ||||||
|  | 
 | ||||||
|  |         for op, _ in self._all_operators(): | ||||||
|  |             # hackety: </> have higher priority than <</>>, but don't confuse them | ||||||
|  |             skip_delim = (op + op) if op in '<>*?' else None | ||||||
|  |             if op == '?': | ||||||
|  |                 skip_delim = (skip_delim, '?.') | ||||||
|  |             separated = list(self._separate(expr, op, skip_delims=skip_delim)) | ||||||
|  |             if len(separated) < 2: | ||||||
|  |                 continue | ||||||
|  | 
 | ||||||
|  |             right_expr = separated.pop() | ||||||
|  |             # handle operators that are both unary and binary, minimal BODMAS | ||||||
|  |             if op in ('+', '-'): | ||||||
|  |                 # simplify/adjust consecutive instances of these operators | ||||||
|  |                 undone = 0 | ||||||
|  |                 separated = [s.strip() for s in separated] | ||||||
|  |                 while len(separated) > 1 and not separated[-1]: | ||||||
|  |                     undone += 1 | ||||||
|  |                     separated.pop() | ||||||
|  |                 if op == '-' and undone % 2 != 0: | ||||||
|  |                     right_expr = op + right_expr | ||||||
|  |                 elif op == '+': | ||||||
|  |                     while len(separated) > 1 and set(separated[-1]) <= self.OP_CHARS: | ||||||
|  |                         right_expr = separated.pop() + right_expr | ||||||
|  |                     if separated[-1][-1:] in self.OP_CHARS: | ||||||
|  |                         right_expr = separated.pop() + right_expr | ||||||
|  |                 # hanging op at end of left => unary + (strip) or - (push right) | ||||||
|  |                 separated.append(right_expr) | ||||||
|  |                 dm_ops = ('*', '%', '/', '**') | ||||||
|  |                 dm_chars = set(''.join(dm_ops)) | ||||||
|  | 
 | ||||||
|  |                 def yield_terms(s): | ||||||
|  |                     skip = False | ||||||
|  |                     for i, term in enumerate(s[:-1]): | ||||||
|  |                         if skip: | ||||||
|  |                             skip = False | ||||||
|  |                             continue | ||||||
|  |                         if not (dm_chars & set(term)): | ||||||
|  |                             yield term | ||||||
|  |                             continue | ||||||
|  |                         for dm_op in dm_ops: | ||||||
|  |                             bodmas = list(self._separate(term, dm_op, skip_delims=skip_delim)) | ||||||
|  |                             if len(bodmas) > 1 and not bodmas[-1].strip(): | ||||||
|  |                                 bodmas[-1] = (op if op == '-' else '') + s[i + 1] | ||||||
|  |                                 yield dm_op.join(bodmas) | ||||||
|  |                                 skip = True | ||||||
|  |                                 break | ||||||
|  |                         else: | ||||||
|  |                             if term: | ||||||
|  |                                 yield term | ||||||
|  | 
 | ||||||
|  |                     if not skip and s[-1]: | ||||||
|  |                         yield s[-1] | ||||||
|  | 
 | ||||||
|  |                 separated = list(yield_terms(separated)) | ||||||
|  |                 right_expr = separated.pop() if len(separated) > 1 else None | ||||||
|  |                 expr = op.join(separated) | ||||||
|  |             if right_expr is None: | ||||||
|  |                 continue | ||||||
|  |             return op, separated, right_expr | ||||||
|  | 
 | ||||||
|     def _operator(self, op, left_val, right_expr, expr, local_vars, allow_recursion): |     def _operator(self, op, left_val, right_expr, expr, local_vars, allow_recursion): | ||||||
|         if op in ('||', '&&'): |         if op in ('||', '&&'): | ||||||
|             if (op == '&&') ^ _js_ternary(left_val): |             if (op == '&&') ^ _js_ternary(left_val): | ||||||
|  | @ -759,51 +821,9 @@ class JSInterpreter(object): | ||||||
|     _FINALLY_RE = re.compile(r'finally\s*\{') |     _FINALLY_RE = re.compile(r'finally\s*\{') | ||||||
|     _SWITCH_RE = re.compile(r'switch\s*\(') |     _SWITCH_RE = re.compile(r'switch\s*\(') | ||||||
| 
 | 
 | ||||||
|     def handle_operators(self, expr, local_vars, allow_recursion): |     def _eval_operator(self, op, left_expr, right_expr, expr, local_vars, allow_recursion): | ||||||
| 
 |         left_val = self.interpret_expression(left_expr, local_vars, allow_recursion) | ||||||
|         for op, _ in self._all_operators(): |         return self._operator(op, left_val, right_expr, expr, local_vars, allow_recursion) | ||||||
|             # hackety: </> have higher priority than <</>>, but don't confuse them |  | ||||||
|             skip_delim = (op + op) if op in '<>*?' else None |  | ||||||
|             if op == '?': |  | ||||||
|                 skip_delim = (skip_delim, '?.') |  | ||||||
|             separated = list(self._separate(expr, op, skip_delims=skip_delim)) |  | ||||||
|             if len(separated) < 2: |  | ||||||
|                 continue |  | ||||||
| 
 |  | ||||||
|             right_expr = separated.pop() |  | ||||||
|             # handle operators that are both unary and binary, minimal BODMAS |  | ||||||
|             if op in ('+', '-'): |  | ||||||
|                 # simplify/adjust consecutive instances of these operators |  | ||||||
|                 undone = 0 |  | ||||||
|                 separated = [s.strip() for s in separated] |  | ||||||
|                 while len(separated) > 1 and not separated[-1]: |  | ||||||
|                     undone += 1 |  | ||||||
|                     separated.pop() |  | ||||||
|                 if op == '-' and undone % 2 != 0: |  | ||||||
|                     right_expr = op + right_expr |  | ||||||
|                 elif op == '+': |  | ||||||
|                     while len(separated) > 1 and set(separated[-1]) <= self.OP_CHARS: |  | ||||||
|                         right_expr = separated.pop() + right_expr |  | ||||||
|                     if separated[-1][-1:] in self.OP_CHARS: |  | ||||||
|                         right_expr = separated.pop() + right_expr |  | ||||||
|                 # hanging op at end of left => unary + (strip) or - (push right) |  | ||||||
|                 left_val = separated[-1] if separated else '' |  | ||||||
|                 for dm_op in ('*', '%', '/', '**'): |  | ||||||
|                     bodmas = tuple(self._separate(left_val, dm_op, skip_delims=skip_delim)) |  | ||||||
|                     if len(bodmas) > 1 and not bodmas[-1].strip(): |  | ||||||
|                         expr = op.join(separated) + op + right_expr |  | ||||||
|                         if len(separated) > 1: |  | ||||||
|                             separated.pop() |  | ||||||
|                             right_expr = op.join((left_val, right_expr)) |  | ||||||
|                         else: |  | ||||||
|                             separated = [op.join((left_val, right_expr))] |  | ||||||
|                             right_expr = None |  | ||||||
|                         break |  | ||||||
|                 if right_expr is None: |  | ||||||
|                     continue |  | ||||||
| 
 |  | ||||||
|             left_val = self.interpret_expression(op.join(separated), local_vars, allow_recursion) |  | ||||||
|             return self._operator(op, left_val, right_expr, expr, local_vars, allow_recursion), True |  | ||||||
| 
 | 
 | ||||||
|     @Debugger.wrap_interpreter |     @Debugger.wrap_interpreter | ||||||
|     def interpret_statement(self, stmt, local_vars, allow_recursion=100): |     def interpret_statement(self, stmt, local_vars, allow_recursion=100): | ||||||
|  | @ -865,9 +885,12 @@ class JSInterpreter(object): | ||||||
|             operand = expr[len(op):] |             operand = expr[len(op):] | ||||||
|             if not operand or operand[0] != ' ': |             if not operand or operand[0] != ' ': | ||||||
|                 continue |                 continue | ||||||
|             op_result = self.handle_operators(expr, local_vars, allow_recursion) |             separated = self._separate_at_op(operand, max_split=1) | ||||||
|             if op_result: |             if separated: | ||||||
|                 return op_result[0], should_return |                 next_op, separated, right_expr = separated | ||||||
|  |                 separated.append(right_expr) | ||||||
|  |                 operand = next_op.join(separated) | ||||||
|  |             return self._eval_operator(op, operand, '', expr, local_vars, allow_recursion), should_return | ||||||
| 
 | 
 | ||||||
|         if expr.startswith('{'): |         if expr.startswith('{'): | ||||||
|             inner, outer = self._separate_at_paren(expr) |             inner, outer = self._separate_at_paren(expr) | ||||||
|  | @ -1138,9 +1161,10 @@ class JSInterpreter(object): | ||||||
|                 val = self._index(val, idx) |                 val = self._index(val, idx) | ||||||
|             return val, should_return |             return val, should_return | ||||||
| 
 | 
 | ||||||
|         op_result = self.handle_operators(expr, local_vars, allow_recursion) |         separated = self._separate_at_op(expr) | ||||||
|         if op_result: |         if separated: | ||||||
|             return op_result[0], should_return |             op, separated, right_expr = separated | ||||||
|  |             return self._eval_operator(op, op.join(separated), right_expr, expr, local_vars, allow_recursion), should_return | ||||||
| 
 | 
 | ||||||
|         if md.get('attribute'): |         if md.get('attribute'): | ||||||
|             variable, member, nullish = m.group('var', 'member', 'nullish') |             variable, member, nullish = m.group('var', 'member', 'nullish') | ||||||
|  |  | ||||||
		Ładowanie…
	
		Reference in New Issue
	
	 dirkf
						dirkf