From 8ae7e22f2e42775a0f661554ed6e4b4a7b55741e Mon Sep 17 00:00:00 2001 From: rocky Date: Mon, 18 Apr 2016 05:14:47 -0400 Subject: [PATCH] Add simgle-mode compilation --- pytest/test_single_compile.py | 1 - uncompyle6/parser.py | 30 ++++++++++++++++++++++++++++-- uncompyle6/parsers/parse2.py | 17 ++++++++--------- uncompyle6/parsers/parse3.py | 15 +++++++++------ 4 files changed, 45 insertions(+), 18 deletions(-) diff --git a/pytest/test_single_compile.py b/pytest/test_single_compile.py index ac55c0fc..1f7f2150 100644 --- a/pytest/test_single_compile.py +++ b/pytest/test_single_compile.py @@ -1,7 +1,6 @@ import pytest from uncompyle6 import PYTHON_VERSION, PYTHON3, deparse_code -@pytest.mark.skip(reason="Reinstate when we have compiilation single") def test_single_mode(): single_expressions = ( 'i = 1', diff --git a/uncompyle6/parser.py b/uncompyle6/parser.py index b1376c83..00044e2b 100644 --- a/uncompyle6/parser.py +++ b/uncompyle6/parser.py @@ -69,6 +69,25 @@ class PythonParser(GenericASTBuilder): # print >> sys.stderr, 'resolve', str(list) return GenericASTBuilder.resolve(self, list) + ############################################## + ## Common Python 2 and Python 3 grammar rules + ############################################## + def p_start(self, args): + ''' + # The start or goal symbol + stmts ::= stmts sstmt + stmts ::= sstmt + ''' + + def p_call_stmt(self, args): + ''' + # eval-mode compilation. Single-mode interactive compilation + # adds another rule. + call_stmt ::= expr POP_TOP + ''' + + + def parse(p, tokens, customize): p.add_custom_rules(tokens, customize) ast = p.parse(tokens) @@ -84,12 +103,19 @@ def get_python_parser(version, debug_parser, compile_mode='exec'): https://docs.python.org/3.6/library/functions.html#compile for an explanation of the different modes. """ + if version < 3.0: import uncompyle6.parsers.parse2 as parse2 - p = parse2.Python2Parser(debug_parser) + if compile_mode == 'exec': + p = parse2.Python2Parser(debug_parser) + else: + p = parse2.Python2ParserSingle(debug_parser) else: import uncompyle6.parsers.parse3 as parse3 - p = parse3.Python3Parser(debug_parser) + if compile_mode == 'exec': + p = parse3.Python3Parser(debug_parser) + else: + p = parse3.Python3ParserSingle(debug_parser) p.version = version return p diff --git a/uncompyle6/parsers/parse2.py b/uncompyle6/parsers/parse2.py index bb16ea79..c8698297 100644 --- a/uncompyle6/parsers/parse2.py +++ b/uncompyle6/parsers/parse2.py @@ -209,12 +209,6 @@ class Python2Parser(PythonParser): load_attrs ::= load_attrs LOAD_ATTR ''' - def p_start(self, args): - ''' - stmts ::= stmts sstmt - stmts ::= sstmt - ''' - def p_grammar(self, args): ''' sstmt ::= stmt @@ -716,6 +710,11 @@ class Python2Parser(PythonParser): self.addRule(rule, nop_func) class Python2ParserSingle(Python2Parser): - # Add: - # call_stmt ::= expr PRINT_EXPR - pass + def p_call_stmt(self, args): + ''' + # single-mode compilation. eval-mode interactive compilation + # drops the last rule. + + call_stmt ::= expr POP_TOP + call_stmt ::= expr PRINT_EXPR + ''' diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index 6e0fb194..07234fbd 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -228,8 +228,7 @@ class Python3Parser(PythonParser): ''' def p_grammar(self, args): - '''stmts ::= stmts sstmt - stmts ::= sstmt + ''' sstmt ::= stmt sstmt ::= ifelsestmtr sstmt ::= return_stmt RETURN_LAST @@ -301,7 +300,6 @@ class Python3Parser(PythonParser): stmt ::= classdef stmt ::= call_stmt - call_stmt ::= expr POP_TOP stmt ::= return_stmt return_stmt ::= ret_expr RETURN_VALUE @@ -820,6 +818,11 @@ class Python3Parser(PythonParser): return class Python3ParserSingle(Python3Parser): - # Add: - # call_stmt ::= expr PRINT_EXPR - pass + def p_call_stmt(self, args): + ''' + # single-mode compilation. Eval-mode interactive compilation + # drops the last rule. + + call_stmt ::= expr POP_TOP + call_stmt ::= expr PRINT_EXPR + '''