1
0
mirror of https://github.com/robertkrimen/otto synced 2025-10-26 20:28:49 +08:00

The zero value of Value is now defined to be undefined

Previously, it was a publically accessible but invalid value (valueEmpty).

* Deprecate internal use of UndefinedValue(), NullValue(), FalseValue(), TrueValue()
* Guard against Empty, Result, Reference values from escaping the package
This commit is contained in:
Robert Krimen
2014-05-28 21:23:32 -07:00
parent 526d3b2fd5
commit 918abeb8d8
40 changed files with 1232 additions and 1219 deletions

48
otto.go
View File

@@ -57,7 +57,7 @@ Set a Go function
vm.Set("sayHello", func(call otto.FunctionCall) otto.Value {
fmt.Printf("Hello, %s.\n", call.Argument(0).String())
return otto.UndefinedValue()
return otto.Value{}
})
Set a Go function that returns something useful
@@ -272,7 +272,7 @@ func (otto *Otto) clone() *Otto {
//
func Run(src interface{}) (*Otto, Value, error) {
otto := New()
value, err := otto.Run(src)
value, err := otto.Run(src) // This already does safety checking
return otto, value, err
}
@@ -288,7 +288,11 @@ func Run(src interface{}) (*Otto, Value, error) {
// src may also be a Program, but if the AST has been modified, then runtime behavior is undefined.
//
func (self Otto) Run(src interface{}) (Value, error) {
return self.runtime.cmpl_run(src)
value, err := self.runtime.cmpl_run(src)
if !value.safe() {
value = Value{}
}
return value, err
}
// Get the value of the top-level binding of the given name.
@@ -296,10 +300,13 @@ func (self Otto) Run(src interface{}) (Value, error) {
// If there is an error (like the binding does not exist), then the value
// will be undefined.
func (self Otto) Get(name string) (Value, error) {
value := UndefinedValue()
value := Value{}
err := catchPanic(func() {
value = self.getValue(name)
})
if !value.safe() {
value = Value{}
}
return value, err
}
@@ -355,7 +362,7 @@ func (self Otto) setValue(name string, value Value) {
//
func (self Otto) Call(source string, this interface{}, argumentList ...interface{}) (Value, error) {
thisValue := UndefinedValue()
thisValue := Value{}
construct := false
if strings.HasPrefix(source, "new ") {
@@ -373,7 +380,7 @@ func (self Otto) Call(source string, this interface{}, argumentList ...interface
value = self.runtime.cmpl_evaluate_nodeCallExpression(node, argumentList)
})
if err != nil {
return UndefinedValue(), err
return Value{}, err
}
return value, nil
}
@@ -382,7 +389,7 @@ func (self Otto) Call(source string, this interface{}, argumentList ...interface
} else {
value, err := self.ToValue(this)
if err != nil {
return UndefinedValue(), err
return Value{}, err
}
thisValue = value
}
@@ -392,20 +399,20 @@ func (self Otto) Call(source string, this interface{}, argumentList ...interface
fn, err := self.Run(source)
if err != nil {
return UndefinedValue(), err
return Value{}, err
}
if construct {
result, err := fn.constructSafe(this, argumentList...)
if err != nil {
return UndefinedValue(), err
return Value{}, err
}
return result, nil
}
result, err := fn.Call(this, argumentList...)
if err != nil {
return UndefinedValue(), err
return Value{}, err
}
return result, nil
}
@@ -441,17 +448,17 @@ func (self Otto) Object(source string) (*Object, error) {
// ToValue will convert an interface{} value to a value digestible by otto/JavaScript.
func (self Otto) ToValue(value interface{}) (Value, error) {
return self.runtime.ToValue(value)
return self.runtime.safeToValue(value)
}
// Copy will create a copy/clone of the runtime.
//
// Copy is useful for saving some processing time when creating many similar
// runtimes.
// Copy is useful for saving some time when creating many similar runtimes.
//
// This implementation is alpha-ish, and works by introspecting every part of the runtime
// and reallocating and then relinking everything back together. Please report if you
// notice any inadvertent sharing of data between copies.
// This method works by walking the original runtime and cloning each object, scope, stash,
// etc. into a new runtime.
//
// Be on the lookout for memory leaks or inadvertent sharing of resources.
func (self *Otto) Copy() *Otto {
otto := &Otto{
runtime: self.runtime.clone(),
@@ -495,7 +502,7 @@ func (self Object) Call(name string, argumentList ...interface{}) (Value, error)
function, err := self.Get(name)
if err != nil {
return UndefinedValue(), err
return Value{}, err
}
return function.Call(self.Value(), argumentList...)
}
@@ -507,10 +514,13 @@ func (self Object) Value() Value {
// Get the value of the property with the given name.
func (self Object) Get(name string) (Value, error) {
value := UndefinedValue()
value := Value{}
err := catchPanic(func() {
value = self.object.get(name)
})
if !value.safe() {
value = Value{}
}
return value, err
}
@@ -520,7 +530,7 @@ func (self Object) Get(name string) (Value, error) {
// or there is an error during conversion of the given value.
func (self Object) Set(name string, value interface{}) error {
{
value, err := self.object.runtime.ToValue(value)
value, err := self.object.runtime.safeToValue(value)
if err != nil {
return err
}