30
30
from grumpy .compiler import util
31
31
32
32
33
- _NATIVE_MODULE_PREFIX = '__go__.'
34
33
_NATIVE_TYPE_PREFIX = 'type_'
35
34
36
35
# Partial list of known vcs for go module import
@@ -371,58 +370,39 @@ def visit_If(self, node):
371
370
372
371
def visit_Import (self , node ):
373
372
self ._write_py_context (node .lineno )
374
- for alias in node .names :
375
- if alias .name .startswith (_NATIVE_MODULE_PREFIX ):
376
- raise util .ParseError (
377
- node , 'for native imports use "from __go__.xyz import ..." syntax' )
378
- with self ._import (alias .name , 0 ) as mod :
379
- asname = alias .asname or alias .name .split ('.' )[0 ]
380
- self .block .bind_var (self .writer , asname , mod .expr )
373
+ for imp in util .ImportVisitor ().visit (node ):
374
+ self ._import_and_bind (imp )
381
375
382
376
def visit_ImportFrom (self , node ):
383
- # Wildcard imports are not yet supported.
384
- for alias in node .names :
385
- if alias .name == '*' :
386
- msg = 'wildcard member import is not implemented: from %s import %s' % (
387
- node .module , alias .name )
388
- raise util .ParseError (node , msg )
389
377
self ._write_py_context (node .lineno )
390
- if node .module .startswith (_NATIVE_MODULE_PREFIX ):
391
- values = [alias .name for alias in node .names ]
392
- with self ._import_native (node .module , values ) as mod :
393
- for alias in node .names :
394
- # Strip the 'type_' prefix when populating the module. This means
395
- # that, e.g. 'from __go__.foo import type_Bar' will populate foo with
396
- # a member called Bar, not type_Bar (although the symbol in the
397
- # importing module will still be type_Bar unless aliased). This bends
398
- # the semantics of import but makes native module contents more
399
- # sensible.
400
- name = alias .name
401
- if name .startswith (_NATIVE_TYPE_PREFIX ):
402
- name = name [len (_NATIVE_TYPE_PREFIX ):]
403
- with self .block .alloc_temp () as member :
404
- self .writer .write_checked_call2 (
405
- member , 'πg.GetAttr(πF, {}, {}, nil)' ,
406
- mod .expr , self .block .root .intern (name ))
407
- self .block .bind_var (
408
- self .writer , alias .asname or alias .name , member .expr )
409
- elif node .module == '__future__' :
410
- # At this stage all future imports are done in an initial pass (see
411
- # visit() above), so if they are encountered here after the last valid
412
- # __future__ then it's a syntax error.
413
- if node .lineno > self .future_features .future_lineno :
414
- raise util .ParseError (node , late_future )
415
- else :
416
- # NOTE: Assume that the names being imported are all modules within a
417
- # package. E.g. "from a.b import c" is importing the module c from package
418
- # a.b, not some member of module b. We cannot distinguish between these
419
- # two cases at compile time and the Google style guide forbids the latter
420
- # so we support that use case only.
421
- for alias in node .names :
422
- name = '{}.{}' .format (node .module , alias .name )
423
- with self ._import (name , name .count ('.' )) as mod :
424
- asname = alias .asname or alias .name
425
- self .block .bind_var (self .writer , asname , mod .expr )
378
+ for imp in util .ImportVisitor ().visit (node ):
379
+ if imp .is_native :
380
+ values = [b .value for b in imp .bindings ]
381
+ with self ._import_native (imp .name , values ) as mod :
382
+ for binding in imp .bindings :
383
+ # Strip the 'type_' prefix when populating the module. This means
384
+ # that, e.g. 'from __go__.foo import type_Bar' will populate foo
385
+ # with a member called Bar, not type_Bar (although the symbol in
386
+ # the importing module will still be type_Bar unless aliased). This
387
+ # bends the semantics of import but makes native module contents
388
+ # more sensible.
389
+ name = binding .value
390
+ if name .startswith (_NATIVE_TYPE_PREFIX ):
391
+ name = name [len (_NATIVE_TYPE_PREFIX ):]
392
+ with self .block .alloc_temp () as member :
393
+ self .writer .write_checked_call2 (
394
+ member , 'πg.GetAttr(πF, {}, {}, nil)' ,
395
+ mod .expr , self .block .root .intern (name ))
396
+ self .block .bind_var (
397
+ self .writer , binding .alias , member .expr )
398
+ elif node .module == '__future__' :
399
+ # At this stage all future imports are done in an initial pass (see
400
+ # visit() above), so if they are encountered here after the last valid
401
+ # __future__ then it's a syntax error.
402
+ if node .lineno > self .future_features .future_lineno :
403
+ raise util .ImportError (node , late_future )
404
+ else :
405
+ self ._import_and_bind (imp )
426
406
427
407
def visit_Module (self , node ):
428
408
self ._visit_each (node .body )
@@ -681,18 +661,14 @@ def _build_assign_target(self, target, assigns):
681
661
tmpl = 'πg.TieTarget{Target: &$temp}'
682
662
return string .Template (tmpl ).substitute (temp = temp .name )
683
663
684
- def _import (self , name , index ):
685
- """Returns an expression for a Module object returned from ImportModule .
664
+ def _import_and_bind (self , imp ):
665
+ """Generates code that imports a module and binds it to a variable .
686
666
687
667
Args:
688
- name: The fully qualified Python module name, e.g. foo.bar.
689
- index: The element in the list of modules that this expression should
690
- select. E.g. for 'foo.bar', 0 corresponds to the package foo and 1
691
- corresponds to the module bar.
692
- Returns:
693
- A Go expression evaluating to an *Object (upcast from a *Module.)
668
+ imp: Import object representing an import of the form "import x.y.z" or
669
+ "from x.y import z". Expects only a single binding.
694
670
"""
695
- parts = name .split ('.' )
671
+ parts = imp . name .split ('.' )
696
672
code_objs = []
697
673
for i in xrange (len (parts )):
698
674
package_name = '/' .join (parts [:i + 1 ])
@@ -701,27 +677,33 @@ def _import(self, name, index):
701
677
code_objs .append ('{}.Code' .format (package .alias ))
702
678
else :
703
679
code_objs .append ('Code' )
704
- mod = self .block .alloc_temp ()
705
- with self .block .alloc_temp ('[]*πg.Object' ) as mod_slice :
680
+ with self .block .alloc_temp () as mod , \
681
+ self .block .alloc_temp ('[]*πg.Object' ) as mod_slice :
706
682
handles_expr = '[]*πg.Code{' + ', ' .join (code_objs ) + '}'
707
683
self .writer .write_checked_call2 (
708
684
mod_slice , 'πg.ImportModule(πF, {}, {})' ,
709
- util .go_str (name ), handles_expr )
685
+ util .go_str (imp .name ), handles_expr )
686
+ # This method only handles simple module imports (i.e. not member
687
+ # imports) which always have a single binding.
688
+ binding = imp .bindings [0 ]
689
+ if binding .value == util .Import .ROOT :
690
+ index = 0
691
+ else :
692
+ index = len (parts ) - 1
710
693
self .writer .write ('{} = {}[{}]' .format (mod .name , mod_slice .expr , index ))
711
- return mod
694
+ self . block . bind_var ( self . writer , binding . alias , mod . expr )
712
695
713
696
def _import_native (self , name , values ):
714
697
reflect_package = self .block .root .add_native_import ('reflect' )
715
- import_name = name [len (_NATIVE_MODULE_PREFIX ):]
716
698
# Work-around for importing go module from VCS
717
699
# TODO: support bzr|git|hg|svn from any server
718
700
package_name = None
719
701
for x in _KNOWN_VCS :
720
- if import_name .startswith (x ):
721
- package_name = x + import_name [len (x ):].replace ('.' , '/' )
702
+ if name .startswith (x ):
703
+ package_name = x + name [len (x ):].replace ('.' , '/' )
722
704
break
723
705
if not package_name :
724
- package_name = import_name .replace ('.' , '/' )
706
+ package_name = name .replace ('.' , '/' )
725
707
726
708
package = self .block .root .add_native_import (package_name )
727
709
mod = self .block .alloc_temp ()
0 commit comments