mirror of
https://github.com/ytdl-org/youtube-dl.git
synced 2025-04-22 23:05:03 -05:00
[JSInterp] Add _separate_at_op()
This commit is contained in:
parent
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')
|
||||||
|
Loading…
x
Reference in New Issue
Block a user