Skip to content

Commit

Permalink
starlarkstruct: add 'module' type, and use it for assert module (goog…
Browse files Browse the repository at this point in the history
…le#91)

...instead of struct, which is more suited to dynamic values.

This type will be used for Stargo (see wip-stargo branch).
For example, this load statement

  load("go", http="net/http", json="encoding/json")

would load two modules.
  • Loading branch information
adonovan authored Jan 4, 2019
1 parent 1ed6497 commit 9d97771
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 24 deletions.
1 change: 1 addition & 0 deletions starlark/eval_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ func TestExecFile(t *testing.T) {
"testdata/string.star",
"testdata/tuple.star",
"testdata/recursion.star",
"testdata/module.star",
} {
filename := filepath.Join(testdata, file)
for _, chunk := range chunkedfile.Read(filename, t) {
Expand Down
8 changes: 8 additions & 0 deletions starlark/testdata/module.star
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Tests of Module.

load("assert.star", "assert")

assert.eq(type(assert), "module")
assert.eq(str(assert), '<module "assert">')
assert.eq(dir(assert), ["contains", "eq", "fail", "fails", "lt", "ne", "true"])
assert.fails(lambda : {assert: None}, "unhashable: module")
43 changes: 43 additions & 0 deletions starlarkstruct/module.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package starlarkstruct

import (
"fmt"

"go.starlark.net/starlark"
)

// A Module is a named collection of values,
// typically a suite of functions imported by a load statement.
//
// It differs from Struct primarily in that its string representation
// does not enumerate its fields.
type Module struct {
Name string
Members starlark.StringDict
}

var _ starlark.HasAttrs = (*Module)(nil)

func (m *Module) Attr(name string) (starlark.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() starlark.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 *starlark.Thread, b *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
var name string
if err := starlark.UnpackPositionalArgs(b.Name(), args, nil, 1, &name); err != nil {
return nil, err
}
members := make(starlark.StringDict, len(kwargs))
for _, kwarg := range kwargs {
k := string(kwarg[0].(starlark.String))
members[k] = kwarg[1]
}
return &Module{name, members}, nil
}
4 changes: 2 additions & 2 deletions starlarkstruct/struct.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package starlarkstruct defines the Starlark 'struct' type,
// an optional language extension.
// Package starlarkstruct defines the Starlark types 'struct' and
// 'module', both optional language extensions.
package starlarkstruct // import "go.starlark.net/starlarkstruct"

// It is tempting to introduce a variant of Struct that is a wrapper
Expand Down
42 changes: 21 additions & 21 deletions starlarktest/assert.star
Original file line number Diff line number Diff line change
@@ -1,45 +1,45 @@

# Predeclared built-ins for this module:
#
# error(msg): report an error in Go's test framework without halting execution.
# catch(f): evaluate f() and returns its evaluation error message, if any
# matches(str, pattern): report whether str matches regular expression pattern.
# struct: a constructor for a simple HasFields implementation.
# module(**kwargs): a constructor for a module.
# _freeze(x): freeze the value x and everything reachable from it.
#
# Clients may use these functions to define their own testing abstractions.

def _eq(x, y):
if x != y:
error("%r != %r" % (x, y))
if x != y:
error("%r != %r" % (x, y))

def _ne(x, y):
if x == y:
error("%r == %r" % (x, y))
if x == y:
error("%r == %r" % (x, y))

def _true(cond, msg="assertion failed"):
if not cond:
error(msg)
def _true(cond, msg = "assertion failed"):
if not cond:
error(msg)

def _lt(x, y):
if not (x < y):
error("%s is not less than %s" % (x, y))
if not (x < y):
error("%s is not less than %s" % (x, y))

def _contains(x, y):
if y not in x:
error("%s does not contain %s" % (x, y))
if y not in x:
error("%s does not contain %s" % (x, y))

def _fails(f, pattern):
"assert_fails asserts that evaluation of f() fails with the specified error."
msg = catch(f)
if msg == None:
error("evaluation succeeded unexpectedly (want error matching %r)" % pattern)
elif not matches(pattern, msg):
error("regular expression (%s) did not match error (%s)" % (pattern, msg))
"assert_fails asserts that evaluation of f() fails with the specified error."
msg = catch(f)
if msg == None:
error("evaluation succeeded unexpectedly (want error matching %r)" % pattern)
elif not matches(pattern, msg):
error("regular expression (%s) did not match error (%s)" % (pattern, msg))

freeze = _freeze # an exported global whose value is the built-in freeze function
freeze = _freeze # an exported global whose value is the built-in freeze function

assert = struct(
assert = module(
"assert",
fail = error,
eq = _eq,
ne = _ne,
Expand Down
2 changes: 1 addition & 1 deletion starlarktest/starlarktest.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func LoadAssertModule() (starlark.StringDict, error) {
"error": starlark.NewBuiltin("error", error_),
"catch": starlark.NewBuiltin("catch", catch),
"matches": starlark.NewBuiltin("matches", matches),
"struct": starlark.NewBuiltin("struct", starlarkstruct.Make),
"module": starlark.NewBuiltin("module", starlarkstruct.MakeModule),
"_freeze": starlark.NewBuiltin("freeze", freeze),
}
filename := DataFile("starlarktest", "assert.star")
Expand Down

0 comments on commit 9d97771

Please sign in to comment.