Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrite load statement #312

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
on: [pull_request]
name: Test
jobs:
test:
strategy:
matrix:
go-version: [1.14.x]
platform: [ubuntu-latest]
runs-on: ${{ matrix.platform }}
steps:
- name: Install Go
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go-version }}
- name: Checkout code
uses: actions/checkout@v2
- name: Run all tests
run: make test
20 changes: 0 additions & 20 deletions .travis.yml

This file was deleted.

3 changes: 3 additions & 0 deletions .vscode/numbered-bookmarks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"bookmarks": []
}
18 changes: 11 additions & 7 deletions internal/compile/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -1207,20 +1207,24 @@ func (fcomp *fcomp) stmt(stmt syntax.Stmt) {
fcomp.block = fcomp.newBlock() // dead code

case *syntax.LoadStmt:
for i := range stmt.From {
fcomp.string(stmt.From[i].Name)
}
// TODO: maxmcd
// for i := range stmt.From {
// fcomp.string(stmt.From[i].Name)
// }
fcomp.string(stmt.Alias.Name)
module := stmt.Module.Value.(string)
fcomp.pcomp.prog.Loads = append(fcomp.pcomp.prog.Loads, Binding{
Name: module,
Pos: stmt.Module.TokenPos,
})
fcomp.string(module)
fcomp.setPos(stmt.Load)
fcomp.emit1(LOAD, uint32(len(stmt.From)))
for i := range stmt.To {
fcomp.set(stmt.To[len(stmt.To)-1-i])
}
fcomp.emit1(LOAD, uint32(0))
fcomp.set(stmt.Alias)
// fcomp.emit1(LOAD, uint32(len(stmt.From)))
// for i := range stmt.To {
// fcomp.set(stmt.To[len(stmt.To)-1-i])
// }

default:
start, _ := stmt.Span()
Expand Down
33 changes: 14 additions & 19 deletions resolve/resolve.go
Original file line number Diff line number Diff line change
Expand Up @@ -563,26 +563,21 @@ func (r *resolver) stmt(stmt syntax.Stmt) {
r.errorf(stmt.Load, "load statement within a conditional")
}

for i, from := range stmt.From {
if from.Name == "" {
r.errorf(from.NamePos, "load: empty identifier")
continue
}
if from.Name[0] == '_' {
r.errorf(from.NamePos, "load: names with leading underscores are not exported: %s", from.Name)
}

id := stmt.To[i]
if LoadBindsGlobally {
r.bind(id)
} else if r.bindLocal(id) && !AllowGlobalReassign {
// "Global" in AllowGlobalReassign is a misnomer for "toplevel".
// Sadly we can't report the previous declaration
// as id.Binding may not be set yet.
r.errorf(id.NamePos, "cannot reassign top-level %s", id.Name)
}
if stmt.Alias.Name == "" {
r.errorf(stmt.Alias.NamePos, "load: empty identifier")
}

if stmt.Alias.Name[0] == '_' {
r.errorf(stmt.Alias.NamePos, "load: names with leading underscores are not exported: %s", stmt.Alias.Name)
}
if LoadBindsGlobally {
r.bind(stmt.Alias)
} else if r.bindLocal(stmt.Alias) && !AllowGlobalReassign {
// "Global" in AllowGlobalReassign is a misnomer for "toplevel".
// Sadly we can't report the previous declaration
// as id.Binding may not be set yet.
r.errorf(stmt.Alias.NamePos, "cannot reassign top-level %s", stmt.Alias.Name)
}
// TODO (maxmcd)
default:
log.Panicf("unexpected stmt %T", stmt)
}
Expand Down
4 changes: 2 additions & 2 deletions resolve/resolve_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (

"go.starlark.net/internal/chunkedfile"
"go.starlark.net/resolve"
"go.starlark.net/starlarktest"
"go.starlark.net/syntax"
)

Expand All @@ -30,7 +29,8 @@ func option(chunk, name string) bool {

func TestResolve(t *testing.T) {
defer setOptions("")
filename := starlarktest.DataFile("resolve", "testdata/resolve.star")
// filename := starlarktest.DataFile("resolve", "testdata/resolve.star")
filename := "./testdata/resolve.star"
for _, chunk := range chunkedfile.Read(filename, t) {
f, err := syntax.Parse(filename, chunk.Source, 0)
if err != nil {
Expand Down
34 changes: 14 additions & 20 deletions resolve/testdata/resolve.star
Original file line number Diff line number Diff line change
Expand Up @@ -130,32 +130,26 @@ def f():
f()

---
load("module", "name") # ok
load(name="module") # ok

def f():
load("foo", "bar") ### "load statement within a function"
load("foo") ### "load statement within a function"

load("foo",
"", ### "load: empty identifier"
"_a", ### "load: names with leading underscores are not exported: _a"
b="", ### "load: empty identifier"
c="_d", ### "load: names with leading underscores are not exported: _d"
_e="f") # ok

---
# option:globalreassign
if M:
load("foo", "bar") ### "load statement within a conditional"
load("bar") ### "load statement within a conditional"

---
# option:globalreassign
for x in M:
load("foo", "bar") ### "load statement within a loop"
load("bar") ### "load statement within a loop"

---
# option:recursion option:globalreassign
while M:
load("foo", "bar") ### "load statement within a loop"
load("bar") ### "load statement within a loop"

---
# return statements must be within a function
Expand Down Expand Up @@ -361,28 +355,28 @@ def f(abc):
print(goodbye) ### `undefined: goodbye$`

---
load("module", "x") # ok
load(x="module") # ok
x = 1 ### `cannot reassign local x`
load("module", "x") ### `cannot reassign top-level x`
load(x="module") ### `cannot reassign top-level x`

---
# option:loadbindsglobally
load("module", "x") # ok
load(x="module") # ok
x = 1 ### `cannot reassign global x`
load("module", "x") ### `cannot reassign global x`
load(x="module") ### `cannot reassign global x`

---
# option:globalreassign
load("module", "x") # ok
load(x="module") # ok
x = 1 # ok
load("module", "x") # ok
load(x="module") # ok

---
# option:globalreassign option:loadbindsglobally
load("module", "x") # ok
load(x="module") # ok
x = 1
load("module", "x") # ok
load(x="module") # ok

---
_ = x # forward ref to file-local
load("module", "x") # ok
load(x="module") # ok
5 changes: 3 additions & 2 deletions starlark/eval_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@ func TestEvalExpr(t *testing.T) {

func TestExecFile(t *testing.T) {
defer setOptions("")
testdata := starlarktest.DataFile("starlark", ".")
// testdata := starlarktest.DataFile("starlark", ".")
testdata := "."
thread := &starlark.Thread{Load: load}
starlarktest.SetReporter(thread, t)
for _, file := range []string{
Expand Down Expand Up @@ -564,7 +565,7 @@ func TestLoadBacktrace(t *testing.T) {
// For discussion, see:
// https://github.com/google/starlark-go/pull/244
const src = `
load('crash.star', 'x')
load('crash.star')
`
const loadedSrc = `
def f(x):
Expand Down
14 changes: 7 additions & 7 deletions starlark/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ squares = [x*x for x in range(10)]
// implementation of 'load' that works sequentially.
func ExampleThread_Load_sequential() {
fakeFilesystem := map[string]string{
"c.star": `load("b.star", "b"); c = b + "!"`,
"b.star": `load("a.star", "a"); b = a + ", world"`,
"c.star": `load("b.star"); c = b.b + "!"`,
"b.star": `load("a.star"); b = a.a + ", world"`,
"a.star": `a = "Hello"`,
}

Expand Down Expand Up @@ -133,8 +133,8 @@ func ExampleThread_Load_parallel() {
cache := &cache{
cache: make(map[string]*entry),
fakeFilesystem: map[string]string{
"c.star": `load("a.star", "a"); c = a * 2`,
"b.star": `load("a.star", "a"); b = a * 3`,
"c.star": `load("a.star"); c = a.a * 2`,
"b.star": `load("a.star"); b = a.a * 3`,
"a.star": `a = 1; print("loaded a")`,
},
}
Expand Down Expand Up @@ -170,9 +170,9 @@ func TestThreadLoad_ParallelCycle(t *testing.T) {
cache := &cache{
cache: make(map[string]*entry),
fakeFilesystem: map[string]string{
"c.star": `load("b.star", "b"); c = b * 2`,
"b.star": `load("a.star", "a"); b = a * 3`,
"a.star": `load("c.star", "c"); a = c * 5; print("loaded a")`,
"c.star": `load("b.star"); c = b.b * 2`,
"b.star": `load("a.star"); b = a.a * 3`,
"a.star": `load("c.star"); a = c.c * 5; print("loaded a")`,
},
}

Expand Down
33 changes: 18 additions & 15 deletions starlark/interp.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"unsafe"

"go.starlark.net/internal/compile"
"go.starlark.net/internal/spell"
"go.starlark.net/resolve"
"go.starlark.net/syntax"
)
Expand Down Expand Up @@ -510,7 +509,7 @@ loop:
}

case compile.LOAD:
n := int(arg)
// hasAlias := int(arg)
module := string(stack[sp-1].(String))
sp--

Expand All @@ -529,19 +528,23 @@ loop:
}
break loop
}

for i := 0; i < n; i++ {
from := string(stack[sp-1-i].(String))
v, ok := dict[from]
if !ok {
err = fmt.Errorf("load: name %s not found in module %s", from, module)
if n := spell.Nearest(from, dict.Keys()); n != "" {
err = fmt.Errorf("%s (did you mean %s?)", err, n)
}
break loop
}
stack[sp-1-i] = v
}
stack[sp-1-0] = &Module{
Name: module,
Members: dict,
}

// for i := 0; i < n; i++ {
// from := string(stack[sp-1-i].(String))
// v, ok := dict[from]
// if !ok {
// err = fmt.Errorf("load: name %s not found in module %s", from, module)
// if n := spell.Nearest(from, dict.Keys()); n != "" {
// err = fmt.Errorf("%s (did you mean %s?)", err, n)
// }
// break loop
// }
// stack[sp-1-i] = v
// }

case compile.SETLOCAL:
locals[arg] = stack[sp-1]
Expand Down
34 changes: 34 additions & 0 deletions starlark/module.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package starlark

import "fmt"

type Module struct {
Name string
Members StringDict
}

var _ HasAttrs = (*Module)(nil)

func (m *Module) Attr(name string) (Value, error) { return m.Members[name], nil }
func (m *Module) AttrNames() []string { return m.Members.Keys() }
func (m *Module) Freeze() { m.Members.Freeze() }
func (m *Module) Hash() (uint32, error) { return 0, fmt.Errorf("unhashable: %s", m.Type()) }
func (m *Module) String() string { return fmt.Sprintf("<module %q>", m.Name) }
func (m *Module) Truth() Bool { return true }
func (m *Module) Type() string { return "module" }

// MakeModule may be used as the implementation of a Starlark built-in
// function, module(name, **kwargs). It returns a new module with the
// specified name and members.
func MakeModule(thread *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) {
var name string
if err := UnpackPositionalArgs(b.Name(), args, nil, 1, &name); err != nil {
return nil, err
}
members := make(StringDict, len(kwargs))
for _, kwarg := range kwargs {
k := string(kwarg[0].(String))
members[k] = kwarg[1]
}
return &Module{name, members}, nil
}
Loading