1*4947cdc7SCole Faust// Copyright 2018 The Bazel Authors. All rights reserved. 2*4947cdc7SCole Faust// Use of this source code is governed by a BSD-style 3*4947cdc7SCole Faust// license that can be found in the LICENSE file. 4*4947cdc7SCole Faust 5*4947cdc7SCole Faustpackage starlarkstruct_test 6*4947cdc7SCole Faust 7*4947cdc7SCole Faustimport ( 8*4947cdc7SCole Faust "fmt" 9*4947cdc7SCole Faust "path/filepath" 10*4947cdc7SCole Faust "testing" 11*4947cdc7SCole Faust 12*4947cdc7SCole Faust "go.starlark.net/starlark" 13*4947cdc7SCole Faust "go.starlark.net/starlarkstruct" 14*4947cdc7SCole Faust "go.starlark.net/starlarktest" 15*4947cdc7SCole Faust) 16*4947cdc7SCole Faust 17*4947cdc7SCole Faustfunc Test(t *testing.T) { 18*4947cdc7SCole Faust testdata := starlarktest.DataFile("starlarkstruct", ".") 19*4947cdc7SCole Faust thread := &starlark.Thread{Load: load} 20*4947cdc7SCole Faust starlarktest.SetReporter(thread, t) 21*4947cdc7SCole Faust filename := filepath.Join(testdata, "testdata/struct.star") 22*4947cdc7SCole Faust predeclared := starlark.StringDict{ 23*4947cdc7SCole Faust "struct": starlark.NewBuiltin("struct", starlarkstruct.Make), 24*4947cdc7SCole Faust "gensym": starlark.NewBuiltin("gensym", gensym), 25*4947cdc7SCole Faust } 26*4947cdc7SCole Faust if _, err := starlark.ExecFile(thread, filename, nil, predeclared); err != nil { 27*4947cdc7SCole Faust if err, ok := err.(*starlark.EvalError); ok { 28*4947cdc7SCole Faust t.Fatal(err.Backtrace()) 29*4947cdc7SCole Faust } 30*4947cdc7SCole Faust t.Fatal(err) 31*4947cdc7SCole Faust } 32*4947cdc7SCole Faust} 33*4947cdc7SCole Faust 34*4947cdc7SCole Faust// load implements the 'load' operation as used in the evaluator tests. 35*4947cdc7SCole Faustfunc load(thread *starlark.Thread, module string) (starlark.StringDict, error) { 36*4947cdc7SCole Faust if module == "assert.star" { 37*4947cdc7SCole Faust return starlarktest.LoadAssertModule() 38*4947cdc7SCole Faust } 39*4947cdc7SCole Faust return nil, fmt.Errorf("load not implemented") 40*4947cdc7SCole Faust} 41*4947cdc7SCole Faust 42*4947cdc7SCole Faust// gensym is a built-in function that generates a unique symbol. 43*4947cdc7SCole Faustfunc gensym(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) { 44*4947cdc7SCole Faust var name string 45*4947cdc7SCole Faust if err := starlark.UnpackArgs("gensym", args, kwargs, "name", &name); err != nil { 46*4947cdc7SCole Faust return nil, err 47*4947cdc7SCole Faust } 48*4947cdc7SCole Faust return &symbol{name: name}, nil 49*4947cdc7SCole Faust} 50*4947cdc7SCole Faust 51*4947cdc7SCole Faust// A symbol is a distinct value that acts as a constructor of "branded" 52*4947cdc7SCole Faust// struct instances, like a class symbol in Python or a "provider" in Bazel. 53*4947cdc7SCole Fausttype symbol struct{ name string } 54*4947cdc7SCole Faust 55*4947cdc7SCole Faustvar _ starlark.Callable = (*symbol)(nil) 56*4947cdc7SCole Faust 57*4947cdc7SCole Faustfunc (sym *symbol) Name() string { return sym.name } 58*4947cdc7SCole Faustfunc (sym *symbol) String() string { return sym.name } 59*4947cdc7SCole Faustfunc (sym *symbol) Type() string { return "symbol" } 60*4947cdc7SCole Faustfunc (sym *symbol) Freeze() {} // immutable 61*4947cdc7SCole Faustfunc (sym *symbol) Truth() starlark.Bool { return starlark.True } 62*4947cdc7SCole Faustfunc (sym *symbol) Hash() (uint32, error) { return 0, fmt.Errorf("unhashable: %s", sym.Type()) } 63*4947cdc7SCole Faust 64*4947cdc7SCole Faustfunc (sym *symbol) CallInternal(thread *starlark.Thread, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) { 65*4947cdc7SCole Faust if len(args) > 0 { 66*4947cdc7SCole Faust return nil, fmt.Errorf("%s: unexpected positional arguments", sym) 67*4947cdc7SCole Faust } 68*4947cdc7SCole Faust return starlarkstruct.FromKeywords(sym, kwargs), nil 69*4947cdc7SCole Faust} 70