mirror of
https://github.com/yt-dlp/yt-dlp.git
synced 2025-07-09 11:31:51 +00:00
[jsinterp] Fix variable scoping (#13639)
Authored by: bashonly, seproDev Co-authored-by: sepro <sepro@sepr0.com>
This commit is contained in:
parent
0b41746964
commit
b6328ca050
@ -490,6 +490,52 @@ class TestJSInterpreter(unittest.TestCase):
|
|||||||
self._test('function f() { var a = "test--"; return a; }', 'test--')
|
self._test('function f() { var a = "test--"; return a; }', 'test--')
|
||||||
self._test('function f() { var b = 1; var a = "b--"; return a; }', 'b--')
|
self._test('function f() { var b = 1; var a = "b--"; return a; }', 'b--')
|
||||||
|
|
||||||
|
def test_nested_function_scoping(self):
|
||||||
|
self._test(R'''
|
||||||
|
function f() {
|
||||||
|
var g = function() {
|
||||||
|
var P = 2;
|
||||||
|
return P;
|
||||||
|
};
|
||||||
|
var P = 1;
|
||||||
|
g();
|
||||||
|
return P;
|
||||||
|
}
|
||||||
|
''', 1)
|
||||||
|
self._test(R'''
|
||||||
|
function f() {
|
||||||
|
var x = function() {
|
||||||
|
for (var w = 1, M = []; w < 2; w++) switch (w) {
|
||||||
|
case 1:
|
||||||
|
M.push("a");
|
||||||
|
case 2:
|
||||||
|
M.push("b");
|
||||||
|
}
|
||||||
|
return M
|
||||||
|
};
|
||||||
|
var w = "c";
|
||||||
|
var M = "d";
|
||||||
|
var y = x();
|
||||||
|
y.push(w);
|
||||||
|
y.push(M);
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
''', ['a', 'b', 'c', 'd'])
|
||||||
|
self._test(R'''
|
||||||
|
function f() {
|
||||||
|
var P, Q;
|
||||||
|
var z = 100;
|
||||||
|
var g = function() {
|
||||||
|
var P, Q; P = 2; Q = 15;
|
||||||
|
z = 0;
|
||||||
|
return P+Q;
|
||||||
|
};
|
||||||
|
P = 1; Q = 10;
|
||||||
|
var x = g(), y = 3;
|
||||||
|
return P+Q+x+y+z;
|
||||||
|
}
|
||||||
|
''', 31)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
@ -222,6 +222,14 @@ class LocalNameSpace(collections.ChainMap):
|
|||||||
def __delitem__(self, key):
|
def __delitem__(self, key):
|
||||||
raise NotImplementedError('Deleting is not supported')
|
raise NotImplementedError('Deleting is not supported')
|
||||||
|
|
||||||
|
def set_local(self, key, value):
|
||||||
|
self.maps[0][key] = value
|
||||||
|
|
||||||
|
def get_local(self, key):
|
||||||
|
if key in self.maps[0]:
|
||||||
|
return self.maps[0][key]
|
||||||
|
return JS_Undefined
|
||||||
|
|
||||||
|
|
||||||
class Debugger:
|
class Debugger:
|
||||||
import sys
|
import sys
|
||||||
@ -381,7 +389,7 @@ class JSInterpreter:
|
|||||||
return self._named_object(namespace, obj)
|
return self._named_object(namespace, obj)
|
||||||
|
|
||||||
@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, _is_var_declaration=False):
|
||||||
if allow_recursion < 0:
|
if allow_recursion < 0:
|
||||||
raise self.Exception('Recursion limit reached')
|
raise self.Exception('Recursion limit reached')
|
||||||
allow_recursion -= 1
|
allow_recursion -= 1
|
||||||
@ -401,6 +409,7 @@ class JSInterpreter:
|
|||||||
if m.group('throw'):
|
if m.group('throw'):
|
||||||
raise JS_Throw(self.interpret_expression(expr, local_vars, allow_recursion))
|
raise JS_Throw(self.interpret_expression(expr, local_vars, allow_recursion))
|
||||||
should_return = not m.group('var')
|
should_return = not m.group('var')
|
||||||
|
_is_var_declaration = _is_var_declaration or bool(m.group('var'))
|
||||||
if not expr:
|
if not expr:
|
||||||
return None, should_return
|
return None, should_return
|
||||||
|
|
||||||
@ -585,7 +594,8 @@ class JSInterpreter:
|
|||||||
sub_expressions = list(self._separate(expr))
|
sub_expressions = list(self._separate(expr))
|
||||||
if len(sub_expressions) > 1:
|
if len(sub_expressions) > 1:
|
||||||
for sub_expr in sub_expressions:
|
for sub_expr in sub_expressions:
|
||||||
ret, should_abort = self.interpret_statement(sub_expr, local_vars, allow_recursion)
|
ret, should_abort = self.interpret_statement(
|
||||||
|
sub_expr, local_vars, allow_recursion, _is_var_declaration=_is_var_declaration)
|
||||||
if should_abort:
|
if should_abort:
|
||||||
return ret, True
|
return ret, True
|
||||||
return ret, False
|
return ret, False
|
||||||
@ -599,8 +609,12 @@ class JSInterpreter:
|
|||||||
left_val = local_vars.get(m.group('out'))
|
left_val = local_vars.get(m.group('out'))
|
||||||
|
|
||||||
if not m.group('index'):
|
if not m.group('index'):
|
||||||
local_vars[m.group('out')] = self._operator(
|
eval_result = self._operator(
|
||||||
m.group('op'), left_val, m.group('expr'), expr, local_vars, allow_recursion)
|
m.group('op'), left_val, m.group('expr'), expr, local_vars, allow_recursion)
|
||||||
|
if _is_var_declaration:
|
||||||
|
local_vars.set_local(m.group('out'), eval_result)
|
||||||
|
else:
|
||||||
|
local_vars[m.group('out')] = eval_result
|
||||||
return local_vars[m.group('out')], should_return
|
return local_vars[m.group('out')], should_return
|
||||||
elif left_val in (None, JS_Undefined):
|
elif left_val in (None, JS_Undefined):
|
||||||
raise self.Exception(f'Cannot index undefined variable {m.group("out")}', expr)
|
raise self.Exception(f'Cannot index undefined variable {m.group("out")}', expr)
|
||||||
@ -654,7 +668,16 @@ class JSInterpreter:
|
|||||||
return float('NaN'), should_return
|
return float('NaN'), should_return
|
||||||
|
|
||||||
elif m and m.group('return'):
|
elif m and m.group('return'):
|
||||||
return local_vars.get(m.group('name'), JS_Undefined), should_return
|
var = m.group('name')
|
||||||
|
# Declared variables
|
||||||
|
if _is_var_declaration:
|
||||||
|
ret = local_vars.get_local(var)
|
||||||
|
# Register varname in local namespace
|
||||||
|
# Set value as JS_Undefined or its pre-existing value
|
||||||
|
local_vars.set_local(var, ret)
|
||||||
|
else:
|
||||||
|
ret = local_vars.get(var, JS_Undefined)
|
||||||
|
return ret, should_return
|
||||||
|
|
||||||
with contextlib.suppress(ValueError):
|
with contextlib.suppress(ValueError):
|
||||||
return json.loads(js_to_json(expr, strict=True)), should_return
|
return json.loads(js_to_json(expr, strict=True)), should_return
|
||||||
|
Loading…
x
Reference in New Issue
Block a user