github.com/kubeshop/testkube@v1.17.23/pkg/tcl/expressionstcl/machine.go (about)

     1  // Copyright 2024 Testkube.
     2  //
     3  // Licensed as a Testkube Pro file under the Testkube Community
     4  // License (the "License"); you may not use this file except in compliance with
     5  // the License. You may obtain a copy of the License at
     6  //
     7  //     https://github.com/kubeshop/testkube/blob/main/licenses/TCL.txt
     8  
     9  package expressionstcl
    10  
    11  import "strings"
    12  
    13  //go:generate mockgen -destination=./mock_machine.go -package=expressionstcl "github.com/kubeshop/testkube/pkg/tcl/expressionstcl" Machine
    14  type Machine interface {
    15  	Get(name string) (Expression, bool, error)
    16  	Call(name string, args ...StaticValue) (Expression, bool, error)
    17  }
    18  
    19  type MachineAccessorExt = func(name string) (interface{}, bool, error)
    20  type MachineAccessor = func(name string) (interface{}, bool)
    21  type MachineFn = func(values ...StaticValue) (interface{}, bool, error)
    22  
    23  type machine struct {
    24  	accessors []MachineAccessorExt
    25  	functions map[string]MachineFn
    26  }
    27  
    28  func NewMachine() *machine {
    29  	return &machine{
    30  		accessors: make([]MachineAccessorExt, 0),
    31  		functions: make(map[string]MachineFn),
    32  	}
    33  }
    34  
    35  func (m *machine) Register(name string, value interface{}) *machine {
    36  	return m.RegisterAccessor(func(n string) (interface{}, bool) {
    37  		if n == name {
    38  			return value, true
    39  		}
    40  		return nil, false
    41  	})
    42  }
    43  
    44  func (m *machine) RegisterStringMap(prefix string, value map[string]string) *machine {
    45  	if len(prefix) > 0 {
    46  		prefix += "."
    47  	}
    48  	return m.RegisterAccessor(func(n string) (interface{}, bool) {
    49  		if !strings.HasPrefix(n, prefix) {
    50  			return nil, false
    51  		}
    52  		v, ok := value[n[len(prefix):]]
    53  		return v, ok
    54  	})
    55  }
    56  
    57  func (m *machine) RegisterAccessorExt(fn MachineAccessorExt) *machine {
    58  	m.accessors = append(m.accessors, fn)
    59  	return m
    60  }
    61  
    62  func (m *machine) RegisterAccessor(fn MachineAccessor) *machine {
    63  	return m.RegisterAccessorExt(func(name string) (interface{}, bool, error) {
    64  		v, ok := fn(name)
    65  		return v, ok, nil
    66  	})
    67  }
    68  
    69  func (m *machine) RegisterFunction(name string, fn MachineFn) *machine {
    70  	m.functions[name] = fn
    71  	return m
    72  }
    73  
    74  func (m *machine) Get(name string) (Expression, bool, error) {
    75  	for i := range m.accessors {
    76  		r, ok, err := m.accessors[i](name)
    77  		if err != nil {
    78  			return nil, true, err
    79  		}
    80  		if ok {
    81  			if v, ok := r.(Expression); ok {
    82  				return v, true, nil
    83  			}
    84  			return NewValue(r), true, nil
    85  		}
    86  	}
    87  	return nil, false, nil
    88  }
    89  
    90  func (m *machine) Call(name string, args ...StaticValue) (Expression, bool, error) {
    91  	fn, ok := m.functions[name]
    92  	if !ok {
    93  		return nil, false, nil
    94  	}
    95  	r, ok, err := fn(args...)
    96  	if !ok || err != nil {
    97  		return nil, ok, err
    98  	}
    99  	if v, ok := r.(Expression); ok {
   100  		return v, true, nil
   101  	}
   102  	return NewValue(r), true, nil
   103  }