1
0
mirror of https://github.com/MontFerret/ferret.git synced 2024-12-16 11:37:36 +02:00
ferret/pkg/runtime/core/scope.go

152 lines
2.5 KiB
Go
Raw Normal View History

2018-09-18 22:42:38 +02:00
package core
import (
"io"
)
type (
2018-10-28 07:45:26 +02:00
CloseFunc func() error
RootScope struct {
closed bool
disposables []io.Closer
}
2018-09-18 22:42:38 +02:00
Scope struct {
2018-10-28 07:45:26 +02:00
root *RootScope
parent *Scope
vars map[string]Value
2018-09-18 22:42:38 +02:00
}
)
func NewRootScope() (*Scope, CloseFunc) {
2018-10-28 07:45:26 +02:00
root := &RootScope{
closed: false,
disposables: make([]io.Closer, 0, 10),
}
return newScope(root, nil), root.Close
2018-10-28 07:45:26 +02:00
}
2018-09-18 22:42:38 +02:00
2018-10-28 07:45:26 +02:00
func (s *RootScope) AddDisposable(disposable io.Closer) {
if s.closed {
return
2018-09-18 22:42:38 +02:00
}
2018-10-28 07:45:26 +02:00
if disposable != nil {
s.disposables = append(s.disposables, disposable)
}
}
func (s *RootScope) Close() error {
if s.closed {
return Error(ErrInvalidOperation, "scope is already closed")
}
s.closed = true
var errors []error
2018-10-28 07:45:26 +02:00
// close all values implemented io.Close
for _, c := range s.disposables {
if err := c.Close(); err != nil {
if errors == nil {
errors = make([]error, 0, len(s.disposables))
}
errors = append(errors, err)
}
2018-10-28 07:45:26 +02:00
}
if errors == nil {
return nil
}
return Errors(errors...)
2018-09-18 22:42:38 +02:00
}
2018-10-28 07:45:26 +02:00
func newScope(root *RootScope, parent *Scope) *Scope {
2018-09-18 22:42:38 +02:00
return &Scope{
2018-10-28 07:45:26 +02:00
root: root,
parent: parent,
vars: make(map[string]Value),
2018-09-18 22:42:38 +02:00
}
}
func (s *Scope) SetVariable(name string, val Value) error {
_, exists := s.vars[name]
// it already has been declared in the current scope
if exists {
2018-10-28 07:45:26 +02:00
return Errorf(ErrNotUnique, "variable is already declared: '%s'", name)
}
disposable, ok := val.(io.Closer)
if ok {
s.root.AddDisposable(disposable)
2018-09-18 22:42:38 +02:00
}
s.vars[name] = val
return nil
}
func (s *Scope) HasVariable(name string) bool {
_, exists := s.vars[name]
// does not exist in the current scope
// try to find in a parent scope
if !exists {
if s.parent != nil {
return s.parent.HasVariable(name)
}
}
return exists
}
func (s *Scope) GetVariable(name string) (Value, error) {
out, exists := s.vars[name]
// does not exist in the current scope
// try to find in the parent scope
if !exists {
if s.parent != nil {
return s.parent.GetVariable(name)
}
2018-10-28 07:45:26 +02:00
return nil, Errorf(ErrNotFound, "variable: '%s'", name)
2018-09-18 22:42:38 +02:00
}
return out, nil
}
2018-10-28 07:45:26 +02:00
func (s *Scope) MustGetVariable(name string) Value {
out, err := s.GetVariable(name)
2018-09-18 22:42:38 +02:00
2018-10-28 07:45:26 +02:00
if err != nil {
panic(err)
}
2018-09-18 22:42:38 +02:00
2018-10-28 07:45:26 +02:00
return out
2018-09-18 22:42:38 +02:00
}
2018-10-28 07:45:26 +02:00
func (s *Scope) UpdateVariable(name string, val Value) error {
_, exists := s.vars[name]
2018-09-18 22:42:38 +02:00
2018-10-28 07:45:26 +02:00
if !exists {
return Errorf(ErrNotFound, "variable: '%s'", name)
2018-09-18 22:42:38 +02:00
}
2018-10-28 07:45:26 +02:00
delete(s.vars, name)
2018-09-18 22:42:38 +02:00
2018-10-28 07:45:26 +02:00
return s.SetVariable(name, val)
}
2018-09-18 22:42:38 +02:00
2018-10-28 07:45:26 +02:00
func (s *Scope) Fork() *Scope {
child := newScope(s.root, s)
2018-09-18 22:42:38 +02:00
2018-10-28 07:45:26 +02:00
return child
2018-09-18 22:42:38 +02:00
}