mirror of
https://github.com/MontFerret/ferret.git
synced 2024-12-16 11:37:36 +02:00
5620be211c
* Renamed DOCUMENT to PAGE * Added PageLoadParams * Added PageLoadParams * Renamed LoadPageParams -> PageLoadParams * Added support for context.Done() (#201) * Bug/#189 operators precedence (#202) * Fixed math operators precedence * Fixed logical operators precedence * Fixed array operator * Added support for parentheses to enforce a different operator evaluation order * Feature/#200 drivers (#209) * Added new interfaces * Renamed dynamic to cdp driver * Renamed drivers * Added ELEMENT_EXISTS function (#210) * Renamed back PAGE to DOCUMENT (#211) * Added Getter and Setter interfaces
154 lines
2.5 KiB
Go
154 lines
2.5 KiB
Go
package core
|
|
|
|
import (
|
|
"io"
|
|
)
|
|
|
|
type (
|
|
CloseFunc func() error
|
|
|
|
RootScope struct {
|
|
closed bool
|
|
disposables []io.Closer
|
|
}
|
|
|
|
Scope struct {
|
|
root *RootScope
|
|
parent *Scope
|
|
vars map[string]Value
|
|
}
|
|
)
|
|
|
|
func NewRootScope() (*Scope, CloseFunc) {
|
|
root := &RootScope{
|
|
closed: false,
|
|
disposables: make([]io.Closer, 0, 10),
|
|
}
|
|
|
|
return newScope(root, nil), func() error {
|
|
return root.Close()
|
|
}
|
|
}
|
|
|
|
func (s *RootScope) AddDisposable(disposable io.Closer) {
|
|
if s.closed {
|
|
return
|
|
}
|
|
|
|
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
|
|
|
|
// 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)
|
|
}
|
|
}
|
|
|
|
if errors == nil {
|
|
return nil
|
|
}
|
|
|
|
return Errors(errors...)
|
|
}
|
|
|
|
func newScope(root *RootScope, parent *Scope) *Scope {
|
|
return &Scope{
|
|
root: root,
|
|
parent: parent,
|
|
vars: make(map[string]Value),
|
|
}
|
|
}
|
|
|
|
func (s *Scope) SetVariable(name string, val Value) error {
|
|
_, exists := s.vars[name]
|
|
|
|
// it already has been declared in the current scope
|
|
if exists {
|
|
return Errorf(ErrNotUnique, "variable is already declared: '%s'", name)
|
|
}
|
|
|
|
disposable, ok := val.(io.Closer)
|
|
|
|
if ok {
|
|
s.root.AddDisposable(disposable)
|
|
}
|
|
|
|
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)
|
|
}
|
|
|
|
return nil, Errorf(ErrNotFound, "variable: '%s'", name)
|
|
}
|
|
|
|
return out, nil
|
|
}
|
|
|
|
func (s *Scope) MustGetVariable(name string) Value {
|
|
out, err := s.GetVariable(name)
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return out
|
|
}
|
|
|
|
func (s *Scope) UpdateVariable(name string, val Value) error {
|
|
_, exists := s.vars[name]
|
|
|
|
if !exists {
|
|
return Errorf(ErrNotFound, "variable: '%s'", name)
|
|
}
|
|
|
|
delete(s.vars, name)
|
|
|
|
return s.SetVariable(name, val)
|
|
}
|
|
|
|
func (s *Scope) Fork() *Scope {
|
|
child := newScope(s.root, s)
|
|
|
|
return child
|
|
}
|