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  }