Skip to content

Commit 6c151b7

Browse files
committed
compile: import/from import
1 parent 8072a76 commit 6c151b7

File tree

3 files changed

+273
-2
lines changed

3 files changed

+273
-2
lines changed

compile/compile.go

+92-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
// compile python code
22
package compile
33

4+
// FIXME kill ast.Identifier and turn into string?
5+
46
import (
57
"fmt"
8+
"strings"
69

710
"github.com/ncw/gpython/ast"
811
"github.com/ncw/gpython/parser"
@@ -307,6 +310,13 @@ func (c *compiler) Name(Id ast.Identifier) uint32 {
307310
return c.Index(string(Id), &c.Code.Names)
308311
}
309312

313+
// Adds this opcode with mangled name as an argument
314+
func (c *compiler) OpName(opcode byte, name ast.Identifier) {
315+
// FIXME mangled := _Py_Mangle(c->u->u_private, o);
316+
mangled := name
317+
c.OpArg(opcode, c.Name(mangled))
318+
}
319+
310320
// Compiles an instruction with an argument
311321
func (c *compiler) OpArg(Op byte, Arg uint32) {
312322
if !vm.HAS_ARG(Op) {
@@ -812,6 +822,86 @@ func (c *compiler) try(node *ast.Try) {
812822
}
813823
}
814824

825+
/* The IMPORT_NAME opcode was already generated. This function
826+
merely needs to bind the result to a name.
827+
828+
If there is a dot in name, we need to split it and emit a
829+
LOAD_ATTR for each name.
830+
*/
831+
func (c *compiler) importAs(name ast.Identifier, asname ast.Identifier) {
832+
attrs := strings.Split(string(name), ".")
833+
if len(attrs) > 1 {
834+
for _, attr := range attrs[1:] {
835+
c.OpArg(vm.LOAD_ATTR, c.Name(ast.Identifier(attr)))
836+
}
837+
}
838+
c.NameOp(string(asname), ast.Store)
839+
}
840+
841+
/* The Import node stores a module name like a.b.c as a single
842+
string. This is convenient for all cases except
843+
import a.b.c as d
844+
where we need to parse that string to extract the individual
845+
module names.
846+
XXX Perhaps change the representation to make this case simpler?
847+
*/
848+
func (c *compiler) import_(node *ast.Import) {
849+
//n = asdl_seq_LEN(s.v.Import.names);
850+
851+
for _, alias := range node.Names {
852+
c.LoadConst(py.Int(0))
853+
c.LoadConst(py.None)
854+
c.OpName(vm.IMPORT_NAME, alias.Name)
855+
856+
if alias.AsName != "" {
857+
c.importAs(alias.Name, alias.AsName)
858+
} else {
859+
tmp := alias.Name
860+
dot := strings.IndexByte(string(alias.Name), '.')
861+
if dot >= 0 {
862+
tmp = alias.Name[:dot]
863+
}
864+
c.NameOp(string(tmp), ast.Store)
865+
}
866+
}
867+
}
868+
869+
func (c *compiler) importFrom(node *ast.ImportFrom) {
870+
names := make(py.Tuple, len(node.Names))
871+
872+
/* build up the names */
873+
for i, alias := range node.Names {
874+
names[i] = py.String(alias.Name)
875+
}
876+
877+
// FIXME if s.lineno > c.c_future.ff_lineno && s.v.ImportFrom.module && !PyUnicode_CompareWithASCIIString(s.v.ImportFrom.module, "__future__") {
878+
// return compiler_error(c, "from __future__ imports must occur at the beginning of the file")
879+
// }
880+
881+
c.LoadConst(py.Int(node.Level))
882+
c.LoadConst(names)
883+
c.OpName(vm.IMPORT_NAME, node.Module)
884+
for i, alias := range node.Names {
885+
if i == 0 && alias.Name[0] == '*' {
886+
if len(alias.Name) != 1 {
887+
panic("can only import *")
888+
}
889+
c.Op(vm.IMPORT_STAR)
890+
return
891+
}
892+
893+
c.OpName(vm.IMPORT_FROM, alias.Name)
894+
store_name := alias.Name
895+
if alias.AsName != "" {
896+
store_name = alias.AsName
897+
}
898+
899+
c.NameOp(string(store_name), ast.Store)
900+
}
901+
/* remove imported module */
902+
c.Op(vm.POP_TOP)
903+
}
904+
815905
// Compile statements
816906
func (c *compiler) Stmts(stmts []ast.Stmt) {
817907
for _, stmt := range stmts {
@@ -1000,12 +1090,12 @@ func (c *compiler) Stmt(stmt ast.Stmt) {
10001090
c.Label(label)
10011091
case *ast.Import:
10021092
// Names []*Alias
1003-
panic("FIXME compile: Import not implemented")
1093+
c.import_(node)
10041094
case *ast.ImportFrom:
10051095
// Module Identifier
10061096
// Names []*Alias
10071097
// Level int
1008-
panic("FIXME compile: ImportFrom not implemented")
1098+
c.importFrom(node)
10091099
case *ast.Global:
10101100
// Names []Identifier
10111101
// Implemented by symtable

compile/compile_data_test.go

+170
Original file line numberDiff line numberDiff line change
@@ -3552,4 +3552,174 @@ var compileTestData = []struct {
35523552
Firstlineno: 1,
35533553
Lnotab: "\x06\x01\x0b\x01\x12\x01\x21\x02",
35543554
}, nil, ""},
3555+
{"import mod", "exec", &py.Code{
3556+
Argcount: 0,
3557+
Kwonlyargcount: 0,
3558+
Nlocals: 0,
3559+
Stacksize: 2,
3560+
Flags: 64,
3561+
Code: "\x64\x00\x00\x64\x01\x00\x6c\x00\x00\x5a\x00\x00\x64\x01\x00\x53",
3562+
Consts: []py.Object{py.Int(0), py.None},
3563+
Names: []string{"mod"},
3564+
Varnames: []string{},
3565+
Freevars: []string{},
3566+
Cellvars: []string{},
3567+
Filename: "<string>",
3568+
Name: "<module>",
3569+
Firstlineno: 1,
3570+
Lnotab: "",
3571+
}, nil, ""},
3572+
{"import mod1, mod2, mod3", "exec", &py.Code{
3573+
Argcount: 0,
3574+
Kwonlyargcount: 0,
3575+
Nlocals: 0,
3576+
Stacksize: 2,
3577+
Flags: 64,
3578+
Code: "\x64\x00\x00\x64\x01\x00\x6c\x00\x00\x5a\x00\x00\x64\x00\x00\x64\x01\x00\x6c\x01\x00\x5a\x01\x00\x64\x00\x00\x64\x01\x00\x6c\x02\x00\x5a\x02\x00\x64\x01\x00\x53",
3579+
Consts: []py.Object{py.Int(0), py.None},
3580+
Names: []string{"mod1", "mod2", "mod3"},
3581+
Varnames: []string{},
3582+
Freevars: []string{},
3583+
Cellvars: []string{},
3584+
Filename: "<string>",
3585+
Name: "<module>",
3586+
Firstlineno: 1,
3587+
Lnotab: "",
3588+
}, nil, ""},
3589+
{"import mod as pod, mod2 as pod2", "exec", &py.Code{
3590+
Argcount: 0,
3591+
Kwonlyargcount: 0,
3592+
Nlocals: 0,
3593+
Stacksize: 2,
3594+
Flags: 64,
3595+
Code: "\x64\x00\x00\x64\x01\x00\x6c\x00\x00\x5a\x01\x00\x64\x00\x00\x64\x01\x00\x6c\x02\x00\x5a\x03\x00\x64\x01\x00\x53",
3596+
Consts: []py.Object{py.Int(0), py.None},
3597+
Names: []string{"mod", "pod", "mod2", "pod2"},
3598+
Varnames: []string{},
3599+
Freevars: []string{},
3600+
Cellvars: []string{},
3601+
Filename: "<string>",
3602+
Name: "<module>",
3603+
Firstlineno: 1,
3604+
Lnotab: "",
3605+
}, nil, ""},
3606+
{"import mod1.mod2", "exec", &py.Code{
3607+
Argcount: 0,
3608+
Kwonlyargcount: 0,
3609+
Nlocals: 0,
3610+
Stacksize: 2,
3611+
Flags: 64,
3612+
Code: "\x64\x00\x00\x64\x01\x00\x6c\x00\x00\x5a\x01\x00\x64\x01\x00\x53",
3613+
Consts: []py.Object{py.Int(0), py.None},
3614+
Names: []string{"mod1.mod2", "mod1"},
3615+
Varnames: []string{},
3616+
Freevars: []string{},
3617+
Cellvars: []string{},
3618+
Filename: "<string>",
3619+
Name: "<module>",
3620+
Firstlineno: 1,
3621+
Lnotab: "",
3622+
}, nil, ""},
3623+
{"import mod1.mod2.mod3", "exec", &py.Code{
3624+
Argcount: 0,
3625+
Kwonlyargcount: 0,
3626+
Nlocals: 0,
3627+
Stacksize: 2,
3628+
Flags: 64,
3629+
Code: "\x64\x00\x00\x64\x01\x00\x6c\x00\x00\x5a\x01\x00\x64\x01\x00\x53",
3630+
Consts: []py.Object{py.Int(0), py.None},
3631+
Names: []string{"mod1.mod2.mod3", "mod1"},
3632+
Varnames: []string{},
3633+
Freevars: []string{},
3634+
Cellvars: []string{},
3635+
Filename: "<string>",
3636+
Name: "<module>",
3637+
Firstlineno: 1,
3638+
Lnotab: "",
3639+
}, nil, ""},
3640+
{"import mod1.mod2.mod3.mod4", "exec", &py.Code{
3641+
Argcount: 0,
3642+
Kwonlyargcount: 0,
3643+
Nlocals: 0,
3644+
Stacksize: 2,
3645+
Flags: 64,
3646+
Code: "\x64\x00\x00\x64\x01\x00\x6c\x00\x00\x5a\x01\x00\x64\x01\x00\x53",
3647+
Consts: []py.Object{py.Int(0), py.None},
3648+
Names: []string{"mod1.mod2.mod3.mod4", "mod1"},
3649+
Varnames: []string{},
3650+
Freevars: []string{},
3651+
Cellvars: []string{},
3652+
Filename: "<string>",
3653+
Name: "<module>",
3654+
Firstlineno: 1,
3655+
Lnotab: "",
3656+
}, nil, ""},
3657+
{"import mod1.mod2.mod3.mod4 as potato", "exec", &py.Code{
3658+
Argcount: 0,
3659+
Kwonlyargcount: 0,
3660+
Nlocals: 0,
3661+
Stacksize: 2,
3662+
Flags: 64,
3663+
Code: "\x64\x00\x00\x64\x01\x00\x6c\x00\x00\x6a\x01\x00\x6a\x02\x00\x6a\x03\x00\x5a\x04\x00\x64\x01\x00\x53",
3664+
Consts: []py.Object{py.Int(0), py.None},
3665+
Names: []string{"mod1.mod2.mod3.mod4", "mod2", "mod3", "mod4", "potato"},
3666+
Varnames: []string{},
3667+
Freevars: []string{},
3668+
Cellvars: []string{},
3669+
Filename: "<string>",
3670+
Name: "<module>",
3671+
Firstlineno: 1,
3672+
Lnotab: "",
3673+
}, nil, ""},
3674+
{"from mod import a", "exec", &py.Code{
3675+
Argcount: 0,
3676+
Kwonlyargcount: 0,
3677+
Nlocals: 0,
3678+
Stacksize: 2,
3679+
Flags: 64,
3680+
Code: "\x64\x00\x00\x64\x01\x00\x6c\x00\x00\x6d\x01\x00\x5a\x01\x00\x01\x64\x02\x00\x53",
3681+
Consts: []py.Object{py.Int(0), py.Tuple{py.String("a")}, py.None},
3682+
Names: []string{"mod", "a"},
3683+
Varnames: []string{},
3684+
Freevars: []string{},
3685+
Cellvars: []string{},
3686+
Filename: "<string>",
3687+
Name: "<module>",
3688+
Firstlineno: 1,
3689+
Lnotab: "",
3690+
}, nil, ""},
3691+
{"from mod1.mod2.mod3 import *", "exec", &py.Code{
3692+
Argcount: 0,
3693+
Kwonlyargcount: 0,
3694+
Nlocals: 0,
3695+
Stacksize: 2,
3696+
Flags: 64,
3697+
Code: "\x64\x00\x00\x64\x01\x00\x6c\x00\x00\x54\x64\x02\x00\x53",
3698+
Consts: []py.Object{py.Int(0), py.Tuple{py.String("*")}, py.None},
3699+
Names: []string{"mod1.mod2.mod3"},
3700+
Varnames: []string{},
3701+
Freevars: []string{},
3702+
Cellvars: []string{},
3703+
Filename: "<string>",
3704+
Name: "<module>",
3705+
Firstlineno: 1,
3706+
Lnotab: "",
3707+
}, nil, ""},
3708+
{"from mod1.mod2.mod3 import a as aa, b as bb, c", "exec", &py.Code{
3709+
Argcount: 0,
3710+
Kwonlyargcount: 0,
3711+
Nlocals: 0,
3712+
Stacksize: 2,
3713+
Flags: 64,
3714+
Code: "\x64\x00\x00\x64\x01\x00\x6c\x00\x00\x6d\x01\x00\x5a\x02\x00\x6d\x03\x00\x5a\x04\x00\x6d\x05\x00\x5a\x05\x00\x01\x64\x02\x00\x53",
3715+
Consts: []py.Object{py.Int(0), py.Tuple{py.String("a"), py.String("b"), py.String("c")}, py.None},
3716+
Names: []string{"mod1.mod2.mod3", "a", "aa", "b", "bb", "c"},
3717+
Varnames: []string{},
3718+
Freevars: []string{},
3719+
Cellvars: []string{},
3720+
Filename: "<string>",
3721+
Name: "<module>",
3722+
Firstlineno: 1,
3723+
Lnotab: "",
3724+
}, nil, ""},
35553725
}

compile/make_compile_test.py

+11
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,17 @@ def method(self, c):
333333
finally:
334334
j()
335335
''', "exec"),
336+
# import / from import
337+
('''import mod''', "exec"),
338+
('''import mod1, mod2, mod3''', "exec"),
339+
('''import mod as pod, mod2 as pod2''', "exec"),
340+
('''import mod1.mod2''', "exec"),
341+
('''import mod1.mod2.mod3''', "exec"),
342+
('''import mod1.mod2.mod3.mod4''', "exec"),
343+
('''import mod1.mod2.mod3.mod4 as potato''', "exec"),
344+
('''from mod import a''', "exec"),
345+
('''from mod1.mod2.mod3 import *''', "exec"),
346+
('''from mod1.mod2.mod3 import a as aa, b as bb, c''', "exec"),
336347

337348
]
338349

0 commit comments

Comments
 (0)