rum-goggles/v1/vendor/github.com/robertkrimen/otto/stash.go

290 lines
6 KiB
Go
Raw Permalink Normal View History

package otto
import (
"fmt"
)
2024-04-04 14:46:14 +00:00
// stasher is implemented by types which can stash data.
type stasher interface {
hasBinding(string) bool //
createBinding(string, bool, Value) // CreateMutableBinding
setBinding(string, Value, bool) // SetMutableBinding
getBinding(string, bool) Value // GetBindingValue
deleteBinding(string) bool //
setValue(string, Value, bool) // createBinding + setBinding
2024-04-04 14:46:14 +00:00
outer() stasher
runtime() *runtime
2024-04-04 14:46:14 +00:00
newReference(string, bool, at) referencer
2024-04-04 14:46:14 +00:00
clone(*cloner) stasher
}
2024-04-04 14:46:14 +00:00
type objectStash struct {
rt *runtime
outr stasher
object *object
}
2024-04-04 14:46:14 +00:00
func (s *objectStash) runtime() *runtime {
return s.rt
}
2024-04-04 14:46:14 +00:00
func (rt *runtime) newObjectStash(obj *object, outer stasher) *objectStash {
if obj == nil {
obj = rt.newBaseObject()
obj.class = "environment"
}
2024-04-04 14:46:14 +00:00
return &objectStash{
rt: rt,
outr: outer,
object: obj,
}
}
2024-04-04 14:46:14 +00:00
func (s *objectStash) clone(c *cloner) stasher {
out, exists := c.objectStash(s)
if exists {
return out
}
2024-04-04 14:46:14 +00:00
*out = objectStash{
c.runtime,
c.stash(s.outr),
c.object(s.object),
}
return out
}
2024-04-04 14:46:14 +00:00
func (s *objectStash) hasBinding(name string) bool {
return s.object.hasProperty(name)
}
2024-04-04 14:46:14 +00:00
func (s *objectStash) createBinding(name string, deletable bool, value Value) {
if s.object.hasProperty(name) {
panic(hereBeDragons())
}
2024-04-04 14:46:14 +00:00
mode := propertyMode(0o111)
if !deletable {
2024-04-04 14:46:14 +00:00
mode = propertyMode(0o110)
}
// TODO False?
2024-04-04 14:46:14 +00:00
s.object.defineProperty(name, value, mode, false)
}
2024-04-04 14:46:14 +00:00
func (s *objectStash) setBinding(name string, value Value, strict bool) {
s.object.put(name, value, strict)
}
2024-04-04 14:46:14 +00:00
func (s *objectStash) setValue(name string, value Value, throw bool) {
if !s.hasBinding(name) {
s.createBinding(name, true, value) // Configurable by default
} else {
2024-04-04 14:46:14 +00:00
s.setBinding(name, value, throw)
}
}
2024-04-04 14:46:14 +00:00
func (s *objectStash) getBinding(name string, throw bool) Value {
if s.object.hasProperty(name) {
return s.object.get(name)
}
if throw { // strict?
2024-04-04 14:46:14 +00:00
panic(s.rt.panicReferenceError("Not Defined", name))
}
return Value{}
}
2024-04-04 14:46:14 +00:00
func (s *objectStash) deleteBinding(name string) bool {
return s.object.delete(name, false)
}
2024-04-04 14:46:14 +00:00
func (s *objectStash) outer() stasher {
return s.outr
}
2024-04-04 14:46:14 +00:00
func (s *objectStash) newReference(name string, strict bool, atv at) referencer {
return newPropertyReference(s.rt, s.object, name, strict, atv)
}
2024-04-04 14:46:14 +00:00
type dclStash struct {
rt *runtime
outr stasher
property map[string]dclProperty
}
2024-04-04 14:46:14 +00:00
type dclProperty struct {
value Value
mutable bool
deletable bool
readable bool
}
2024-04-04 14:46:14 +00:00
func (rt *runtime) newDeclarationStash(outer stasher) *dclStash {
return &dclStash{
rt: rt,
outr: outer,
property: map[string]dclProperty{},
}
}
2024-04-04 14:46:14 +00:00
func (s *dclStash) clone(c *cloner) stasher {
out, exists := c.dclStash(s)
if exists {
return out
}
2024-04-04 14:46:14 +00:00
prop := make(map[string]dclProperty, len(s.property))
for index, value := range s.property {
prop[index] = c.dclProperty(value)
}
2024-04-04 14:46:14 +00:00
*out = dclStash{
c.runtime,
c.stash(s.outr),
prop,
}
return out
}
2024-04-04 14:46:14 +00:00
func (s *dclStash) hasBinding(name string) bool {
_, exists := s.property[name]
return exists
}
2024-04-04 14:46:14 +00:00
func (s *dclStash) runtime() *runtime {
return s.rt
}
2024-04-04 14:46:14 +00:00
func (s *dclStash) createBinding(name string, deletable bool, value Value) {
if _, exists := s.property[name]; exists {
panic(fmt.Errorf("createBinding: %s: already exists", name))
}
2024-04-04 14:46:14 +00:00
s.property[name] = dclProperty{
value: value,
mutable: true,
deletable: deletable,
readable: false,
}
}
2024-04-04 14:46:14 +00:00
func (s *dclStash) setBinding(name string, value Value, strict bool) {
prop, exists := s.property[name]
if !exists {
panic(fmt.Errorf("setBinding: %s: missing", name))
}
2024-04-04 14:46:14 +00:00
if prop.mutable {
prop.value = value
s.property[name] = prop
} else {
2024-04-04 14:46:14 +00:00
s.rt.typeErrorResult(strict)
}
}
2024-04-04 14:46:14 +00:00
func (s *dclStash) setValue(name string, value Value, throw bool) {
if !s.hasBinding(name) {
s.createBinding(name, false, value) // NOT deletable by default
} else {
2024-04-04 14:46:14 +00:00
s.setBinding(name, value, throw)
}
}
2024-04-04 14:46:14 +00:00
// FIXME This is called a __lot__.
func (s *dclStash) getBinding(name string, throw bool) Value {
prop, exists := s.property[name]
if !exists {
panic(fmt.Errorf("getBinding: %s: missing", name))
}
2024-04-04 14:46:14 +00:00
if !prop.mutable && !prop.readable {
if throw { // strict?
2024-04-04 14:46:14 +00:00
panic(s.rt.panicTypeError("getBinding property %s not mutable and not readable", name))
}
return Value{}
}
2024-04-04 14:46:14 +00:00
return prop.value
}
2024-04-04 14:46:14 +00:00
func (s *dclStash) deleteBinding(name string) bool {
prop, exists := s.property[name]
if !exists {
return true
}
2024-04-04 14:46:14 +00:00
if !prop.deletable {
return false
}
2024-04-04 14:46:14 +00:00
delete(s.property, name)
return true
}
2024-04-04 14:46:14 +00:00
func (s *dclStash) outer() stasher {
return s.outr
}
2024-04-04 14:46:14 +00:00
func (s *dclStash) newReference(name string, strict bool, _ at) referencer {
return &stashReference{
name: name,
2024-04-04 14:46:14 +00:00
base: s,
}
}
// ========
// _fnStash
// ========
2024-04-04 14:46:14 +00:00
type fnStash struct {
dclStash
arguments *object
indexOfArgumentName map[string]string
}
2024-04-04 14:46:14 +00:00
func (rt *runtime) newFunctionStash(outer stasher) *fnStash {
return &fnStash{
dclStash: dclStash{
rt: rt,
outr: outer,
property: map[string]dclProperty{},
},
}
}
2024-04-04 14:46:14 +00:00
func (s *fnStash) clone(c *cloner) stasher {
out, exists := c.fnStash(s)
if exists {
return out
}
2024-04-04 14:46:14 +00:00
dclStash := s.dclStash.clone(c).(*dclStash)
index := make(map[string]string, len(s.indexOfArgumentName))
for name, value := range s.indexOfArgumentName {
index[name] = value
}
2024-04-04 14:46:14 +00:00
*out = fnStash{
dclStash: *dclStash,
arguments: c.object(s.arguments),
indexOfArgumentName: index,
}
return out
}
2024-04-04 14:46:14 +00:00
// getStashProperties returns the properties from stash.
func getStashProperties(stash stasher) []string {
switch vars := stash.(type) {
2024-04-04 14:46:14 +00:00
case *dclStash:
keys := make([]string, 0, len(vars.property))
for k := range vars.property {
keys = append(keys, k)
}
2024-04-04 14:46:14 +00:00
return keys
case *fnStash:
keys := make([]string, 0, len(vars.property))
for k := range vars.property {
keys = append(keys, k)
}
2024-04-04 14:46:14 +00:00
return keys
case *objectStash:
keys := make([]string, 0, len(vars.object.property))
for k := range vars.object.property {
keys = append(keys, k)
}
2024-04-04 14:46:14 +00:00
return keys
default:
panic("unknown stash type")
}
}