Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit fa0cf4f

Browse files
committed
Add support for absolute/relative imports and if/else expressions:
- regenerate ast.py - add future flags for absolute-import and with-statement so they (hopefully) properly get set in code-object flags - try out if/else expressions in actual code for the hell of it. Seems to generate the same kind of bytecode as the normal compiler.
1 parent 7e2ac25 commit fa0cf4f

5 files changed

Lines changed: 82 additions & 19 deletions

File tree

Lib/compiler/ast.py

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -524,19 +524,20 @@ def __repr__(self):
524524
return "For(%s, %s, %s, %s)" % (repr(self.assign), repr(self.list), repr(self.body), repr(self.else_))
525525

526526
class From(Node):
527-
def __init__(self, modname, names, lineno=None):
527+
def __init__(self, modname, names, level, lineno=None):
528528
self.modname = modname
529529
self.names = names
530+
self.level = level
530531
self.lineno = lineno
531532

532533
def getChildren(self):
533-
return self.modname, self.names
534+
return self.modname, self.names, self.level
534535

535536
def getChildNodes(self):
536537
return ()
537538

538539
def __repr__(self):
539-
return "From(%s, %s)" % (repr(self.modname), repr(self.names))
540+
return "From(%s, %s, %s)" % (repr(self.modname), repr(self.names), repr(self.level))
540541

541542
class Function(Node):
542543
def __init__(self, decorators, name, argnames, defaults, flags, doc, code, lineno=None):
@@ -553,7 +554,7 @@ def __init__(self, decorators, name, argnames, defaults, flags, doc, code, linen
553554
self.varargs = 1
554555
if flags & CO_VARKEYWORDS:
555556
self.kwargs = 1
556-
557+
557558

558559

559560
def getChildren(self):
@@ -584,7 +585,7 @@ def __init__(self, code, lineno=None):
584585
self.lineno = lineno
585586
self.argnames = ['[outmost-iterable]']
586587
self.varargs = self.kwargs = None
587-
588+
588589

589590

590591
def getChildren(self):
@@ -708,6 +709,22 @@ def getChildNodes(self):
708709
def __repr__(self):
709710
return "If(%s, %s)" % (repr(self.tests), repr(self.else_))
710711

712+
class IfExp(Node):
713+
def __init__(self, test, then, else_, lineno=None):
714+
self.test = test
715+
self.then = then
716+
self.else_ = else_
717+
self.lineno = lineno
718+
719+
def getChildren(self):
720+
return self.test, self.then, self.else_
721+
722+
def getChildNodes(self):
723+
return self.test, self.then, self.else_
724+
725+
def __repr__(self):
726+
return "IfExp(%s, %s, %s)" % (repr(self.test), repr(self.then), repr(self.else_))
727+
711728
class Import(Node):
712729
def __init__(self, names, lineno=None):
713730
self.names = names
@@ -763,7 +780,7 @@ def __init__(self, argnames, defaults, flags, code, lineno=None):
763780
self.varargs = 1
764781
if flags & CO_VARKEYWORDS:
765782
self.kwargs = 1
766-
783+
767784

768785

769786
def getChildren(self):

Lib/compiler/consts.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,5 @@
1717
CO_GENERATOR = 0x0020
1818
CO_GENERATOR_ALLOWED = 0x1000
1919
CO_FUTURE_DIVISION = 0x2000
20+
CO_FUTURE_ABSIMPORT = 0x4000
21+
CO_FUTURE_WITH_STATEMENT = 0x8000

Lib/compiler/pyassem.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -771,7 +771,7 @@ def findDepth(self, insts, debug=0):
771771
'COMPARE_OP': -1,
772772
'STORE_FAST': -1,
773773
'IMPORT_STAR': -1,
774-
'IMPORT_NAME': 0,
774+
'IMPORT_NAME': -1,
775775
'IMPORT_FROM': 1,
776776
'LOAD_ATTR': 0, # unlike other loads
777777
# close enough...

Lib/compiler/pycodegen.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@
88
from compiler import ast, parse, walk, syntax
99
from compiler import pyassem, misc, future, symbols
1010
from compiler.consts import SC_LOCAL, SC_GLOBAL, SC_FREE, SC_CELL
11-
from compiler.consts import CO_VARARGS, CO_VARKEYWORDS, CO_NEWLOCALS,\
12-
CO_NESTED, CO_GENERATOR, CO_GENERATOR_ALLOWED, CO_FUTURE_DIVISION
11+
from compiler.consts import (CO_VARARGS, CO_VARKEYWORDS, CO_NEWLOCALS,
12+
CO_NESTED, CO_GENERATOR, CO_GENERATOR_ALLOWED, CO_FUTURE_DIVISION,
13+
CO_FUTURE_ABSIMPORT, CO_FUTURE_WITH_STATEMENT)
1314
from compiler.pyassem import TupleArg
1415

1516
# XXX The version-specific code can go, since this code only works with 2.x.
@@ -215,6 +216,10 @@ def __init__(self):
215216
self._div_op = "BINARY_TRUE_DIVIDE"
216217
elif feature == "generators":
217218
self.graph.setFlag(CO_GENERATOR_ALLOWED)
219+
elif feature == "absolute_import":
220+
self.graph.setFlag(CO_FUTURE_ABSIMPORT)
221+
elif feature == "with_statement":
222+
self.graph.setFlag(CO_FUTURE_WITH_STATEMENT)
218223

219224
def initClass(self):
220225
"""This method is called once for each class"""
@@ -543,6 +548,19 @@ def visitAnd(self, node):
543548
def visitOr(self, node):
544549
self.visitTest(node, 'JUMP_IF_TRUE')
545550

551+
def visitIfExp(self, node):
552+
endblock = self.newBlock()
553+
elseblock = self.newBlock()
554+
self.visit(node.test)
555+
self.emit('JUMP_IF_FALSE', elseblock)
556+
self.emit('POP_TOP')
557+
self.visit(node.then)
558+
self.emit('JUMP_FORWARD', endblock)
559+
self.nextBlock(elseblock)
560+
self.emit('POP_TOP')
561+
self.visit(node.else_)
562+
self.nextBlock(endblock)
563+
546564
def visitCompare(self, node):
547565
self.visit(node.expr)
548566
cleanup = self.newBlock()
@@ -875,8 +893,10 @@ def visitPass(self, node):
875893

876894
def visitImport(self, node):
877895
self.set_lineno(node)
896+
level = 0 if "absolute_import" in self.futures else -1
878897
for name, alias in node.names:
879898
if VERSION > 1:
899+
self.emit('LOAD_CONST', level)
880900
self.emit('LOAD_CONST', None)
881901
self.emit('IMPORT_NAME', name)
882902
mod = name.split(".")[0]
@@ -888,8 +908,12 @@ def visitImport(self, node):
888908

889909
def visitFrom(self, node):
890910
self.set_lineno(node)
911+
level = node.level
912+
if level == 0 and "absolute_import" not in self.futures:
913+
level = -1
891914
fromlist = map(lambda (name, alias): name, node.names)
892915
if VERSION > 1:
916+
self.emit('LOAD_CONST', level)
893917
self.emit('LOAD_CONST', tuple(fromlist))
894918
self.emit('IMPORT_NAME', node.modname)
895919
for name, alias in node.names:

Lib/compiler/transformer.py

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -441,18 +441,25 @@ def import_name(self, nodelist):
441441
lineno=nodelist[0][2])
442442

443443
def import_from(self, nodelist):
444-
# import_from: 'from' dotted_name 'import' ('*' |
444+
# import_from: 'from' ('.'* dotted_name | '.') 'import' ('*' |
445445
# '(' import_as_names ')' | import_as_names)
446446
assert nodelist[0][1] == 'from'
447-
assert nodelist[1][0] == symbol.dotted_name
448-
assert nodelist[2][1] == 'import'
449-
fromname = self.com_dotted_name(nodelist[1])
450-
if nodelist[3][0] == token.STAR:
451-
return From(fromname, [('*', None)],
447+
idx = 1
448+
while nodelist[idx][1] == '.':
449+
idx += 1
450+
level = idx - 1
451+
if nodelist[idx][0] == symbol.dotted_name:
452+
fromname = self.com_dotted_name(nodelist[idx])
453+
idx += 1
454+
else:
455+
fromname = ""
456+
assert nodelist[idx][1] == 'import'
457+
if nodelist[idx + 1][0] == token.STAR:
458+
return From(fromname, [('*', None)], level,
452459
lineno=nodelist[0][2])
453460
else:
454-
node = nodelist[3 + (nodelist[3][0] == token.LPAR)]
455-
return From(fromname, self.com_import_as_names(node),
461+
node = nodelist[idx + 1 + (nodelist[idx + 1][0] == token.LPAR)]
462+
return From(fromname, self.com_import_as_names(node), level,
456463
lineno=nodelist[0][2])
457464

458465
def global_stmt(self, nodelist):
@@ -575,12 +582,25 @@ def testlist_gexp(self, nodelist):
575582
return self.testlist(nodelist)
576583

577584
def test(self, nodelist):
585+
# or_test ['if' or_test 'else' test] | lambdef
586+
if len(nodelist) == 1 and nodelist[0][0] == symbol.lambdef:
587+
return self.lambdef(nodelist[0])
588+
then = self.com_node(nodelist[0])
589+
if len(nodelist) > 1:
590+
assert len(nodelist) == 5
591+
assert nodelist[1][1] == 'if'
592+
assert nodelist[3][1] == 'else'
593+
test = self.com_node(nodelist[2])
594+
else_ = self.com_node(nodelist[4])
595+
return IfExp(test, then, else_, lineno=nodelist[1][2])
596+
return then
597+
598+
def or_test(self, nodelist):
578599
# and_test ('or' and_test)* | lambdef
579600
if len(nodelist) == 1 and nodelist[0][0] == symbol.lambdef:
580601
return self.lambdef(nodelist[0])
581602
return self.com_binary(Or, nodelist)
582-
or_test = test
583-
old_test = test
603+
old_test = or_test
584604

585605
def and_test(self, nodelist):
586606
# not_test ('and' not_test)*

0 commit comments

Comments
 (0)