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