[jsinterp] Adding function declaration and call
Refractors ast: * function declaration is no longer a statement * function body is no longer a block
This commit is contained in:
parent
dca2e9e965
commit
3b536690d7
@ -15,21 +15,18 @@ tests = [
|
|||||||
''',
|
''',
|
||||||
'asserts': [{'value': True, 'call': ('a', 1)}, {'value': False, 'call': ('a', 0)}],
|
'asserts': [{'value': True, 'call': ('a', 1)}, {'value': False, 'call': ('a', 0)}],
|
||||||
'ast': [
|
'ast': [
|
||||||
(Token.FUNC, 'a',
|
(Token.FUNC, 'a', ['x'], [
|
||||||
['x'],
|
(Token.IF,
|
||||||
(Token.BLOCK, [
|
(Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
(Token.IF,
|
(Token.MEMBER, (Token.ID, 'x'), None, None),
|
||||||
(Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
(Token.MEMBER, (Token.INT, 0), None, None),
|
||||||
(Token.MEMBER, (Token.ID, 'x'), None, None),
|
(Token.REL, _RELATIONS['>'][1])
|
||||||
(Token.MEMBER, (Token.INT, 0), None, None),
|
]), None)]),
|
||||||
(Token.REL, _RELATIONS['>'][1])
|
(Token.RETURN, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
]), None)]),
|
(Token.MEMBER, (Token.BOOL, True), None, None)]), None)])),
|
||||||
(Token.RETURN, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
(Token.RETURN, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
(Token.MEMBER, (Token.BOOL, True), None, None)]), None)])),
|
(Token.MEMBER, (Token.BOOL, False), None, None)]), None)])))
|
||||||
(Token.RETURN, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
])
|
||||||
(Token.MEMBER, (Token.BOOL, False), None, None)]), None)])))
|
|
||||||
|
|
||||||
]))
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -1,111 +1,109 @@
|
|||||||
from youtube_dl.jsinterp.jsgrammar import Token
|
from youtube_dl.jsinterp.jsgrammar import Token
|
||||||
from youtube_dl.jsinterp.tstream import _OPERATORS
|
from youtube_dl.jsinterp.tstream import _OPERATORS
|
||||||
|
|
||||||
skip = {'i': 'Interpreting function call not yet implemented'}
|
|
||||||
|
|
||||||
tests = [
|
tests = [
|
||||||
{
|
{
|
||||||
'code': '''
|
'code': '''
|
||||||
function x() { return 2; }
|
function x() { return 2; }
|
||||||
function y(a) { return x() + a; }
|
function y(a) { return x() + a; }
|
||||||
function z() { return y(3); }
|
function z() { return y(3); }
|
||||||
|
z();
|
||||||
''',
|
''',
|
||||||
'asserts': [{'value': 5, 'call': ('z',)}],
|
'asserts': [{'value': 5}],
|
||||||
'ast': [
|
'ast': [
|
||||||
(Token.FUNC, 'x',
|
(Token.FUNC, 'x', [], [
|
||||||
[],
|
(Token.RETURN, (Token.EXPR, [
|
||||||
(Token.BLOCK, [
|
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.INT, 2), None, None)]), None)
|
||||||
(Token.RETURN, (Token.EXPR, [
|
]))
|
||||||
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.INT, 2), None, None)]), None)
|
]),
|
||||||
])
|
(Token.FUNC, 'y', ['a'], [
|
||||||
)
|
(Token.RETURN, (Token.EXPR, [
|
||||||
])),
|
(Token.ASSIGN, None,
|
||||||
(Token.FUNC, 'y',
|
(Token.OPEXPR, [
|
||||||
['a'],
|
(Token.MEMBER, (Token.ID, 'x'), None, (Token.CALL, [], None)),
|
||||||
(Token.BLOCK, [
|
(Token.MEMBER, (Token.ID, 'a'), None, None),
|
||||||
(Token.RETURN, (Token.EXPR, [
|
(Token.OP, _OPERATORS['+'][1])
|
||||||
(Token.ASSIGN, None,
|
|
||||||
(Token.OPEXPR, [
|
|
||||||
(Token.MEMBER, (Token.ID, 'x'), None, (Token.CALL, [], None)),
|
|
||||||
(Token.MEMBER, (Token.ID, 'a'), None, None),
|
|
||||||
(Token.OP, _OPERATORS['+'][1])
|
|
||||||
]), None)
|
|
||||||
])
|
|
||||||
)
|
|
||||||
])),
|
|
||||||
(Token.FUNC, 'z',
|
|
||||||
[],
|
|
||||||
(Token.BLOCK, [
|
|
||||||
(Token.RETURN, (Token.EXPR, [
|
|
||||||
(Token.ASSIGN, None, (Token.OPEXPR, [
|
|
||||||
(Token.MEMBER, (Token.ID, 'y'), None, (Token.CALL, [
|
|
||||||
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.INT, 3), None, None)]), None)
|
|
||||||
], None))
|
|
||||||
]), None)
|
]), None)
|
||||||
])
|
]))
|
||||||
)
|
]),
|
||||||
]))
|
(Token.FUNC, 'z', [], [
|
||||||
|
(Token.RETURN, (Token.EXPR, [
|
||||||
|
(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
|
(Token.MEMBER, (Token.ID, 'y'), None, (Token.CALL, [
|
||||||
|
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.INT, 3), None, None)]), None)
|
||||||
|
], None))
|
||||||
|
]), None)
|
||||||
|
])
|
||||||
|
)
|
||||||
|
]),
|
||||||
|
(Token.EXPR, [
|
||||||
|
(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
|
(Token.MEMBER, (Token.ID, 'z'), None, (Token.CALL, [], None))
|
||||||
|
]), None)
|
||||||
|
])
|
||||||
]
|
]
|
||||||
}, {
|
}, {
|
||||||
'code': 'function x(a) { return a.split(""); }',
|
'code': 'function x(a) { return a.split(""); }',
|
||||||
'asserts': [{'value': ["a", "b", "c"], 'call': ('x',)}],
|
# built-in functions not yet implemented
|
||||||
|
# 'asserts': [{'value': ["a", "b", "c"], 'call': ('x',"abc")}],
|
||||||
'ast': [
|
'ast': [
|
||||||
(Token.FUNC, 'x',
|
(Token.FUNC, 'x', ['a'], [
|
||||||
['a'],
|
(Token.RETURN, (Token.EXPR, [
|
||||||
(Token.BLOCK, [
|
(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
(Token.RETURN, (Token.EXPR, [
|
(Token.MEMBER, (Token.ID, 'a'), None,
|
||||||
(Token.ASSIGN, None, (Token.OPEXPR, [
|
(Token.FIELD, 'split',
|
||||||
(Token.MEMBER, (Token.ID, 'a'), None,
|
(Token.CALL, [
|
||||||
(Token.FIELD, 'split',
|
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.STR, ''), None, None)]), None)
|
||||||
(Token.CALL, [
|
], None))
|
||||||
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.STR, ''), None, None)]), None)
|
)]),
|
||||||
], None))
|
None)
|
||||||
)]),
|
]))
|
||||||
None)
|
])
|
||||||
])
|
|
||||||
)
|
|
||||||
]))
|
|
||||||
]
|
]
|
||||||
}, {
|
}, {
|
||||||
'code': '''
|
'code': '''
|
||||||
function a(x) { return x; }
|
function a(x) { return x; }
|
||||||
function b(x) { return x; }
|
function b(x) { return x + 1; }
|
||||||
function c() { return [a, b][0](0); }
|
function c() { return [a, b][0](0); }
|
||||||
|
c();
|
||||||
''',
|
''',
|
||||||
'asserts': [{'value': 0}],
|
'asserts': [{'value': 0}],
|
||||||
'ast': [
|
'ast': [
|
||||||
(Token.FUNC, 'a', ['x'],
|
(Token.FUNC, 'a', ['x'], [
|
||||||
(Token.BLOCK, [
|
(Token.RETURN, (Token.EXPR, [
|
||||||
(Token.RETURN, (Token.EXPR, [
|
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'x'), None, None)]), None)
|
||||||
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'x'), None, None)]), None)
|
]))
|
||||||
])
|
]),
|
||||||
)
|
(Token.FUNC, 'b', ['x'], [
|
||||||
])),
|
(Token.RETURN, (Token.EXPR, [
|
||||||
(Token.FUNC, 'b', ['x'],
|
(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
(Token.BLOCK, [
|
(Token.MEMBER, (Token.ID, 'x'), None, None),
|
||||||
(Token.RETURN, (Token.EXPR, [
|
(Token.MEMBER, (Token.INT, 1), None, None),
|
||||||
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'x'), None, None)]), None)
|
(Token.OP, _OPERATORS['+'][1])
|
||||||
])
|
]), None)
|
||||||
)
|
]))
|
||||||
])),
|
]),
|
||||||
(Token.FUNC, 'c', [],
|
(Token.FUNC, 'c', [], [
|
||||||
(Token.BLOCK, [
|
(Token.RETURN, (Token.EXPR, [
|
||||||
(Token.RETURN, (Token.EXPR, [
|
(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
(Token.ASSIGN, None, (Token.OPEXPR, [
|
(Token.MEMBER, (Token.ARRAY, [
|
||||||
(Token.MEMBER, (Token.ARRAY, [
|
(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
(Token.ASSIGN, None, (Token.OPEXPR, [
|
(Token.MEMBER, (Token.ID, 'a'), None, None)]), None),
|
||||||
(Token.MEMBER, (Token.ID, 'a'), None, None)]), None),
|
(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
(Token.ASSIGN, None, (Token.OPEXPR, [
|
(Token.MEMBER, (Token.ID, 'b'), None, None)]), None)
|
||||||
(Token.MEMBER, (Token.ID, 'b'), None, None)]), None)
|
]), None, (Token.ELEM, (Token.EXPR, [
|
||||||
]), None, (Token.ELEM, (Token.EXPR, [
|
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.INT, 0), None, None)]), None)
|
||||||
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.INT, 0), None, None)]), None)
|
]), (Token.CALL, [
|
||||||
]), (Token.CALL, [
|
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.INT, 0), None, None)]), None)
|
||||||
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.INT, 0), None, None)]), None)
|
], None)))
|
||||||
], None)))
|
]), None)
|
||||||
]), None)
|
]))
|
||||||
])
|
]),
|
||||||
)
|
(Token.EXPR, [
|
||||||
]))
|
(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
|
(Token.MEMBER, (Token.ID, 'c'), None, (Token.CALL, [], None))
|
||||||
|
]), None)
|
||||||
|
])
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -16,32 +16,31 @@ tests = [
|
|||||||
''',
|
''',
|
||||||
'asserts': [{'value': 5, 'call': 5}],
|
'asserts': [{'value': 5, 'call': 5}],
|
||||||
'ast': [
|
'ast': [
|
||||||
(Token.FUNC, 'f', ['x'],
|
(Token.FUNC, 'f', ['x'], [
|
||||||
(Token.BLOCK, [
|
(Token.EXPR, [
|
||||||
|
(Token.ASSIGN, _ASSIGN_OPERATORS['='][1],
|
||||||
|
(Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'i'), None, None)]),
|
||||||
|
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.INT, 1), None, None)]), None))
|
||||||
|
]),
|
||||||
|
(Token.DO,
|
||||||
(Token.EXPR, [
|
(Token.EXPR, [
|
||||||
(Token.ASSIGN, _ASSIGN_OPERATORS['='][1],
|
(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
(Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'i'), None, None)]),
|
(Token.MEMBER, (Token.ID, 'i'), None, None),
|
||||||
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.INT, 1), None, None)]), None))
|
(Token.MEMBER, (Token.ID, 'x'), None, None),
|
||||||
|
(Token.REL, _RELATIONS['<'][1])
|
||||||
|
]), None)
|
||||||
]),
|
]),
|
||||||
(Token.DO,
|
(Token.BLOCK, [
|
||||||
(Token.EXPR, [
|
(Token.EXPR, [
|
||||||
(Token.ASSIGN, None, (Token.OPEXPR, [
|
(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
(Token.MEMBER, (Token.ID, 'i'), None, None),
|
(Token.MEMBER, (Token.ID, 'i'), None, None),
|
||||||
(Token.MEMBER, (Token.ID, 'x'), None, None),
|
(Token.POSTFIX, _UNARY_OPERATORS['++'][1])
|
||||||
(Token.REL, _RELATIONS['<'][1])
|
]), None)
|
||||||
]), None)
|
])
|
||||||
]),
|
])),
|
||||||
(Token.BLOCK, [
|
(Token.RETURN, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
(Token.EXPR, [
|
(Token.MEMBER, (Token.ID, 'i'), None, None)]), None)]))
|
||||||
(Token.ASSIGN, None, (Token.OPEXPR, [
|
])
|
||||||
(Token.MEMBER, (Token.ID, 'i'), None, None),
|
|
||||||
(Token.POSTFIX, _UNARY_OPERATORS['++'][1])
|
|
||||||
]), None)
|
|
||||||
])
|
|
||||||
])),
|
|
||||||
(Token.RETURN, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
|
||||||
(Token.MEMBER, (Token.ID, 'i'), None, None)]), None)]))
|
|
||||||
]))
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -16,32 +16,31 @@ tests = [
|
|||||||
''',
|
''',
|
||||||
'asserts': [{'value': 5, 'call': ('f', 5)}],
|
'asserts': [{'value': 5, 'call': ('f', 5)}],
|
||||||
'ast': [
|
'ast': [
|
||||||
(Token.FUNC, 'f', ['x'],
|
(Token.FUNC, 'f', ['x'], [
|
||||||
(Token.BLOCK, [
|
(Token.VAR, zip(['h'], [
|
||||||
(Token.VAR, zip(['h'], [
|
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.INT, 0), None, None)]), None)
|
||||||
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.INT, 0), None, None)]), None)
|
])),
|
||||||
|
(Token.FOR,
|
||||||
|
None,
|
||||||
|
(Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
|
(Token.MEMBER, (Token.ID, 'h'), None, None),
|
||||||
|
(Token.MEMBER, (Token.ID, 'x'), None, None),
|
||||||
|
(Token.REL, _RELATIONS['<='][1])
|
||||||
|
]), None)]),
|
||||||
|
(Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
|
(Token.MEMBER, (Token.ID, 'h'), None, None),
|
||||||
|
(Token.PREFIX, _UNARY_OPERATORS['++'][1])
|
||||||
|
]), None)]),
|
||||||
|
(Token.BLOCK, [
|
||||||
|
(Token.EXPR, [
|
||||||
|
(Token.ASSIGN, _ASSIGN_OPERATORS['='][1],
|
||||||
|
(Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'a'), None, None)]),
|
||||||
|
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'h'), None, None)]), None))
|
||||||
|
])
|
||||||
])),
|
])),
|
||||||
(Token.FOR,
|
(Token.RETURN, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
None,
|
(Token.MEMBER, (Token.ID, 'a'), None, None)]), None)]))
|
||||||
(Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
])
|
||||||
(Token.MEMBER, (Token.ID, 'h'), None, None),
|
|
||||||
(Token.MEMBER, (Token.ID, 'x'), None, None),
|
|
||||||
(Token.REL, _RELATIONS['<='][1])
|
|
||||||
]), None)]),
|
|
||||||
(Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
|
||||||
(Token.MEMBER, (Token.ID, 'h'), None, None),
|
|
||||||
(Token.PREFIX, _UNARY_OPERATORS['++'][1])
|
|
||||||
]), None)]),
|
|
||||||
(Token.BLOCK, [
|
|
||||||
(Token.EXPR, [
|
|
||||||
(Token.ASSIGN, _ASSIGN_OPERATORS['='][1],
|
|
||||||
(Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'a'), None, None)]),
|
|
||||||
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'h'), None, None)]), None))
|
|
||||||
])
|
|
||||||
])),
|
|
||||||
(Token.RETURN, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
|
||||||
(Token.MEMBER, (Token.ID, 'a'), None, None)]), None)]))
|
|
||||||
]))
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -15,26 +15,25 @@ tests = [
|
|||||||
''',
|
''',
|
||||||
'asserts': [{'value': 'c', 'call': ('f', ['a', 'b', 'c'])}],
|
'asserts': [{'value': 'c', 'call': ('f', ['a', 'b', 'c'])}],
|
||||||
'ast': [
|
'ast': [
|
||||||
(Token.FUNC, 'f', ['z'],
|
(Token.FUNC, 'f', ['z'], [
|
||||||
(Token.BLOCK, [
|
(Token.FOR,
|
||||||
(Token.FOR,
|
(Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
(Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
(Token.MEMBER, (Token.ID, 'h'), None, None)
|
||||||
(Token.MEMBER, (Token.ID, 'h'), None, None)
|
]), None)]),
|
||||||
]), None)]),
|
(Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
(Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
(Token.MEMBER, (Token.ID, 'z'), None, None)
|
||||||
(Token.MEMBER, (Token.ID, 'z'), None, None)
|
]), None)]),
|
||||||
]), None)]),
|
None,
|
||||||
None,
|
(Token.BLOCK, [
|
||||||
(Token.BLOCK, [
|
(Token.EXPR, [
|
||||||
(Token.EXPR, [
|
(Token.ASSIGN, _ASSIGN_OPERATORS['='][1],
|
||||||
(Token.ASSIGN, _ASSIGN_OPERATORS['='][1],
|
(Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'a'), None, None)]),
|
||||||
(Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'a'), None, None)]),
|
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'h'), None, None)]), None))
|
||||||
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'h'), None, None)]), None))
|
])
|
||||||
])
|
])),
|
||||||
])),
|
(Token.RETURN, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
(Token.RETURN, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
(Token.MEMBER, (Token.ID, 'a'), None, None)]), None)]))
|
||||||
(Token.MEMBER, (Token.ID, 'a'), None, None)]), None)]))
|
])
|
||||||
]))
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -15,31 +15,30 @@ tests = [
|
|||||||
''',
|
''',
|
||||||
'asserts': [{'value': 5, 'call': ('f', 5)}],
|
'asserts': [{'value': 5, 'call': ('f', 5)}],
|
||||||
'ast': [
|
'ast': [
|
||||||
(Token.FUNC, 'f', ['x'],
|
(Token.FUNC, 'f', ['x'], [
|
||||||
(Token.BLOCK, [
|
(Token.FOR,
|
||||||
(Token.FOR,
|
(Token.VAR, zip(['h'], [
|
||||||
(Token.VAR, zip(['h'], [
|
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.INT, 0), None, None)]), None)
|
||||||
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.INT, 0), None, None)]), None)
|
])),
|
||||||
])),
|
(Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
(Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
(Token.MEMBER, (Token.ID, 'h'), None, None),
|
||||||
(Token.MEMBER, (Token.ID, 'h'), None, None),
|
(Token.MEMBER, (Token.ID, 'x'), None, None),
|
||||||
(Token.MEMBER, (Token.ID, 'x'), None, None),
|
(Token.REL, _RELATIONS['<='][1])
|
||||||
(Token.REL, _RELATIONS['<='][1])
|
]), None)]),
|
||||||
]), None)]),
|
(Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
(Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
(Token.MEMBER, (Token.ID, 'h'), None, None),
|
||||||
(Token.MEMBER, (Token.ID, 'h'), None, None),
|
(Token.PREFIX, _UNARY_OPERATORS['++'][1])
|
||||||
(Token.PREFIX, _UNARY_OPERATORS['++'][1])
|
]), None)]),
|
||||||
]), None)]),
|
(Token.BLOCK, [
|
||||||
(Token.BLOCK, [
|
(Token.EXPR, [
|
||||||
(Token.EXPR, [
|
(Token.ASSIGN, _ASSIGN_OPERATORS['='][1],
|
||||||
(Token.ASSIGN, _ASSIGN_OPERATORS['='][1],
|
(Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'a'), None, None)]),
|
||||||
(Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'a'), None, None)]),
|
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'h'), None, None)]), None))
|
||||||
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'h'), None, None)]), None))
|
])
|
||||||
])
|
])),
|
||||||
])),
|
(Token.RETURN, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
(Token.RETURN, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
(Token.MEMBER, (Token.ID, 'a'), None, None)]), None)]))
|
||||||
(Token.MEMBER, (Token.ID, 'a'), None, None)]), None)]))
|
])
|
||||||
]))
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -18,41 +18,40 @@ tests = [
|
|||||||
''',
|
''',
|
||||||
'asserts': [{'value': 3, 'call': ('f',)}],
|
'asserts': [{'value': 3, 'call': ('f',)}],
|
||||||
'ast': [
|
'ast': [
|
||||||
(Token.FUNC, 'f', [],
|
(Token.FUNC, 'f', [], [
|
||||||
(Token.BLOCK, [
|
(Token.VAR, zip(['add'], [(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
(Token.VAR, zip(['add'], [(Token.ASSIGN, None, (Token.OPEXPR, [
|
(Token.MEMBER, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
(Token.MEMBER, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
(Token.MEMBER, (Token.FUNC, None, [], [
|
||||||
(Token.MEMBER, (Token.FUNC, None, [], (Token.BLOCK, [
|
(Token.VAR, zip(
|
||||||
(Token.VAR, zip(
|
['counter'],
|
||||||
['counter'],
|
[(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
[(Token.ASSIGN, None, (Token.OPEXPR, [
|
(Token.MEMBER, (Token.INT, 0), None, None)
|
||||||
(Token.MEMBER, (Token.INT, 0), None, None)
|
]), None)]
|
||||||
]), None)]
|
)),
|
||||||
)),
|
(Token.RETURN, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
(Token.RETURN, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
(Token.MEMBER, (Token.FUNC, None, [], [
|
||||||
(Token.MEMBER, (Token.FUNC, None, [], (Token.BLOCK, [
|
(Token.RETURN, (Token.EXPR, [
|
||||||
(Token.RETURN, (Token.EXPR, [
|
(Token.ASSIGN, _ASSIGN_OPERATORS['+='][1], (Token.OPEXPR, [
|
||||||
(Token.ASSIGN, _ASSIGN_OPERATORS['+='][1], (Token.OPEXPR, [
|
(Token.MEMBER, (Token.ID, 'counter'), None, None)
|
||||||
(Token.MEMBER, (Token.ID, 'counter'), None, None)
|
]), (Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
]), (Token.ASSIGN, None, (Token.OPEXPR, [
|
(Token.MEMBER, (Token.INT, 1), None, None)
|
||||||
(Token.MEMBER, (Token.INT, 1), None, None)
|
]), None))
|
||||||
]), None))
|
]))
|
||||||
]))
|
]), None, None)
|
||||||
])), None, None)
|
]), None)]))
|
||||||
]), None)]))
|
]), None, None),
|
||||||
])), None, None),
|
]), None)]), None, (Token.CALL, [], None))
|
||||||
]), None)]), None, (Token.CALL, [], None))
|
]), None)])),
|
||||||
]), None)])),
|
(Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
(Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
(Token.MEMBER, (Token.ID, 'add'), None, (Token.CALL, [], None))
|
||||||
(Token.MEMBER, (Token.ID, 'add'), None, (Token.CALL, [], None))
|
]), None)]),
|
||||||
]), None)]),
|
(Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
(Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
(Token.MEMBER, (Token.ID, 'add'), None, (Token.CALL, [], None))
|
||||||
(Token.MEMBER, (Token.ID, 'add'), None, (Token.CALL, [], None))
|
]), None)]),
|
||||||
]), None)]),
|
(Token.RETURN, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
(Token.RETURN, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
(Token.MEMBER, (Token.ID, 'add'), None, (Token.CALL, [], None))
|
||||||
(Token.MEMBER, (Token.ID, 'add'), None, (Token.CALL, [], None))
|
]), None)]))
|
||||||
]), None)]))
|
])
|
||||||
]))
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -16,44 +16,43 @@ tests = [
|
|||||||
}
|
}
|
||||||
''',
|
''',
|
||||||
'ast': [
|
'ast': [
|
||||||
(Token.FUNC, 'f', [],
|
(Token.FUNC, 'f', [], [
|
||||||
(Token.BLOCK, [
|
(Token.VAR,
|
||||||
(Token.VAR,
|
zip(['o'],
|
||||||
zip(['o'],
|
[(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
[(Token.ASSIGN, None, (Token.OPEXPR, [
|
(Token.MEMBER, (Token.OBJECT, [
|
||||||
(Token.MEMBER, (Token.OBJECT, [
|
('a', (Token.PROPVALUE, (Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
('a', (Token.PROPVALUE, (Token.ASSIGN, None, (Token.OPEXPR, [
|
(Token.MEMBER, (Token.INT, 7), None, None)
|
||||||
(Token.MEMBER, (Token.INT, 7), None, None)
|
]), None))),
|
||||||
]), None))),
|
('b', (Token.PROPGET, [
|
||||||
('b', (Token.PROPGET, (Token.BLOCK, [
|
(Token.RETURN, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
(Token.RETURN, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
(Token.MEMBER, (Token.RSV, 'this'), None, (Token.FIELD, 'a', None)),
|
||||||
(Token.MEMBER, (Token.RSV, 'this'), None, (Token.FIELD, 'a', None)),
|
(Token.MEMBER, (Token.INT, 1), None, None),
|
||||||
(Token.MEMBER, (Token.INT, 1), None, None),
|
(Token.OP, _OPERATORS['+'][1])
|
||||||
(Token.OP, _OPERATORS['+'][1])
|
]), None)]))
|
||||||
]), None)]))
|
])),
|
||||||
]))),
|
('c', (Token.PROPSET, 'x', [
|
||||||
('c', (Token.PROPSET, 'x', (Token.BLOCK, [
|
(Token.EXPR, [
|
||||||
(Token.EXPR, [
|
(Token.ASSIGN,
|
||||||
(Token.ASSIGN,
|
_ASSIGN_OPERATORS['='][1],
|
||||||
_ASSIGN_OPERATORS['='][1],
|
(Token.OPEXPR, [
|
||||||
(Token.OPEXPR, [
|
(Token.MEMBER, (Token.RSV, 'this'), None, (Token.FIELD, 'a', None))
|
||||||
(Token.MEMBER, (Token.RSV, 'this'), None, (Token.FIELD, 'a', None))
|
]),
|
||||||
]),
|
(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
(Token.ASSIGN, None, (Token.OPEXPR, [
|
(Token.MEMBER, (Token.ID, 'x'), None, None),
|
||||||
(Token.MEMBER, (Token.ID, 'x'), None, None),
|
(Token.MEMBER, (Token.INT, 2), None, None),
|
||||||
(Token.MEMBER, (Token.INT, 2), None, None),
|
(Token.OP, _OPERATORS['/'][1])
|
||||||
(Token.OP, _OPERATORS['/'][1])
|
]), None))
|
||||||
]), None))
|
])
|
||||||
])
|
]))
|
||||||
])))
|
]),
|
||||||
]),
|
None, None)
|
||||||
None, None)
|
]), None)]
|
||||||
]), None)]
|
)
|
||||||
)
|
),
|
||||||
),
|
(Token.RETURN, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
(Token.RETURN, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
(Token.MEMBER, (Token.ID, 'o'), None, None)]), None)]))
|
||||||
(Token.MEMBER, (Token.ID, 'o'), None, None)]), None)]))
|
])
|
||||||
]))
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -26,48 +26,48 @@ tests = [
|
|||||||
{'value': 6, 'call': ('a', 6)},
|
{'value': 6, 'call': ('a', 6)},
|
||||||
{'value': 8, 'call': ('a', 7)}],
|
{'value': 8, 'call': ('a', 7)}],
|
||||||
'ast': [
|
'ast': [
|
||||||
(Token.FUNC, 'a', ['x'],
|
(Token.FUNC, 'a', ['x'], [
|
||||||
(Token.BLOCK, [
|
(Token.SWITCH, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
(Token.SWITCH, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
(Token.MEMBER, (Token.ID, 'x'), None, None)
|
||||||
(Token.MEMBER, (Token.ID, 'x'), None, None)
|
]), None)]),
|
||||||
]), None)]),
|
[
|
||||||
[
|
((Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
((Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
(Token.MEMBER, (Token.INT, 6), None, None)]), None)]),
|
||||||
(Token.MEMBER, (Token.INT, 6), None, None)]), None)]),
|
[
|
||||||
[
|
(Token.BREAK, None)
|
||||||
(Token.BREAK, None)
|
]),
|
||||||
]),
|
((Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
((Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
(Token.MEMBER, (Token.INT, 5), None, None)]), None)]),
|
||||||
(Token.MEMBER, (Token.INT, 5), None, None)]), None)]),
|
[
|
||||||
[
|
(Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
(Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
(Token.MEMBER, (Token.ID, 'x'), None, None),
|
||||||
(Token.MEMBER, (Token.ID, 'x'), None, None),
|
(Token.POSTFIX, _UNARY_OPERATORS['++'][1])
|
||||||
(Token.POSTFIX, _UNARY_OPERATORS['++'][1])
|
]), None)])
|
||||||
]), None)])
|
]),
|
||||||
]),
|
((Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
((Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
(Token.MEMBER, (Token.INT, 8), None, None)]), None)]),
|
||||||
(Token.MEMBER, (Token.INT, 8), None, None)]), None)]),
|
[
|
||||||
[
|
(Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
(Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
(Token.MEMBER, (Token.ID, 'x'), None, None),
|
||||||
(Token.MEMBER, (Token.ID, 'x'), None, None),
|
(Token.POSTFIX, _UNARY_OPERATORS['--'][1])
|
||||||
(Token.POSTFIX, _UNARY_OPERATORS['--'][1])
|
]), None)]),
|
||||||
]), None)]),
|
(Token.BREAK, None)
|
||||||
(Token.BREAK, None)
|
]),
|
||||||
]),
|
(None,
|
||||||
(None,
|
[
|
||||||
[
|
(Token.EXPR, [
|
||||||
(Token.EXPR, [
|
(Token.ASSIGN,
|
||||||
(Token.ASSIGN,
|
_ASSIGN_OPERATORS['='][1],
|
||||||
_ASSIGN_OPERATORS['='][1],
|
(Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'x'), None, None)]),
|
||||||
(Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'x'), None, None)]),
|
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.INT, 0), None, None)]), None)
|
||||||
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.INT, 0), None, None)]), None)
|
)
|
||||||
)
|
])
|
||||||
])
|
])
|
||||||
])
|
]
|
||||||
]
|
),
|
||||||
),
|
(Token.RETURN, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
(Token.RETURN, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
(Token.MEMBER, (Token.ID, 'x'), None, None)]), None)]))
|
||||||
(Token.MEMBER, (Token.ID, 'x'), None, None)]), None)]))
|
])
|
||||||
]))]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -16,32 +16,31 @@ tests = [
|
|||||||
''',
|
''',
|
||||||
'asserts': [{'value': 5, 'call': ('f', 5)}],
|
'asserts': [{'value': 5, 'call': ('f', 5)}],
|
||||||
'ast': [
|
'ast': [
|
||||||
(Token.FUNC, 'f', ['x'],
|
(Token.FUNC, 'f', ['x'], [
|
||||||
(Token.BLOCK, [
|
(Token.EXPR, [
|
||||||
|
(Token.ASSIGN, _ASSIGN_OPERATORS['='][1],
|
||||||
|
(Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'i'), None, None)]),
|
||||||
|
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.INT, 1), None, None)]), None))
|
||||||
|
]),
|
||||||
|
(Token.WHILE,
|
||||||
(Token.EXPR, [
|
(Token.EXPR, [
|
||||||
(Token.ASSIGN, _ASSIGN_OPERATORS['='][1],
|
(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
(Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'i'), None, None)]),
|
(Token.MEMBER, (Token.ID, 'i'), None, None),
|
||||||
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.INT, 1), None, None)]), None))
|
(Token.MEMBER, (Token.ID, 'x'), None, None),
|
||||||
|
(Token.REL, _RELATIONS['<'][1])
|
||||||
|
]), None)
|
||||||
]),
|
]),
|
||||||
(Token.WHILE,
|
(Token.BLOCK, [
|
||||||
(Token.EXPR, [
|
(Token.EXPR, [
|
||||||
(Token.ASSIGN, None, (Token.OPEXPR, [
|
(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
(Token.MEMBER, (Token.ID, 'i'), None, None),
|
(Token.MEMBER, (Token.ID, 'i'), None, None),
|
||||||
(Token.MEMBER, (Token.ID, 'x'), None, None),
|
(Token.POSTFIX, _UNARY_OPERATORS['++'][1])
|
||||||
(Token.REL, _RELATIONS['<'][1])
|
]), None)
|
||||||
]), None)
|
])
|
||||||
]),
|
])),
|
||||||
(Token.BLOCK, [
|
(Token.RETURN, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
||||||
(Token.EXPR, [
|
(Token.MEMBER, (Token.ID, 'i'), None, None)]), None)]))
|
||||||
(Token.ASSIGN, None, (Token.OPEXPR, [
|
])
|
||||||
(Token.MEMBER, (Token.ID, 'i'), None, None),
|
|
||||||
(Token.POSTFIX, _UNARY_OPERATORS['++'][1])
|
|
||||||
]), None)
|
|
||||||
])
|
|
||||||
])),
|
|
||||||
(Token.RETURN, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
|
|
||||||
(Token.MEMBER, (Token.ID, 'i'), None, None)]), None)]))
|
|
||||||
]))
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -43,7 +43,7 @@ def generator(test_case, name):
|
|||||||
def test_template(self):
|
def test_template(self):
|
||||||
for a in test_case['subtests']:
|
for a in test_case['subtests']:
|
||||||
jsi = JSInterpreter(a['code'], variables=None if 'globals' not in a else a['globals'])
|
jsi = JSInterpreter(a['code'], variables=None if 'globals' not in a else a['globals'])
|
||||||
parsed = list(jsi.statements())
|
parsed = list(jsi.parse())
|
||||||
if 'ast' in a:
|
if 'ast' in a:
|
||||||
self.assertEqual(traverse(parsed), traverse(a['ast']))
|
self.assertEqual(traverse(parsed), traverse(a['ast']))
|
||||||
else:
|
else:
|
||||||
|
@ -24,8 +24,18 @@ class Reference(object):
|
|||||||
self._value = value
|
self._value = value
|
||||||
self._parent = parent
|
self._parent = parent
|
||||||
|
|
||||||
def getvalue(self):
|
def getvalue(self, deep=False):
|
||||||
return self._value
|
value = self._value
|
||||||
|
if deep:
|
||||||
|
if isinstance(self._value, (list, tuple)):
|
||||||
|
# TODO test nested arrays
|
||||||
|
value = [elem.getvalue() for elem in self._value]
|
||||||
|
elif isinstance(self._value, dict):
|
||||||
|
value = {}
|
||||||
|
for key, prop in self._value.items():
|
||||||
|
value[key] = prop.getvalue()
|
||||||
|
|
||||||
|
return value
|
||||||
|
|
||||||
def putvalue(self, value):
|
def putvalue(self, value):
|
||||||
if self._parent is None:
|
if self._parent is None:
|
||||||
@ -34,6 +44,7 @@ class Reference(object):
|
|||||||
if not hasattr(parent, '__setitem__'):
|
if not hasattr(parent, '__setitem__'):
|
||||||
raise ExtractorError('Unknown reference')
|
raise ExtractorError('Unknown reference')
|
||||||
parent.__setitem__(key, Reference(value, (parent, key)))
|
parent.__setitem__(key, Reference(value, (parent, key)))
|
||||||
|
self._value = value
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
@ -62,12 +73,12 @@ class JSInterpreter(object):
|
|||||||
def this(self):
|
def this(self):
|
||||||
return self._context.local_vars
|
return self._context.local_vars
|
||||||
|
|
||||||
def statements(self, code=None, pos=0, stack_size=100):
|
def parse(self, code=None, pos=0, stack_size=100):
|
||||||
if code is None:
|
if code is None:
|
||||||
code = self.code
|
code = self.code
|
||||||
ts = TokenStream(code, pos)
|
ts = TokenStream(code, pos)
|
||||||
while not ts.ended:
|
while not ts.ended:
|
||||||
yield self._statement(ts, stack_size)
|
yield self._source_element(ts, stack_size)
|
||||||
raise StopIteration
|
raise StopIteration
|
||||||
|
|
||||||
def create_reference(self, value, parent_key):
|
def create_reference(self, value, parent_key):
|
||||||
@ -86,23 +97,29 @@ class JSInterpreter(object):
|
|||||||
|
|
||||||
return Reference(o, parent_key)
|
return Reference(o, parent_key)
|
||||||
|
|
||||||
|
def _source_element(self, token_stream, stack_top):
|
||||||
|
if stack_top < 0:
|
||||||
|
raise ExtractorError('Recursion limit reached')
|
||||||
|
|
||||||
|
token_id, token_value, token_pos = token_stream.peek()
|
||||||
|
if token_id is Token.ID and token_value == 'function':
|
||||||
|
source_element = self._function(token_stream, stack_top - 1)
|
||||||
|
else:
|
||||||
|
source_element = self._statement(token_stream, stack_top - 1)
|
||||||
|
|
||||||
|
return source_element
|
||||||
|
|
||||||
def _statement(self, token_stream, stack_top):
|
def _statement(self, token_stream, stack_top):
|
||||||
if stack_top < 0:
|
if stack_top < 0:
|
||||||
raise ExtractorError('Recursion limit reached')
|
raise ExtractorError('Recursion limit reached')
|
||||||
# ast
|
|
||||||
statement = None
|
|
||||||
|
|
||||||
|
statement = None
|
||||||
token_id, token_value, token_pos = token_stream.peek()
|
token_id, token_value, token_pos = token_stream.peek()
|
||||||
if token_id is Token.END:
|
if token_id is Token.END:
|
||||||
# empty statement goes straight here
|
# empty statement goes straight here
|
||||||
token_stream.pop()
|
token_stream.pop()
|
||||||
return statement
|
return statement
|
||||||
|
|
||||||
elif token_id is Token.ID and token_value == 'function':
|
|
||||||
# FIXME allowed only in program and function body
|
|
||||||
# main, function expr, object literal (set, get), function declaration
|
|
||||||
statement = self._function(token_stream, stack_top - 1)
|
|
||||||
|
|
||||||
# block
|
# block
|
||||||
elif token_id is Token.COPEN:
|
elif token_id is Token.COPEN:
|
||||||
# XXX refactor will deprecate some _statement calls
|
# XXX refactor will deprecate some _statement calls
|
||||||
@ -245,21 +262,27 @@ class JSInterpreter(object):
|
|||||||
return statement
|
return statement
|
||||||
|
|
||||||
def _if_statement(self, token_stream, stack_top):
|
def _if_statement(self, token_stream, stack_top):
|
||||||
|
if stack_top < 0:
|
||||||
|
raise ExtractorError('Recursion limit reached')
|
||||||
|
|
||||||
token_stream.pop()
|
token_stream.pop()
|
||||||
token_id, token_value, token_pos = token_stream.pop()
|
token_id, token_value, token_pos = token_stream.pop()
|
||||||
if token_id is not Token.POPEN:
|
if token_id is not Token.POPEN:
|
||||||
raise ExtractorError('Missing condition at %d' % token_pos)
|
raise ExtractorError('Missing condition at %d' % token_pos)
|
||||||
cond_expr = self._expression(token_stream, stack_top - 1)
|
cond_expr = self._expression(token_stream, stack_top - 1)
|
||||||
token_stream.pop() # Token.PCLOSE
|
token_stream.pop() # Token.PCLOSE
|
||||||
true_expr = self._statement(token_stream, stack_top - 1)
|
true_stmt = self._statement(token_stream, stack_top - 1)
|
||||||
false_expr = None
|
false_stmt = None
|
||||||
token_id, token_value, token_pos = token_stream.peek()
|
token_id, token_value, token_pos = token_stream.peek()
|
||||||
if token_id is Token.ID and token_value == 'else':
|
if token_id is Token.ID and token_value == 'else':
|
||||||
token_stream.pop()
|
token_stream.pop()
|
||||||
false_expr = self._statement(token_stream, stack_top - 1)
|
false_stmt = self._statement(token_stream, stack_top - 1)
|
||||||
return (Token.IF, cond_expr, true_expr, false_expr)
|
return (Token.IF, cond_expr, true_stmt, false_stmt)
|
||||||
|
|
||||||
def _for_loop(self, token_stream, stack_top):
|
def _for_loop(self, token_stream, stack_top):
|
||||||
|
if stack_top < 0:
|
||||||
|
raise ExtractorError('Recursion limit reached')
|
||||||
|
|
||||||
token_stream.pop()
|
token_stream.pop()
|
||||||
token_id, token_value, token_pos = token_stream.pop()
|
token_id, token_value, token_pos = token_stream.pop()
|
||||||
if token_id is not Token.POPEN:
|
if token_id is not Token.POPEN:
|
||||||
@ -302,6 +325,9 @@ class JSInterpreter(object):
|
|||||||
return (Token.FOR, init, cond, incr, body)
|
return (Token.FOR, init, cond, incr, body)
|
||||||
|
|
||||||
def _do_loop(self, token_stream, stack_top):
|
def _do_loop(self, token_stream, stack_top):
|
||||||
|
if stack_top < 0:
|
||||||
|
raise ExtractorError('Recursion limit reached')
|
||||||
|
|
||||||
token_stream.pop()
|
token_stream.pop()
|
||||||
body = self._statement(token_stream, stack_top - 1)
|
body = self._statement(token_stream, stack_top - 1)
|
||||||
token_id, token_value, token_pos = token_stream.pop()
|
token_id, token_value, token_pos = token_stream.pop()
|
||||||
@ -323,6 +349,9 @@ class JSInterpreter(object):
|
|||||||
return (Token.DO, expr, body)
|
return (Token.DO, expr, body)
|
||||||
|
|
||||||
def _while_loop(self, token_stream, stack_top):
|
def _while_loop(self, token_stream, stack_top):
|
||||||
|
if stack_top < 0:
|
||||||
|
raise ExtractorError('Recursion limit reached')
|
||||||
|
|
||||||
token_stream.pop()
|
token_stream.pop()
|
||||||
token_id, token_value, token_pos = token_stream.pop()
|
token_id, token_value, token_pos = token_stream.pop()
|
||||||
if token_id is not Token.POPEN:
|
if token_id is not Token.POPEN:
|
||||||
@ -335,6 +364,9 @@ class JSInterpreter(object):
|
|||||||
return (Token.WHILE, expr, body)
|
return (Token.WHILE, expr, body)
|
||||||
|
|
||||||
def _return_statement(self, token_stream, stack_top):
|
def _return_statement(self, token_stream, stack_top):
|
||||||
|
if stack_top < 0:
|
||||||
|
raise ExtractorError('Recursion limit reached')
|
||||||
|
|
||||||
token_stream.pop()
|
token_stream.pop()
|
||||||
peek_id, peek_value, peek_pos = token_stream.peek()
|
peek_id, peek_value, peek_pos = token_stream.peek()
|
||||||
# XXX no line break here
|
# XXX no line break here
|
||||||
@ -342,6 +374,9 @@ class JSInterpreter(object):
|
|||||||
return (Token.RETURN, expr)
|
return (Token.RETURN, expr)
|
||||||
|
|
||||||
def _with_statement(self, token_stream, stack_top):
|
def _with_statement(self, token_stream, stack_top):
|
||||||
|
if stack_top < 0:
|
||||||
|
raise ExtractorError('Recursion limit reached')
|
||||||
|
|
||||||
token_stream.pop()
|
token_stream.pop()
|
||||||
token_id, token_value, token_pos = token_stream.pop()
|
token_id, token_value, token_pos = token_stream.pop()
|
||||||
if token_id is not Token.POPEN:
|
if token_id is not Token.POPEN:
|
||||||
@ -351,6 +386,9 @@ class JSInterpreter(object):
|
|||||||
return (Token.WITH, expr, self._statement(token_stream, stack_top - 1))
|
return (Token.WITH, expr, self._statement(token_stream, stack_top - 1))
|
||||||
|
|
||||||
def _switch_statement(self, token_stream, stack_top):
|
def _switch_statement(self, token_stream, stack_top):
|
||||||
|
if stack_top < 0:
|
||||||
|
raise ExtractorError('Recursion limit reached')
|
||||||
|
|
||||||
token_stream.pop()
|
token_stream.pop()
|
||||||
token_id, token_value, token_pos = token_stream.pop()
|
token_id, token_value, token_pos = token_stream.pop()
|
||||||
if token_id is not Token.POPEN:
|
if token_id is not Token.POPEN:
|
||||||
@ -402,6 +440,9 @@ class JSInterpreter(object):
|
|||||||
return (Token.SWITCH, discriminant, block)
|
return (Token.SWITCH, discriminant, block)
|
||||||
|
|
||||||
def _try_statement(self, token_stream, stack_top):
|
def _try_statement(self, token_stream, stack_top):
|
||||||
|
if stack_top < 0:
|
||||||
|
raise ExtractorError('Recursion limit reached')
|
||||||
|
|
||||||
token_stream.pop()
|
token_stream.pop()
|
||||||
token_id, token_value, token_pos = token_stream.peek()
|
token_id, token_value, token_pos = token_stream.peek()
|
||||||
if token_id is not Token.COPEN:
|
if token_id is not Token.COPEN:
|
||||||
@ -434,6 +475,9 @@ class JSInterpreter(object):
|
|||||||
return (Token.TRY, try_block, catch_block, finally_block)
|
return (Token.TRY, try_block, catch_block, finally_block)
|
||||||
|
|
||||||
def _expression(self, token_stream, stack_top):
|
def _expression(self, token_stream, stack_top):
|
||||||
|
if stack_top < 0:
|
||||||
|
raise ExtractorError('Recursion limit reached')
|
||||||
|
|
||||||
expr_list = []
|
expr_list = []
|
||||||
has_another = True
|
has_another = True
|
||||||
while has_another:
|
while has_another:
|
||||||
@ -464,6 +508,9 @@ class JSInterpreter(object):
|
|||||||
return (Token.ASSIGN, op, left, right)
|
return (Token.ASSIGN, op, left, right)
|
||||||
|
|
||||||
def _member_expression(self, token_stream, stack_top):
|
def _member_expression(self, token_stream, stack_top):
|
||||||
|
if stack_top < 0:
|
||||||
|
raise ExtractorError('Recursion limit reached')
|
||||||
|
|
||||||
peek_id, peek_value, peek_pos = token_stream.peek()
|
peek_id, peek_value, peek_pos = token_stream.peek()
|
||||||
if peek_id is Token.ID and peek_value == 'new':
|
if peek_id is Token.ID and peek_value == 'new':
|
||||||
token_stream.pop()
|
token_stream.pop()
|
||||||
@ -555,8 +602,12 @@ class JSInterpreter(object):
|
|||||||
raise ExtractorError('Syntax error at %d' % peek_pos)
|
raise ExtractorError('Syntax error at %d' % peek_pos)
|
||||||
|
|
||||||
def _function(self, token_stream, stack_top, is_expr=False):
|
def _function(self, token_stream, stack_top, is_expr=False):
|
||||||
|
if stack_top < 0:
|
||||||
|
raise ExtractorError('Recursion limit reached')
|
||||||
|
|
||||||
token_stream.pop()
|
token_stream.pop()
|
||||||
token_id, token_value, token_pos = token_stream.peek()
|
token_id, token_value, token_pos = token_stream.peek()
|
||||||
|
|
||||||
name = None
|
name = None
|
||||||
if token_id is Token.ID:
|
if token_id is Token.ID:
|
||||||
token_stream.chk_id()
|
token_stream.chk_id()
|
||||||
@ -568,9 +619,9 @@ class JSInterpreter(object):
|
|||||||
if token_id is not Token.POPEN:
|
if token_id is not Token.POPEN:
|
||||||
raise ExtractorError('Expected argument list at %d' % token_pos)
|
raise ExtractorError('Expected argument list at %d' % token_pos)
|
||||||
|
|
||||||
|
# args
|
||||||
token_stream.pop()
|
token_stream.pop()
|
||||||
open_pos = token_pos
|
open_pos = token_pos
|
||||||
|
|
||||||
args = []
|
args = []
|
||||||
while True:
|
while True:
|
||||||
token_id, token_value, token_pos = token_stream.peek()
|
token_id, token_value, token_pos = token_stream.peek()
|
||||||
@ -594,7 +645,24 @@ class JSInterpreter(object):
|
|||||||
if token_id is not Token.COPEN:
|
if token_id is not Token.COPEN:
|
||||||
raise ExtractorError('Expected function body at %d' % token_pos)
|
raise ExtractorError('Expected function body at %d' % token_pos)
|
||||||
|
|
||||||
return (Token.FUNC, name, args, self._statement(token_stream, stack_top - 1))
|
return (Token.FUNC, name, args, (self._function_body(token_stream, stack_top - 1)))
|
||||||
|
|
||||||
|
def _function_body(self, token_stream, stack_top):
|
||||||
|
if stack_top < 0:
|
||||||
|
raise ExtractorError('Recursion limit reached')
|
||||||
|
|
||||||
|
token_id, token_value, open_pos = token_stream.pop()
|
||||||
|
body = []
|
||||||
|
while True:
|
||||||
|
token_id, token_value, token_pos = token_stream.peek()
|
||||||
|
if token_id is Token.CCLOSE:
|
||||||
|
token_stream.pop()
|
||||||
|
break
|
||||||
|
elif token_id is Token.END and token_stream.ended:
|
||||||
|
raise ExtractorError('Unbalanced parentheses at %d' % open_pos)
|
||||||
|
body.append(self._source_element(token_stream, stack_top - 1))
|
||||||
|
|
||||||
|
return body
|
||||||
|
|
||||||
def _arguments(self, token_stream, stack_top):
|
def _arguments(self, token_stream, stack_top):
|
||||||
if stack_top < 0:
|
if stack_top < 0:
|
||||||
@ -660,6 +728,9 @@ class JSInterpreter(object):
|
|||||||
return (Token.ARRAY, elements)
|
return (Token.ARRAY, elements)
|
||||||
|
|
||||||
def _object_literal(self, token_stream, stack_top):
|
def _object_literal(self, token_stream, stack_top):
|
||||||
|
if stack_top < 0:
|
||||||
|
raise ExtractorError('Recursion limit reached')
|
||||||
|
|
||||||
token_id, token_value, open_pos = token_stream.pop()
|
token_id, token_value, open_pos = token_stream.pop()
|
||||||
property_list = []
|
property_list = []
|
||||||
while True:
|
while True:
|
||||||
@ -688,9 +759,9 @@ class JSInterpreter(object):
|
|||||||
raise ExtractorError('''Expected ')' at %d''' % token_pos)
|
raise ExtractorError('''Expected ')' at %d''' % token_pos)
|
||||||
|
|
||||||
if is_set:
|
if is_set:
|
||||||
desc = (Token.PROPSET, arg, self._statement(token_stream, stack_top - 1))
|
desc = (Token.PROPSET, arg, self._function_body(token_stream, stack_top - 1))
|
||||||
else:
|
else:
|
||||||
desc = (Token.PROPGET, self._statement(token_stream, stack_top - 1))
|
desc = (Token.PROPGET, self._function_body(token_stream, stack_top - 1))
|
||||||
|
|
||||||
elif token_id in (Token.ID, Token.STR, Token.INT, Token.FLOAT):
|
elif token_id in (Token.ID, Token.STR, Token.INT, Token.FLOAT):
|
||||||
property_name = token_value
|
property_name = token_value
|
||||||
@ -757,8 +828,7 @@ class JSInterpreter(object):
|
|||||||
out = []
|
out = []
|
||||||
stack = []
|
stack = []
|
||||||
|
|
||||||
has_another = True
|
while True:
|
||||||
while has_another:
|
|
||||||
had_inc = False
|
had_inc = False
|
||||||
has_prefix = True
|
has_prefix = True
|
||||||
while has_prefix:
|
while has_prefix:
|
||||||
@ -828,13 +898,15 @@ class JSInterpreter(object):
|
|||||||
name, op = peek_value
|
name, op = peek_value
|
||||||
prec = {Token.OR: 5, Token.AND: 6}[name]
|
prec = {Token.OR: 5, Token.AND: 6}[name]
|
||||||
else:
|
else:
|
||||||
has_another = False
|
op = None
|
||||||
prec = 4 # empties stack
|
prec = 4 # empties stack
|
||||||
|
|
||||||
while stack and stack[-1][0] >= prec:
|
while stack and stack[-1][0] >= prec:
|
||||||
_, stack_id, stack_op = stack.pop()
|
_, stack_id, stack_op = stack.pop()
|
||||||
out.append((stack_id, stack_op))
|
out.append((stack_id, stack_op))
|
||||||
if has_another:
|
if op is None:
|
||||||
|
break
|
||||||
|
else:
|
||||||
stack.append((prec, peek_id, op))
|
stack.append((prec, peek_id, op))
|
||||||
token_stream.pop()
|
token_stream.pop()
|
||||||
|
|
||||||
@ -846,9 +918,15 @@ class JSInterpreter(object):
|
|||||||
|
|
||||||
name = stmt[0]
|
name = stmt[0]
|
||||||
ref = None
|
ref = None
|
||||||
if name == 'funcdecl':
|
if name == Token.FUNC:
|
||||||
# TODO interpret funcdecl
|
name, args, body = stmt[1:]
|
||||||
raise ExtractorError('''Can't interpret statement called %s''' % name)
|
if name is not None:
|
||||||
|
if self._context_stack:
|
||||||
|
self.this[name] = Reference(self.build_function(args, body), (self.this, name))
|
||||||
|
else:
|
||||||
|
self.global_vars[name] = Reference(self.build_function(args, body), (self.this, name))
|
||||||
|
else:
|
||||||
|
raise ExtractorError('Function expression is not yet implemented')
|
||||||
elif name is Token.BLOCK:
|
elif name is Token.BLOCK:
|
||||||
block = stmt[1]
|
block = stmt[1]
|
||||||
for stmt in block:
|
for stmt in block:
|
||||||
@ -857,8 +935,8 @@ class JSInterpreter(object):
|
|||||||
ref = s.getvalue()
|
ref = s.getvalue()
|
||||||
elif name is Token.VAR:
|
elif name is Token.VAR:
|
||||||
for name, value in stmt[1]:
|
for name, value in stmt[1]:
|
||||||
self._context.local_vars[name] = Reference(self.interpret_expression(value).getvalue(),
|
self.this[name] = Reference(self.interpret_expression(value).getvalue(),
|
||||||
(self._context.local_vars, name))
|
(self.this, name))
|
||||||
elif name is Token.EXPR:
|
elif name is Token.EXPR:
|
||||||
for expr in stmt[1]:
|
for expr in stmt[1]:
|
||||||
ref = self.interpret_expression(expr)
|
ref = self.interpret_expression(expr)
|
||||||
@ -866,11 +944,6 @@ class JSInterpreter(object):
|
|||||||
# continue, break
|
# continue, break
|
||||||
elif name is Token.RETURN:
|
elif name is Token.RETURN:
|
||||||
ref = self.interpret_statement(stmt[1])
|
ref = self.interpret_statement(stmt[1])
|
||||||
ref = None if ref is None else ref.getvalue()
|
|
||||||
if isinstance(ref, list):
|
|
||||||
# TODO test nested arrays
|
|
||||||
ref = [elem.getvalue() for elem in ref]
|
|
||||||
|
|
||||||
self._context.ended = True
|
self._context.ended = True
|
||||||
# with
|
# with
|
||||||
# label
|
# label
|
||||||
@ -892,7 +965,6 @@ class JSInterpreter(object):
|
|||||||
if op is None:
|
if op is None:
|
||||||
ref = self.interpret_expression(left)
|
ref = self.interpret_expression(left)
|
||||||
else:
|
else:
|
||||||
# TODO handle undeclared variables (create propery)
|
|
||||||
try:
|
try:
|
||||||
leftref = self.interpret_expression(left)
|
leftref = self.interpret_expression(left)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@ -908,7 +980,7 @@ class JSInterpreter(object):
|
|||||||
u = Reference(self.undefined, (self.this, key))
|
u = Reference(self.undefined, (self.this, key))
|
||||||
leftref = self.this[key] = u
|
leftref = self.this[key] = u
|
||||||
else:
|
else:
|
||||||
raise ExtractorError('''Invalid left-hand side in assignment''')
|
raise ExtractorError('Invalid left-hand side in assignment')
|
||||||
leftvalue = leftref.getvalue()
|
leftvalue = leftref.getvalue()
|
||||||
rightvalue = self.interpret_expression(right).getvalue()
|
rightvalue = self.interpret_expression(right).getvalue()
|
||||||
leftref.putvalue(op(leftvalue, rightvalue))
|
leftref.putvalue(op(leftvalue, rightvalue))
|
||||||
@ -964,13 +1036,13 @@ class JSInterpreter(object):
|
|||||||
index = self.interpret_expression(tail_value).getvalue()
|
index = self.interpret_expression(tail_value).getvalue()
|
||||||
target = target.getvalue()[index]
|
target = target.getvalue()[index]
|
||||||
elif tail_name is Token.CALL:
|
elif tail_name is Token.CALL:
|
||||||
# TODO interpret call
|
args = (self.interpret_expression(arg).getvalue() for arg in tail_value)
|
||||||
raise ExtractorError('''Can't interpret expression called %s''' % tail_name)
|
target = Reference(target.getvalue()(*args))
|
||||||
ref = target
|
ref = target
|
||||||
|
|
||||||
elif name is Token.ID:
|
elif name is Token.ID:
|
||||||
# XXX error handling (unknown id)
|
# XXX error handling (unknown id)
|
||||||
ref = (self._context.local_vars[expr[1]] if expr[1] in self._context.local_vars else
|
ref = (self.this[expr[1]] if expr[1] in self.this else
|
||||||
self.global_vars[expr[1]])
|
self.global_vars[expr[1]])
|
||||||
|
|
||||||
# literal
|
# literal
|
||||||
@ -989,18 +1061,6 @@ class JSInterpreter(object):
|
|||||||
|
|
||||||
return ref
|
return ref
|
||||||
|
|
||||||
def run(self, cx=None):
|
|
||||||
if cx is not None:
|
|
||||||
self.push_context(cx)
|
|
||||||
res = None
|
|
||||||
for stmt in self.statements():
|
|
||||||
res = self.interpret_statement(stmt)
|
|
||||||
if self._context.ended:
|
|
||||||
if cx is not None:
|
|
||||||
self.pop_context()
|
|
||||||
break
|
|
||||||
return res
|
|
||||||
|
|
||||||
def extract_object(self, objname):
|
def extract_object(self, objname):
|
||||||
obj = {}
|
obj = {}
|
||||||
obj_m = re.search(
|
obj_m = re.search(
|
||||||
@ -1016,7 +1076,7 @@ class JSInterpreter(object):
|
|||||||
fields)
|
fields)
|
||||||
for f in fields_m:
|
for f in fields_m:
|
||||||
argnames = f.group('args').split(',')
|
argnames = f.group('args').split(',')
|
||||||
obj[f.group('key')] = self.build_function(argnames, f.group('code'))
|
obj[f.group('key')] = self.build_function(argnames, self.parse(f.group('code')))
|
||||||
|
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
@ -1032,7 +1092,7 @@ class JSInterpreter(object):
|
|||||||
raise ExtractorError('Could not find JS function %r' % funcname)
|
raise ExtractorError('Could not find JS function %r' % funcname)
|
||||||
argnames = func_m.group('args').split(',')
|
argnames = func_m.group('args').split(',')
|
||||||
|
|
||||||
return self.build_function(argnames, func_m.group('code'))
|
return self.build_function(argnames, self.parse(func_m.group('code')))
|
||||||
|
|
||||||
def push_context(self, cx):
|
def push_context(self, cx):
|
||||||
self._context_stack.append(self._context)
|
self._context_stack.append(self._context)
|
||||||
@ -1043,16 +1103,33 @@ class JSInterpreter(object):
|
|||||||
self._context = self._context_stack.pop()
|
self._context = self._context_stack.pop()
|
||||||
|
|
||||||
def call_function(self, funcname, *args):
|
def call_function(self, funcname, *args):
|
||||||
f = self.extract_function(funcname)
|
f = (self.this[funcname] if funcname in self.this else
|
||||||
return f(args)
|
self.global_vars[funcname] if funcname in self.global_vars else
|
||||||
|
self.extract_function(funcname))
|
||||||
|
return f(*args)
|
||||||
|
|
||||||
def build_function(self, argnames, code):
|
def build_function(self, argnames, ast):
|
||||||
def resf(args):
|
def resf(*args):
|
||||||
self.push_context(Context(dict(zip(argnames, args))))
|
self.push_context(Context(dict(zip(argnames, args))))
|
||||||
for stmt in self.statements(code):
|
res = None
|
||||||
|
for stmt in ast:
|
||||||
res = self.interpret_statement(stmt)
|
res = self.interpret_statement(stmt)
|
||||||
|
res = None if res is None else res.getvalue(deep=True)
|
||||||
if self._context.ended:
|
if self._context.ended:
|
||||||
self.pop_context()
|
self.pop_context()
|
||||||
break
|
break
|
||||||
return res
|
return res
|
||||||
return resf
|
return resf
|
||||||
|
|
||||||
|
def run(self, cx=None):
|
||||||
|
if cx is not None:
|
||||||
|
self.push_context(cx)
|
||||||
|
res = None
|
||||||
|
for stmt in self.parse():
|
||||||
|
res = self.interpret_statement(stmt)
|
||||||
|
res = None if res is None else res.getvalue(deep=True)
|
||||||
|
if self._context.ended:
|
||||||
|
if cx is not None:
|
||||||
|
self.pop_context()
|
||||||
|
break
|
||||||
|
return res
|
||||||
|
Loading…
x
Reference in New Issue
Block a user