1
0
mirror of https://github.com/robertkrimen/otto synced 2025-10-19 19:55:30 +08:00

Cleanup of stash, property, and object

Use octal to designate write/enumerate/configure (experimental)
Move extensibility responsibility into the stash
Rename propertyStash => objectStash (be congruent with arrayStash, etc.)
Get rid of a bunch of useless methods
Privatize everything ([A-Z] => [a-z_])
gofmt
This commit is contained in:
Robert Krimen 2012-10-22 14:39:16 -07:00
parent c1a21812fe
commit 3c93384f5c
25 changed files with 585 additions and 592 deletions

View File

@ -8,6 +8,8 @@ WITH_otto := --command "$(otto)"
test:
$(TEST) $(WITH_otto)
release: otto gauntlet
test-otto: test
otto: build

View File

@ -81,13 +81,13 @@ func _builtinGlobal_encodeURI(call FunctionCall, characterRegexp *regexp.Regexp)
return toValue(string(value))
}
var encodeURI_Regexp *regexp.Regexp = regexp.MustCompile(`([^~!@#$&*()=:/,;?+'])`)
var encodeURI_Regexp = regexp.MustCompile(`([^~!@#$&*()=:/,;?+'])`)
func builtinGlobal_encodeURI(call FunctionCall) Value {
return _builtinGlobal_encodeURI(call, encodeURI_Regexp)
}
var encodeURIComponent_Regexp *regexp.Regexp = regexp.MustCompile(`([^~!*()'])`)
var encodeURIComponent_Regexp = regexp.MustCompile(`([^~!*()'])`)
func builtinGlobal_encodeURIComponent(call FunctionCall) Value {
return _builtinGlobal_encodeURI(call, encodeURIComponent_Regexp)
@ -124,7 +124,7 @@ func builtinObject_toString(call FunctionCall) Value {
} else if call.This.IsNull() {
result = "[object Null]"
} else {
result = fmt.Sprintf("[object %s]", call.thisObject().Class)
result = fmt.Sprintf("[object %s]", call.thisObject().class)
}
return toValue(result)
}
@ -177,10 +177,10 @@ func builtinFunction_apply(call FunctionCall) Value {
arrayObject := argumentList._object()
thisObject := call.thisObject()
length := uint(toUI32(arrayObject.Get("length")))
length := uint(toUI32(arrayObject.get("length")))
valueArray := make([]Value, length)
for index := uint(0); index < length; index++ {
valueArray[index] = arrayObject.Get(arrayIndexToString(index))
valueArray[index] = arrayObject.get(arrayIndexToString(index))
}
return thisObject.Call(this, valueArray)
}
@ -317,10 +317,10 @@ func builtinString_match(call FunctionCall) Value {
target := toString(call.This)
matcherValue := call.Argument(0)
matcher := matcherValue._object()
if !matcherValue.IsObject() || matcher.Class != "RegExp" {
if !matcherValue.IsObject() || matcher.class != "RegExp" {
matcher = call.runtime.newRegExp(matcherValue, UndefinedValue())
}
global := toBoolean(matcher.Get("global"))
global := toBoolean(matcher.get("global"))
if !global {
match, result := execRegExp(matcher, target)
if !match {
@ -330,10 +330,10 @@ func builtinString_match(call FunctionCall) Value {
}
{
result := matcher.RegExp.RegularExpression.FindAllStringIndex(target, -1)
result := matcher._RegExp.RegularExpression.FindAllStringIndex(target, -1)
matchCount := len(result)
if result == nil {
matcher.WriteValue("lastIndex", toValue(0), true)
matcher.set("lastIndex", toValue(0), true)
return UndefinedValue() // !match
}
matchCount = len(result)
@ -341,12 +341,12 @@ func builtinString_match(call FunctionCall) Value {
for index := 0; index < matchCount; index++ {
valueArray[index] = toValue(target[result[index][0]:result[index][1]])
}
matcher.WriteValue("lastIndex", toValue(result[matchCount-1][1]), true)
matcher.set("lastIndex", toValue(result[matchCount-1][1]), true)
return toValue(call.runtime.newArray(valueArray))
}
}
var builtinString_replace_Regexp *regexp.Regexp = regexp.MustCompile("\\$(?:[\\$\\&\\'\\`1-9]|0[1-9]|[1-9][0-9])")
var builtinString_replace_Regexp = regexp.MustCompile("\\$(?:[\\$\\&\\'\\`1-9]|0[1-9]|[1-9][0-9])")
func builtinString_findAndReplaceString(input []byte, lastIndex int, match []int, target []byte, replaceValue []byte) (output []byte) {
matchCount := len(match) / 2
@ -391,9 +391,9 @@ func builtinString_replace(call FunctionCall) Value {
var search *regexp.Regexp
global := false
find := 1
if searchValue.IsObject() && searchObject.Class == "RegExp" {
search = searchObject.RegExp.RegularExpression
global = toBoolean(searchObject.Get("global"))
if searchValue.IsObject() && searchObject.class == "RegExp" {
search = searchObject._RegExp.RegularExpression
global = toBoolean(searchObject.get("global"))
if global {
find = -1
}
@ -448,7 +448,7 @@ func builtinString_replace(call FunctionCall) Value {
}
if global && searchObject != nil {
searchObject.Put("lastIndex", toValue(lastIndex), true)
searchObject.put("lastIndex", toValue(lastIndex), true)
}
return toValue(string(result))
@ -462,10 +462,10 @@ func builtinString_search(call FunctionCall) Value {
target := toString(call.This)
searchValue := call.Argument(0)
search := searchValue._object()
if !searchValue.IsObject() || search.Class != "RegExp" {
if !searchValue.IsObject() || search.class != "RegExp" {
search = call.runtime.newRegExp(searchValue, UndefinedValue())
}
result := search.RegExp.RegularExpression.FindStringIndex(target)
result := search._RegExp.RegularExpression.FindStringIndex(target)
if result == nil {
return toValue(-1)
}
@ -504,7 +504,7 @@ func builtinString_split(call FunctionCall) Value {
if separatorValue.isRegExp() {
targetLength := len(target)
search := separatorValue._object().RegExp.RegularExpression
search := separatorValue._object()._RegExp.RegularExpression
valueArray := []Value{}
result := search.FindAllStringSubmatchIndex(target, -1)
lastIndex := 0
@ -697,8 +697,8 @@ func builtinArray_concat(call FunctionCall) Value {
switch item._valueType {
case valueObject:
value := item._object()
if value.Class == "Array" {
itemValueArray := value._propertyStash.(*_arrayStash).valueArray
if value.class == "Array" {
itemValueArray := value.stash.(*_arrayStash).valueArray
for _, item := range itemValueArray {
if item._valueType == valueEmpty {
continue
@ -717,50 +717,50 @@ func builtinArray_concat(call FunctionCall) Value {
func builtinArray_shift(call FunctionCall) Value {
thisObject := call.thisObject()
length := uint(toUI32(thisObject.Get("length")))
length := uint(toUI32(thisObject.get("length")))
if 0 == length {
thisObject.Put("length", toValue(length), true)
thisObject.put("length", toValue(length), true)
return UndefinedValue()
}
first := thisObject.Get("0")
first := thisObject.get("0")
for index := uint(1); index < length; index++ {
from := arrayIndexToString(index)
to := arrayIndexToString(index - 1)
if thisObject.HasProperty(from) {
thisObject.Put(to, thisObject.Get(from), true)
if thisObject.hasProperty(from) {
thisObject.put(to, thisObject.get(from), true)
} else {
thisObject.Delete(to, true)
thisObject.delete(to, true)
}
}
thisObject.Delete(arrayIndexToString(length - 1), true)
thisObject.Put("length", toValue(length - 1), true)
thisObject.delete(arrayIndexToString(length - 1), true)
thisObject.put("length", toValue(length - 1), true)
return first
}
func builtinArray_push(call FunctionCall) Value {
thisObject := call.thisObject()
itemList := call.ArgumentList
index := uint(toUI32(thisObject.Get("length")))
index := uint(toUI32(thisObject.get("length")))
for len(itemList) > 0 {
thisObject.Put(arrayIndexToString(index), itemList[0], true)
thisObject.put(arrayIndexToString(index), itemList[0], true)
itemList = itemList[1:]
index += 1
}
length := toValue(index)
thisObject.Put("length", length, true)
thisObject.put("length", length, true)
return length
}
func builtinArray_pop(call FunctionCall) Value {
thisObject := call.thisObject()
length := uint(toUI32(thisObject.Get("length")))
length := uint(toUI32(thisObject.get("length")))
if 0 == length {
thisObject.Put("length", toValue(length), true)
thisObject.put("length", toValue(length), true)
return UndefinedValue()
}
last := thisObject.Get(arrayIndexToString(length - 1))
thisObject.Delete(arrayIndexToString(length - 1), true)
thisObject.Put("length", toValue(length - 1), true)
last := thisObject.get(arrayIndexToString(length - 1))
thisObject.delete(arrayIndexToString(length - 1), true)
thisObject.put("length", toValue(length - 1), true)
return last
}
@ -773,17 +773,17 @@ func builtinArray_join(call FunctionCall) Value {
}
}
thisObject := call.thisObject()
if stash, isArray := thisObject._propertyStash.(*_arrayStash); isArray {
if stash, isArray := thisObject.stash.(*_arrayStash); isArray {
return toValue(builtinArray_joinNative(stash.valueArray, separator))
}
// Generic .join
length := uint(toUI32(thisObject.Get("length")))
length := uint(toUI32(thisObject.get("length")))
if length == 0 {
return toValue("")
}
stringList := make([]string, 0, length)
for index := uint(0); index < length; index += 1 {
value := thisObject.Get(arrayIndexToString(index))
value := thisObject.get(arrayIndexToString(index))
stringValue := ""
switch value._valueType {
case valueEmpty, valueUndefined, valueNull:
@ -852,7 +852,7 @@ func rangeStartLength(source []Value, size uint) (start, length int64) {
func builtinArray_splice(call FunctionCall) Value {
thisObject := call.thisObject()
length := uint(toUI32(thisObject.Get("length")))
length := uint(toUI32(thisObject.get("length")))
start := valueToArrayIndex(call.Argument(0), length, true)
deleteCount := valueToArrayIndex(call.Argument(1), length - start, false)
@ -860,8 +860,8 @@ func builtinArray_splice(call FunctionCall) Value {
for index := uint(0); index < deleteCount; index++ {
indexString := arrayIndexToString(start + index)
if thisObject.HasProperty(indexString) {
valueArray[index] = thisObject.Get(indexString)
if thisObject.hasProperty(indexString) {
valueArray[index] = thisObject.get(indexString)
}
}
@ -887,17 +887,17 @@ func builtinArray_splice(call FunctionCall) Value {
for index := start; index < stop; index++ {
from := arrayIndexToString(index + deleteCount) // Position just after deletion
to := arrayIndexToString(index + itemCount) // Position just after splice (insertion)
if thisObject.HasProperty(from) {
thisObject.Put(to, thisObject.Get(from), true)
if thisObject.hasProperty(from) {
thisObject.put(to, thisObject.get(from), true)
} else {
thisObject.Delete(to, true)
thisObject.delete(to, true)
}
}
// Delete off the end
// We don't bother to delete below <stop + itemCount> (if any) since those
// will be overwritten anyway
for index := length; index > (stop + itemCount); index-- {
thisObject.Delete(arrayIndexToString(index - 1), true)
thisObject.delete(arrayIndexToString(index - 1), true)
}
} else if itemCount > deleteCount {
// The Object/Array is growing
@ -910,18 +910,18 @@ func builtinArray_splice(call FunctionCall) Value {
for index := length - deleteCount; index > start; index-- {
from := arrayIndexToString(index + deleteCount - 1)
to := arrayIndexToString(index + itemCount - 1)
if thisObject.HasProperty(from) {
thisObject.Put(to, thisObject.Get(from), true)
if thisObject.hasProperty(from) {
thisObject.put(to, thisObject.get(from), true)
} else {
thisObject.Delete(to, true)
thisObject.delete(to, true)
}
}
}
for index := uint(0); index < itemCount; index++ {
thisObject.Put(arrayIndexToString(index + start), itemList[index], true)
thisObject.put(arrayIndexToString(index + start), itemList[index], true)
}
thisObject.Put("length", toValue(length + itemCount - deleteCount), true)
thisObject.put("length", toValue(length + itemCount - deleteCount), true)
return toValue(call.runtime.newArray(valueArray))
}
@ -929,7 +929,7 @@ func builtinArray_splice(call FunctionCall) Value {
func builtinArray_slice(call FunctionCall) Value {
thisObject := call.thisObject()
length := uint(toUI32(thisObject.Get("length")))
length := uint(toUI32(thisObject.get("length")))
start, end := rangeStartEnd(call.ArgumentList, length)
if start >= end {
@ -940,13 +940,13 @@ func builtinArray_slice(call FunctionCall) Value {
sliceValueArray := make([]Value, sliceLength)
// Native slicing if a "real" array
if _arrayStash, ok := thisObject._propertyStash.(*_arrayStash); ok {
if _arrayStash, ok := thisObject.stash.(*_arrayStash); ok {
copy(sliceValueArray, _arrayStash.valueArray[start:start+sliceLength])
} else {
for index := uint(0); index < sliceLength; index++ {
from := arrayIndexToString(index + start)
if thisObject.HasProperty(from) {
sliceValueArray[index] = thisObject.Get(from)
if thisObject.hasProperty(from) {
sliceValueArray[index] = thisObject.get(from)
}
}
}
@ -956,32 +956,32 @@ func builtinArray_slice(call FunctionCall) Value {
func builtinArray_unshift(call FunctionCall) Value {
thisObject := call.thisObject()
length := uint(toUI32(thisObject.Get("length")))
length := uint(toUI32(thisObject.get("length")))
itemList := call.ArgumentList
itemCount := uint(len(itemList))
for index := length; index > 0; index-- {
from := arrayIndexToString(index - 1)
to := arrayIndexToString(index + itemCount - 1)
if thisObject.HasProperty(from) {
thisObject.Put(to, thisObject.Get(from), true)
if thisObject.hasProperty(from) {
thisObject.put(to, thisObject.get(from), true)
} else {
thisObject.Delete(to, true)
thisObject.delete(to, true)
}
}
for index := uint(0); index < itemCount; index++ {
thisObject.Put(arrayIndexToString(index), itemList[index], true)
thisObject.put(arrayIndexToString(index), itemList[index], true)
}
newLength := toValue(length + itemCount)
thisObject.Put("length", newLength, true)
thisObject.put("length", newLength, true)
return newLength
}
func builtinArray_reverse(call FunctionCall) Value {
thisObject := call.thisObject()
length := uint(toUI32(thisObject.Get("length")))
length := uint(toUI32(thisObject.get("length")))
lower := struct {
name string
@ -998,22 +998,22 @@ func builtinArray_reverse(call FunctionCall) Value {
upper.index = length - lower.index - 1
upper.name = arrayIndexToString(upper.index)
lower.exists = thisObject.HasProperty(lower.name)
upper.exists = thisObject.HasProperty(upper.name)
lower.exists = thisObject.hasProperty(lower.name)
upper.exists = thisObject.hasProperty(upper.name)
if lower.exists && upper.exists {
lowerValue := thisObject.Get(lower.name)
upperValue := thisObject.Get(upper.name)
thisObject.Put(lower.name, upperValue, true)
thisObject.Put(upper.name, lowerValue, true)
lowerValue := thisObject.get(lower.name)
upperValue := thisObject.get(upper.name)
thisObject.put(lower.name, upperValue, true)
thisObject.put(upper.name, lowerValue, true)
} else if !lower.exists && upper.exists {
value := thisObject.Get(upper.name)
thisObject.Delete(upper.name, true)
thisObject.Put(lower.name, value, true)
value := thisObject.get(upper.name)
thisObject.delete(upper.name, true)
thisObject.put(lower.name, value, true)
} else if lower.exists && !upper.exists {
value := thisObject.Get(lower.name)
thisObject.Delete(lower.name, true)
thisObject.Put(upper.name, value, true)
value := thisObject.get(lower.name)
thisObject.delete(lower.name, true)
thisObject.put(upper.name, value, true)
} else {
// Nothing happens.
}
@ -1033,9 +1033,9 @@ func sortCompare(thisObject *_object, index0, index1 uint, compare *_object) int
}{}
k := j
j.name = arrayIndexToString(index0)
j.exists = thisObject.HasProperty(j.name)
j.exists = thisObject.hasProperty(j.name)
k.name = arrayIndexToString(index1)
k.exists = thisObject.HasProperty(k.name)
k.exists = thisObject.hasProperty(k.name)
if !j.exists && !k.exists {
return 0
@ -1045,8 +1045,8 @@ func sortCompare(thisObject *_object, index0, index1 uint, compare *_object) int
return -1
}
x := thisObject.Get(j.name)
y := thisObject.Get(k.name)
x := thisObject.get(j.name)
y := thisObject.get(k.name)
j.defined = x.IsDefined()
k.defined = y.IsDefined()
@ -1083,23 +1083,23 @@ func arraySortSwap(thisObject *_object, index0, index1 uint) {
k := j
j.name = arrayIndexToString(index0)
j.exists = thisObject.HasProperty(j.name)
j.exists = thisObject.hasProperty(j.name)
k.name = arrayIndexToString(index1)
k.exists = thisObject.HasProperty(k.name)
k.exists = thisObject.hasProperty(k.name)
if j.exists && k.exists {
jValue := thisObject.Get(j.name)
kValue := thisObject.Get(k.name)
thisObject.Put(j.name, kValue, true)
thisObject.Put(k.name, jValue, true)
jValue := thisObject.get(j.name)
kValue := thisObject.get(k.name)
thisObject.put(j.name, kValue, true)
thisObject.put(k.name, jValue, true)
} else if !j.exists && k.exists {
value := thisObject.Get(k.name)
thisObject.Delete(k.name, true)
thisObject.Put(j.name, value, true)
value := thisObject.get(k.name)
thisObject.delete(k.name, true)
thisObject.put(j.name, value, true)
} else if j.exists && !k.exists {
value := thisObject.Get(j.name)
thisObject.Delete(j.name, true)
thisObject.Put(k.name, value, true)
value := thisObject.get(j.name)
thisObject.delete(j.name, true)
thisObject.put(k.name, value, true)
} else {
// Nothing happens.
}
@ -1131,7 +1131,7 @@ func arraySortQuickSort(thisObject *_object, left, right uint, compare *_object)
func builtinArray_sort(call FunctionCall) Value {
thisObject := call.thisObject()
length := uint(toUI32(thisObject.Get("length")))
length := uint(toUI32(thisObject.get("length")))
compareValue := call.Argument(0)
compare := compareValue._object()
if compareValue.IsUndefined() {
@ -1156,15 +1156,15 @@ func builtinNewRegExp(self *_object, _ Value, argumentList []Value) Value {
func builtinRegExp_toString(call FunctionCall) Value {
thisObject := call.thisObject()
source := toString(thisObject.Get("source"))
source := toString(thisObject.get("source"))
flags := []byte{}
if toBoolean(thisObject.Get("global")) {
if toBoolean(thisObject.get("global")) {
flags = append(flags, 'g')
}
if toBoolean(thisObject.Get("ignoreCase")) {
if toBoolean(thisObject.get("ignoreCase")) {
flags = append(flags, 'i')
}
if toBoolean(thisObject.Get("multiline")) {
if toBoolean(thisObject.get("multiline")) {
flags = append(flags, 'm')
}
return toValue(fmt.Sprintf("/%s/%s", source, flags))
@ -1339,13 +1339,13 @@ func builtinError_toString(call FunctionCall) Value {
}
name := "Error"
nameValue := thisObject.Get("name")
nameValue := thisObject.get("name")
if nameValue.IsDefined() {
name = toString(nameValue)
}
message := ""
messageValue := thisObject.Get("message")
messageValue := thisObject.get("message")
if messageValue.IsDefined() {
message = toString(messageValue)
}

View File

@ -32,7 +32,7 @@ func builtinConsole_placeholder(call FunctionCall) Value {
func (runtime *_runtime) newConsole() *_object {
self := runtime.newObject()
self.Define(
self.write(
"log", builtinConsole_log,
"debug", builtinConsole_log,
"info", builtinConsole_log,

View File

@ -58,7 +58,7 @@ func (self *_functionEnvironment) HasBinding(name string) bool {
if exists {
return true
}
return self.Object.HasProperty(name)
return self.Object.hasProperty(name)
}
type _objectEnvironment struct {
@ -77,23 +77,23 @@ func (runtime *_runtime) newObjectEnvironment() *_objectEnvironment {
}
func (self *_objectEnvironment) HasBinding(name string) bool {
return self.Object.HasProperty(name)
return self.Object.hasProperty(name)
}
func (self *_objectEnvironment) CreateMutableBinding(name string, configure bool) {
if self.Object.HasProperty(name) {
if self.Object.hasProperty(name) {
panic(hereBeDragons())
}
self.Object._propertyStash.Write(name, UndefinedValue())
self.Object.stash.put(name, UndefinedValue())
}
func (self *_objectEnvironment) SetMutableBinding(name string, value Value, strict bool) {
self.Object.WriteValue(name, value, strict)
self.Object.set(name, value, strict)
}
func (self *_objectEnvironment) GetBindingValue(name string, strict bool) Value {
if self.Object.HasProperty(name) {
return self.Object.Get(name)
if self.Object.hasProperty(name) {
return self.Object.get(name)
}
if strict {
panic(newReferenceError("Not Defined", name))
@ -102,7 +102,7 @@ func (self *_objectEnvironment) GetBindingValue(name string, strict bool) Value
}
func (self *_objectEnvironment) DeleteBinding(name string) bool {
return self.Object.Delete(name, false)
return self.Object.delete(name, false)
}
func (self *_objectEnvironment) ImplicitThisValue() *_object {

View File

@ -46,7 +46,7 @@ func (self *_runtime) evaluateObject(node *_objectNode) Value {
result := self.newObject()
for _, property := range node.propertyList {
result.WriteValue(property.Key, self.GetValue(self.evaluate(property.Value)), false)
result.set(property.Key, self.GetValue(self.evaluate(property.Value)), false)
}
return toValue(result)
@ -118,7 +118,7 @@ func (self *_runtime) evaluateUnaryOperation(node *_unaryOperationNode) Value {
case valueString:
return toValue("string")
case valueObject:
if targetValue._object().Function != nil {
if targetValue._object()._Function != nil {
return toValue("function")
}
return toValue("object")
@ -256,7 +256,7 @@ func (self *_runtime) calculateBinaryOperation(operator string, left Value, righ
if !rightValue.IsObject() {
panic(newTypeError())
}
return toValue(rightValue._object().HasProperty(toString(leftValue)))
return toValue(rightValue._object().hasProperty(toString(leftValue)))
}
panic(hereBeDragons(operator))

View File

@ -190,7 +190,7 @@ func (self *_runtime) evaluateForIn(node *_forInNode) Value {
result := emptyValue()
object := sourceObject
for object != nil {
object.Enumerate(func(name string){
object.enumerate(func(name string){
into := self.evaluate(into)
// In the case of: for (var abc in def) ...
if into.reference() == nil {
@ -204,7 +204,7 @@ func (self *_runtime) evaluateForIn(node *_forInNode) Value {
result = value
}
})
object = object.Prototype
object = object.prototype
}
return result
})

159
global.go
View File

@ -10,45 +10,43 @@ type _globalConstructFunction _constructFunction
func (self *_runtime) newGlobalFunction(
length int,
callFunction _globalCallFunction,
name string, callFunction _globalCallFunction,
constructFunction _globalConstructFunction,
prototype *_object,
nameAndValue... interface{}) *_object {
//
definition... interface{}) *_object {
// TODO We're overwriting the prototype of newNativeFunction with this one,
// what is going on?
target := self.newNativeFunction(_nativeFunction(callFunction), length)
target.Function.Construct = _constructFunction(constructFunction)
target.define(_propertyMode(0), "prototype", toValue(prototype))
nameAndValue = append(
[]interface{}{
functionObject := self.newNativeFunction(_nativeFunction(callFunction), length, "native" + name)
functionObject._Function.Construct = _constructFunction(constructFunction)
functionObject.stash.set("prototype", toValue(prototype), _propertyMode(0))
prototype.write(append([]interface{}{
_functionSignature("builtin"),
_propertyMode(propertyModeWrite | propertyModeConfigure),
"constructor", toValue(target),
_propertyMode(0101), // Write | Configure
"constructor", toValue(functionObject),
},
nameAndValue...,
)
// This actually may be slower than Define
// Benchmark?
prototype.define(nameAndValue...)
return target
definition...,
)...)
return functionObject
}
func (self *_runtime) newGlobalObject(
class string,
nameAndValue... interface{}) *_object {
//
target := self.newClassObject(class)
nameAndValue = append(
[]interface{}{
_functionSignature("builtin"),
_propertyMode(propertyModeWrite | propertyModeConfigure),
_propertyMode(0101), // Write | Configure
},
nameAndValue...,
)
// This actually may be slower than Define
// Benchmark?
target.define(nameAndValue...)
target.write(nameAndValue...)
return target
}
@ -56,11 +54,11 @@ func builtinDefine(target *_object, nameAndValue... interface{}) {
nameAndValue = append(
[]interface{}{
_functionSignature("builtin"),
_propertyMode(propertyModeWrite | propertyModeConfigure),
_propertyMode(0101), // Write | Configure
},
nameAndValue...,
)
target.define(nameAndValue)
target.write(nameAndValue)
}
func newContext() *_runtime {
@ -76,63 +74,63 @@ func newContext() *_runtime {
{
ObjectPrototype := self.newObject()
ObjectPrototype.Prototype = nil
ObjectPrototype.prototype = nil
self.Global.ObjectPrototype = ObjectPrototype
}
{
FunctionPrototype := self.newNativeFunctionObject(func(FunctionCall) Value {
return UndefinedValue()
}, 0)
FunctionPrototype.Prototype = self.Global.ObjectPrototype
}, 0, "nativeFunction_")
FunctionPrototype.prototype = self.Global.ObjectPrototype
self.Global.FunctionPrototype = FunctionPrototype
}
{
ArrayPrototype := self.newArray([]Value{})
ArrayPrototype.Prototype = self.Global.ObjectPrototype
ArrayPrototype.prototype = self.Global.ObjectPrototype
self.Global.ArrayPrototype = ArrayPrototype
}
{
StringPrototype := self.newString(toValue(""))
StringPrototype.Prototype = self.Global.ObjectPrototype
StringPrototype.prototype = self.Global.ObjectPrototype
self.Global.StringPrototype = StringPrototype
}
{
BooleanPrototype := self.newBoolean(FalseValue())
BooleanPrototype.Prototype = self.Global.ObjectPrototype
BooleanPrototype.prototype = self.Global.ObjectPrototype
self.Global.BooleanPrototype = BooleanPrototype
}
{
NumberPrototype := self.newNumber(toValue(0))
NumberPrototype.Prototype = self.Global.ObjectPrototype
NumberPrototype.prototype = self.Global.ObjectPrototype
self.Global.NumberPrototype = NumberPrototype
}
{
DatePrototype := self.newDate(0)
DatePrototype.Prototype = self.Global.ObjectPrototype
DatePrototype.prototype = self.Global.ObjectPrototype
self.Global.DatePrototype = DatePrototype
}
{
RegExpPrototype := self.newRegExp(UndefinedValue(), UndefinedValue())
RegExpPrototype.Prototype = self.Global.ObjectPrototype
RegExpPrototype.prototype = self.Global.ObjectPrototype
self.Global.RegExpPrototype = RegExpPrototype
}
{
ErrorPrototype := self.newErrorObject(UndefinedValue())
ErrorPrototype.Prototype = self.Global.ObjectPrototype
ErrorPrototype.prototype = self.Global.ObjectPrototype
self.Global.ErrorPrototype = ErrorPrototype
}
self.Global.Object = self.newGlobalFunction(
1,
builtinObject,
"Object", builtinObject,
builtinNewObject,
self.Global.ObjectPrototype,
"valueOf", func(call FunctionCall) Value {
@ -142,27 +140,27 @@ func newContext() *_runtime {
"hasOwnProperty", func(call FunctionCall) Value {
propertyName := toString(call.Argument(0))
thisObject := call.thisObject()
return toValue(thisObject.HasOwnProperty(propertyName))
return toValue(thisObject.hasOwnProperty(propertyName))
},
"isPrototypeOf", func(call FunctionCall) Value {
value := call.Argument(0)
if !value.IsObject() {
return FalseValue()
}
prototype := call.toObject(value).Prototype
prototype := call.toObject(value).prototype
thisObject := call.thisObject()
for prototype != nil {
if thisObject == prototype {
return TrueValue()
}
prototype = prototype.Prototype
prototype = prototype.prototype
}
return FalseValue()
},
"propertyIsEnumerable", func(call FunctionCall) Value {
propertyName := toString(call.Argument(0))
thisObject := call.thisObject()
property := thisObject.GetOwnProperty(propertyName)
property := thisObject.getOwnProperty(propertyName)
if property != nil && property.CanEnumerate() {
return TrueValue()
}
@ -172,7 +170,7 @@ func newContext() *_runtime {
self.Global.Function = self.newGlobalFunction(
1,
builtinFunction,
"Function", builtinFunction,
builtinNewFunction,
self.Global.FunctionPrototype,
"toString", func(FunctionCall) Value {
@ -184,16 +182,16 @@ func newContext() *_runtime {
self.Global.Array = self.newGlobalFunction(
1,
builtinArray,
"Array", builtinArray,
builtinNewArray,
self.Global.ArrayPrototype,
"toString", func(call FunctionCall) Value {
thisObject := call.thisObject()
join := thisObject.Get("join")
join := thisObject.get("join")
if join.isCallable() {
join := join._object()
if join.Function.Call.Signature() == "builtin" {
if stash, isArray := thisObject._propertyStash.(*_arrayStash); isArray {
if join._Function.Call.name() == "nativeArray_join" {
if stash, isArray := thisObject.stash.(*_arrayStash); isArray {
return toValue(builtinArray_joinNative(stash.valueArray, ","))
}
}
@ -215,14 +213,14 @@ func newContext() *_runtime {
self.Global.String = self.newGlobalFunction(
1,
builtinString,
"String", builtinString,
builtinNewString,
self.Global.StringPrototype,
"toString", func(call FunctionCall) Value {
return *call.thisClassObject("String").Primitive
return *call.thisClassObject("String").primitive
},
"valueOf", func(call FunctionCall) Value {
return *call.thisClassObject("String").Primitive
return *call.thisClassObject("String").primitive
},
"charAt", 1, builtinString_charAt,
"charCodeAt", 1, builtinString_charCodeAt,
@ -240,27 +238,27 @@ func newContext() *_runtime {
"substr", 2, builtinString_substr,
)
// TODO Maybe streamline this redundancy?
self.Global.String.Define(
self.Global.String.write(
"fromCharCode", 1, builtinString_fromCharCode,
)
self.Global.Boolean = self.newGlobalFunction(
1,
builtinBoolean,
"Boolean", builtinBoolean,
builtinNewBoolean,
self.Global.BooleanPrototype,
"toString", func(call FunctionCall) Value {
value := call.This
if !value.IsBoolean() {
// Will throw a TypeError if ThisObject is not a Boolean
value = call.thisClassObject("Boolean").PrimitiveValue()
value = call.thisClassObject("Boolean").primitiveValue()
}
return toValue(toString(value))
},
"valueOf", func(call FunctionCall) Value {
value := call.This
if !value.IsBoolean() {
value = call.thisClassObject("Boolean").PrimitiveValue()
value = call.thisClassObject("Boolean").primitiveValue()
}
return value
},
@ -268,18 +266,18 @@ func newContext() *_runtime {
self.Global.Number = self.newGlobalFunction(
1,
builtinNumber,
"Number", builtinNumber,
builtinNewNumber,
self.Global.NumberPrototype,
"valueOf", func(call FunctionCall) Value {
return *call.thisClassObject("Number").Primitive
return *call.thisClassObject("Number").primitive
},
// TODO toFixed
// TODO toExponential
// TODO toPrecision
)
self.Global.Number.Define(
self.Global.Number.write(
_propertyMode(0),
"MAX_VALUE", toValue(math.MaxFloat64),
"MIN_VALUE", toValue(math.SmallestNonzeroFloat64),
@ -300,7 +298,7 @@ func newContext() *_runtime {
self.Global.Date = self.newGlobalFunction(
7,
builtinDate,
"Date", builtinDate,
builtinNewDate,
self.Global.DatePrototype,
"toString", 0, builtinDate_toString,
@ -584,7 +582,7 @@ func newContext() *_runtime {
self.Global.RegExp = self.newGlobalFunction(
2,
builtinRegExp,
"RegExp", builtinRegExp,
builtinNewRegExp,
self.Global.RegExpPrototype,
"toString", 0, builtinRegExp_toString,
@ -594,14 +592,14 @@ func newContext() *_runtime {
self.Global.Error = self.newGlobalFunction(
1,
builtinError,
"Error", builtinError,
builtinNewError,
self.Global.ErrorPrototype,
"name", toValue("Error"),
"toString", 0, builtinError_toString,
)
self.GlobalObject.Define(
self.GlobalObject.write(
"Object", toValue(self.Global.Object),
"Function", toValue(self.Global.Function),
"Array", toValue(self.Global.Array),
@ -651,37 +649,37 @@ func (runtime *_runtime) newClassObject(class string) *_object {
func (runtime *_runtime) newPrimitiveObject(class string, value Value) *_object {
self := runtime.newClassObject(class)
self.Primitive = &value
self.primitive = &value
return self
}
func (runtime *_runtime) newObject() *_object {
self := runtime.newClassObject("Object")
self.Prototype = runtime.Global.ObjectPrototype
self.prototype = runtime.Global.ObjectPrototype
return self
}
func (runtime *_runtime) newArray(valueArray []Value) *_object {
self := runtime.newArrayObject(valueArray)
self.Prototype = runtime.Global.ArrayPrototype
self.prototype = runtime.Global.ArrayPrototype
return self
}
func (runtime *_runtime) newString(value Value) *_object {
self := runtime.newStringObject(value)
self.Prototype = runtime.Global.StringPrototype
self.prototype = runtime.Global.StringPrototype
return self
}
func (runtime *_runtime) newBoolean(value Value) *_object {
self := runtime.newBooleanObject(value)
self.Prototype = runtime.Global.BooleanPrototype
self.prototype = runtime.Global.BooleanPrototype
return self
}
func (runtime *_runtime) newNumber(value Value) *_object {
self := runtime.newNumberObject(value)
self.Prototype = runtime.Global.NumberPrototype
self.prototype = runtime.Global.NumberPrototype
return self
}
@ -699,14 +697,14 @@ func (runtime *_runtime) newRegExp(patternValue Value, flagsValue Value) *_objec
func (runtime *_runtime) _newRegExp(pattern string, flags string) *_object {
self := runtime.newRegExpObject(pattern, flags)
self.Prototype = runtime.Global.RegExpPrototype
self.prototype = runtime.Global.RegExpPrototype
return self
}
// TODO Should (probably) be one argument, right? This is redundant
func (runtime *_runtime) newDate(epoch float64) *_object {
self := runtime.newDateObject(epoch)
self.Prototype = runtime.Global.DatePrototype
self.prototype = runtime.Global.DatePrototype
return self
}
@ -717,43 +715,37 @@ func (runtime *_runtime) newError(name string, message Value) *_object {
self = _newError(message)
} else {
self = runtime.newErrorObject(message)
self.Prototype = runtime.Global.ErrorPrototype
self.prototype = runtime.Global.ErrorPrototype
if name != "" {
self.WriteValue("name", toValue(name), false)
self.set("name", toValue(name), false)
}
}
return self
}
func (runtime *_runtime) newNativeFunction(_nativeFunction _nativeFunction, length int) *_object {
self := runtime.newNativeFunctionObject(_nativeFunction, length)
self.Prototype = runtime.Global.FunctionPrototype
func (runtime *_runtime) newNativeFunction(_nativeFunction _nativeFunction, length int, name string) *_object {
self := runtime.newNativeFunctionObject(_nativeFunction, length, name)
self.prototype = runtime.Global.FunctionPrototype
prototype := runtime.newObject()
self.define(_propertyMode(0), "prototype", toValue(prototype))
prototype.define(
_propertyMode(propertyModeWrite | propertyModeConfigure),
"constructor", toValue(self),
)
self.stash.set("prototype", toValue(prototype), _propertyMode(0100))
prototype.stash.set("constructor", toValue(self), _propertyMode(0101))
return self
}
func (runtime *_runtime) newNodeFunction(node *_functionNode, scopeEnvironment _environment) *_object {
// TODO Implement 13.2 fully
self := runtime.newNodeFunctionObject(node, scopeEnvironment)
self.Prototype = runtime.Global.FunctionPrototype
self.prototype = runtime.Global.FunctionPrototype
prototype := runtime.newObject()
self.define(_propertyMode(propertyModeWrite), "prototype", toValue(prototype))
prototype.define(
_propertyMode(propertyModeWrite | propertyModeConfigure),
"constructor", toValue(self),
)
self.stash.set("prototype", toValue(prototype), _propertyMode(0100))
prototype.stash.set("constructor", toValue(self), _propertyMode(0101))
return self
}
func (runtime *_runtime) newErrorPrototype(name string) *_object {
prototype := runtime.newClassObject("Error")
prototype.WriteValue("name", toValue(name), false)
prototype.Prototype = runtime.Global.ErrorPrototype
prototype.set("name", toValue(name), false)
prototype.prototype = runtime.Global.ErrorPrototype
return prototype
}
@ -762,13 +754,14 @@ func (runtime *_runtime) defineError(name string) func(Value) *_object {
errorFunction := func(message Value) *_object {
error := runtime.newErrorObject(message)
error.Prototype = prototype
error.prototype = prototype
return error
}
runtime.GlobalObject.WriteValue(name, toValue(runtime.newGlobalFunction(
runtime.GlobalObject.set(name, toValue(runtime.newGlobalFunction(
1,
// e.g. TypeError( ... )
name,
func (call FunctionCall) Value { // TypeError( ... )
return toValue(errorFunction(call.Argument(0)))
},

View File

@ -17,21 +17,21 @@ func TestGlobal(t *testing.T) {
result := runtime.localGet("Object")._object().Call(UndefinedValue(), []Value{toValue(runtime.newObject())})
Is(result.IsObject(), true)
Is(result, "[object Object]")
Is(result._object().Prototype == runtime.Global.ObjectPrototype, true)
Is(result._object().Prototype == runtime.Global.Object.Get("prototype")._object(), true)
Is(runtime.newObject().Prototype == runtime.Global.Object.Get("prototype")._object(), true)
Is(result._object().Get("toString"), "[function]")
Is(result._object().prototype == runtime.Global.ObjectPrototype, true)
Is(result._object().prototype == runtime.Global.Object.get("prototype")._object(), true)
Is(runtime.newObject().prototype == runtime.Global.Object.get("prototype")._object(), true)
Is(result._object().get("toString"), "[function]")
//Is(result.Object().CallMethod("hasOwnProperty", "hasOwnProperty"), falseValue)
//Is(result.Object().Get("toString").Object().Prototype.CallMethod("toString"), "[function]")
//Is(result.Object().Get("toString").Object().Get("toString").Object(), "[function]")
//Is(result.Object().Get("toString").Object().Get("toString"), "[function]")
//Is(result.Object().get("toString").Object().prototype.CallMethod("toString"), "[function]")
//Is(result.Object().get("toString").Object().get("toString").Object(), "[function]")
//Is(result.Object().get("toString").Object().get("toString"), "[function]")
//Is(runtime.localGet("Object").Object().CallMethod("isPrototypeOf", result), falseValue)
//Is(runtime.localGet("Object").Object().Get("prototype").Object().CallMethod("isPrototypeOf", result), trueValue)
//Is(runtime.localGet("Object").Object().get("prototype").Object().CallMethod("isPrototypeOf", result), trueValue)
//Is(runtime.localGet("Function").Object().CallMethod("isPrototypeOf", result), falseValue)
//Is(result.Object().CallMethod("propertyIsEnumerable", "isPrototypeOf"), falseValue)
//result.Object().WriteValue("xyzzy", toValue("Nothing happens."), false)
//Is(result.Object().CallMethod("propertyIsEnumerable", "xyzzy"), trueValue)
//Is(result.Object().Get("xyzzy"), "Nothing happens.")
//Is(result.Object().get("xyzzy"), "Nothing happens.")
abc := runtime.newBoolean(TrueValue())
Is(abc, "true")

296
object.go
View File

@ -3,70 +3,55 @@ package otto
type _object struct {
runtime *_runtime
Class string
Extensible bool
Prototype *_object
class string
prototype *_object
_propertyStash _stash
stash _stash
Primitive *Value
Function *_functionObject
RegExp *_regExpObject
Date *_dateObject
primitive *Value
_Function *_functionObject
_RegExp *_regExpObject
_Date *_dateObject
}
func (self _object) PrimitiveValue() Value {
return *self.Primitive
func (self _object) extensible() bool {
return self.stash.extensible()
}
func (self _object) primitiveValue() Value {
return *self.primitive
}
func newObject(runtime *_runtime, class string) *_object {
return &_object{
runtime: runtime,
Class: class,
Extensible: true,
class: class,
_propertyStash: newPropertyStash(true),
stash: newObjectStash(true),
}
}
// Write
func (self *_object) WriteValue(name string, value Value, throw bool) {
canWrite := self._propertyStash.CanWrite(name)
if !canWrite {
typeErrorResult(throw)
return
}
self._propertyStash.Write(name, value)
}
// Delete
func (self *_object) Delete(name string, throw bool) bool {
property_ := self.GetOwnProperty(name)
func (self *_object) delete(name string, throw bool) bool {
property_ := self.getOwnProperty(name)
if property_ == nil {
return true
}
if property_.CanConfigure() {
self._propertyStash.Delete(name)
self.stash.delete(name)
return true
}
return typeErrorResult(throw)
}
// Get
func (self *_object) GetValue(name string) Value {
return self.Get(name)
}
// 8.12
// 8.12.1
func (self *_object) GetOwnProperty(name string) *_property {
func (self *_object) getOwnProperty(name string) *_property {
// Return a _copy_ of the property
property := self._propertyStash.property(name)
property := self.stash.property(name)
if property == nil {
return nil
}
@ -76,10 +61,11 @@ func (self *_object) GetOwnProperty(name string) *_property {
}
}
// 8.12.2
func (self *_object) getProperty(name string) *_property {
for object := self; object != nil; object = object.Prototype {
property := object._propertyStash.property(name)
for object := self; object != nil; object = object.prototype {
// Despite being a pointer, this property is always a copy
property := object.stash.property(name)
if property != nil {
return property
}
@ -88,31 +74,22 @@ func (self *_object) getProperty(name string) *_property {
return nil
}
// 8.12.2
func (self *_object) GetProperty(name string) *_property {
property := self.getProperty(name)
if property != nil {
property = property.Copy()
}
return property
}
// 8.12.3
func (self *_object) Get(name string) Value {
func (self *_object) get(name string) Value {
object := self
for object != nil {
if object._propertyStash.CanRead(name) {
return object._propertyStash.Read(name)
if object.stash.test(name) {
return object.stash.get(name)
}
object = object.Prototype
object = object.prototype
}
return UndefinedValue()
}
// 8.12.4
func (self *_object) CanPut(name string) bool {
func (self *_object) canPut(name string) bool {
property := self._propertyStash.property(name)
property := self.stash.property(name)
if property != nil {
switch value := property.Value.(type) {
case Value:
@ -124,16 +101,16 @@ func (self *_object) CanPut(name string) bool {
}
}
if self.Prototype != nil {
property = self.Prototype.getProperty(name)
if self.prototype != nil {
property = self.prototype.getProperty(name)
}
if property == nil {
return self.Extensible
return self.extensible()
}
switch value := property.Value.(type) {
case Value:
if !self.Extensible {
if !self.extensible() {
return false
}
return property.CanWrite()
@ -145,18 +122,27 @@ func (self *_object) CanPut(name string) bool {
}
// 8.12.5
func (self *_object) Put(name string, value Value, throw bool) {
if !self.CanPut(name) {
func (self *_object) put(name string, value Value, throw bool) {
if !self.canPut(name) {
typeErrorResult(throw)
return
}
self._propertyStash.Write(name, value)
self.stash.put(name, value)
}
// Like put, but bypass checking of prototype property presence
func (self *_object) set(name string, value Value, throw bool) {
if !self.stash.canPut(name) {
typeErrorResult(throw)
return
}
self.stash.put(name, value)
}
// 8.12.6
func (self *_object) HasProperty(name string) bool {
for object := self; object != nil; object = object.Prototype {
if object._propertyStash.CanRead(name) {
func (self *_object) hasProperty(name string) bool {
for object := self; object != nil; object = object.prototype {
if object.stash.test(name) {
return true
}
}
@ -167,29 +153,29 @@ func (self *_object) HasProperty(name string) bool {
type _defaultValueHint int
const (
defaultValueNoHint _defaultValueHint = iota
defaultValueHintString
defaultValueHintNumber
defaultValueNoHint _defaultValueHint = iota
defaultValueHintString
defaultValueHintNumber
)
// 8.12.8
func (self *_object) DefaultValue(hint _defaultValueHint) Value {
if hint == defaultValueNoHint {
hint = defaultValueHintNumber
}
methodSequence := []string{"valueOf", "toString"}
if (hint == defaultValueHintString) {
methodSequence = []string{"toString", "valueOf"}
}
for _, methodName := range methodSequence {
method := self.Get(methodName)
if method.isCallable() {
result := method._object().Call(toValue(self))
if result.IsPrimitive() {
return result
}
}
}
if hint == defaultValueNoHint {
hint = defaultValueHintNumber
}
methodSequence := []string{"valueOf", "toString"}
if hint == defaultValueHintString {
methodSequence = []string{"toString", "valueOf"}
}
for _, methodName := range methodSequence {
method := self.get(methodName)
if method.isCallable() {
result := method._object().Call(toValue(self))
if result.IsPrimitive() {
return result
}
}
}
panic(newTypeError())
return UndefinedValue()
@ -200,105 +186,93 @@ func (self *_object) String() string {
}
// 8.12.9
func (self *_object) DefineOwnProperty(name string, _defineProperty _defineProperty, throw bool) bool {
return self._propertyStash.Define(name, _defineProperty)
func (self *_object) defineOwnProperty(name string, _defineProperty _defineProperty, throw bool) bool {
return self.stash.define(name, _defineProperty)
}
func (self *_object) DefineOwnValueProperty(name string, value Value, mode _propertyMode, throw bool) bool {
return self._propertyStash.Define(name, _property{Value: value, Mode: mode}.toDefineProperty())
func (self *_object) hasOwnProperty(name string) bool {
return self.stash.test(name)
}
func (self *_object) HasOwnProperty(name string) bool {
return self._propertyStash.CanRead(name)
}
//func (self *_object) Define(definition... interface{}) {
// property_ := _property{ Mode: 0111 }.toDefineProperty()
// length := 0
// nativeClass_ := "native" + self.Class + "_"
func (self *_object) Define(nameAndValue... interface{}) {
property_ := _property{Mode: propertyModeWriteEnumerateConfigure}.toDefineProperty()
// for index := 0; index < len(definition); index++ {
// value := definition[index]
// switch value := value.(type) {
// case _propertyMode:
// property_ = _property{Mode: value}.toDefineProperty()
// case string:
// name := value
// length = 0
// index += 1
//REPEAT: {
// value := definition[index]
// switch value := value.(type) {
// case func(FunctionCall) Value: {
// value := self.runtime.newNativeFunction(value, length, nativeClass_ + name)
// property_.Value = toValue(value)
// self.DefineOwnProperty(name, property_, false)
// }
// case *_object:
// property_.Value = toValue(value)
// self.DefineOwnProperty(name, property_, false)
// case Value:
// property_.Value = value
// self.DefineOwnProperty(name, property_, false)
// case int:
// length = value
// index += 1
// goto REPEAT
// default:
// panic(hereBeDragons())
// }
// }
// }
// }
//}
func (self *_object) write(definition ...interface{}) {
mode := _propertyMode(0111)
length := 0
signature := _functionSignature("")
nativeClass_ := "native" + self.class + "_"
for index := 0; index < len(nameAndValue); index++ {
value := nameAndValue[index]
for index := 0; index < len(definition); index++ {
value := definition[index]
switch value := value.(type) {
case _functionSignature:
signature = value
case _propertyMode:
property_ = _property{Mode: value}.toDefineProperty()
case string:
name := value
length = 0
index += 1
REPEAT: {
value := nameAndValue[index]
switch value := value.(type) {
case func(FunctionCall) Value: {
value := self.runtime.newNativeFunction(value, length)
value.Function.Call.Sign(signature)
property_.Value = toValue(value)
self.DefineOwnProperty(name, property_, false)
}
case *_object:
property_.Value = toValue(value)
self.DefineOwnProperty(name, property_, false)
case Value:
property_.Value = value
self.DefineOwnProperty(name, property_, false)
case int:
length = value
index += 1
goto REPEAT
default:
panic(hereBeDragons())
}
}
}
}
}
func (self *_object) define(nameAndValue... interface{}) {
mode := propertyModeWriteEnumerateConfigure
length := 0
signature := _functionSignature("")
stash := map[string]_valueProperty{}
for index := 0; index < len(nameAndValue); index++ {
value := nameAndValue[index]
switch value := value.(type) {
case _functionSignature:
signature = value
case _propertyMode:
mode = value
case string:
name := value
length = 0
index += 1
REPEAT: {
value := nameAndValue[index]
REPEAT:
{
value := definition[index]
switch value := value.(type) {
case func(FunctionCall) Value: {
value := self.runtime.newNativeFunction(value, length)
value.Function.Call.Sign(signature)
stash[name] = _valueProperty{ toValue(value), mode }
case func(FunctionCall) Value:
{
value := self.runtime.newNativeFunction(value, length, nativeClass_+name)
self.stash.set(name, toValue(value), mode)
}
case *_object:
stash[name] = _valueProperty{ toValue(value), mode }
case Value:
stash[name] = _valueProperty{ value, mode }
case int:
length = value
index += 1
goto REPEAT
default:
panic(hereBeDragons())
case *_object:
self.stash.set(name, toValue(value), mode)
case Value:
self.stash.set(name, value, mode)
case int:
length = value
index += 1
goto REPEAT
default:
panic(hereBeDragons())
}
}
}
}
self._propertyStash.writeValuePropertyMap(stash)
}
func (self *_object) Enumerate(each func(string)) {
self._propertyStash.Enumerate(each)
func (self *_object) enumerate(each func(string)) {
self.stash.enumerate(each)
}

View File

@ -11,15 +11,15 @@ func TestObject_(t *testing.T) {
object := newObject(nil, "")
IsTrue(object != nil)
object.Put("xyzzy", toValue("Nothing happens."), true)
Is(object.Get("xyzzy"), "Nothing happens.")
object.put("xyzzy", toValue("Nothing happens."), true)
Is(object.get("xyzzy"), "Nothing happens.")
}
func TestStringObject(t *testing.T) {
Terst(t)
object := New().runtime.newStringObject(toValue("xyzzy"))
Is(object.Get("1"), "y")
Is(object.Get("10"), "undefined")
Is(object.Get("2"), "z")
Is(object.get("1"), "y")
Is(object.get("10"), "undefined")
Is(object.get("2"), "z")
}

View File

@ -289,7 +289,7 @@ func (self Object) Value() Value {
func (self Object) Get(name string) (Value, error) {
result := UndefinedValue()
err := catchPanic(func(){
result = self.object.Get(name)
result = self.object.get(name)
})
return result, err
}
@ -300,7 +300,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) {
err := catchPanic(func(){
self.object.Put(name, self.object.runtime.toValue(value), true)
self.object.put(name, self.object.runtime.toValue(value), true)
})
return err
}
@ -319,5 +319,5 @@ func (self Object) Set(name string, value interface{}) (error) {
// RegExp
//
func (self Object) Class() string {
return self.object.Class
return self.object.class
}

View File

@ -948,7 +948,7 @@ func TestObjectLiteral(t *testing.T) {
Otto.Run(`
result = { xyzzy: "Nothing happens.", 0: 1 }
`)
Is(Otto.getValue("result")._object().GetValue("xyzzy"), "Nothing happens.")
Is(Otto.getValue("result")._object().get("xyzzy"), "Nothing happens.")
}
func TestArrayLiteral(t *testing.T) {
@ -963,7 +963,7 @@ func TestArrayLiteral(t *testing.T) {
test(`
result = [ "Nothing happens.", 0, 1 ]
`)
Is(test("result")._object().GetValue("0"), "Nothing happens.")
Is(test("result")._object().get("0"), "Nothing happens.")
test(`
xyzzy = [ "Nothing happens.", 0, 1 ]
@ -1554,15 +1554,15 @@ func TestRegExp(t *testing.T) {
test(`""+/abc/gi`, "/abc/gi")
result := test(`/(a)?/.exec('b')`, ",")
Is(result._object().Get("0"), "")
Is(result._object().Get("1"), "undefined")
Is(result._object().Get("length"), "2")
Is(result._object().get("0"), "")
Is(result._object().get("1"), "undefined")
Is(result._object().get("length"), "2")
result = test(`/(a)?(b)?/.exec('b')`, "b,,b")
Is(result._object().Get("0"), "b")
Is(result._object().Get("1"), "undefined")
Is(result._object().Get("2"), "b")
Is(result._object().Get("length"), "3")
Is(result._object().get("0"), "b")
Is(result._object().get("1"), "undefined")
Is(result._object().get("2"), "b")
Is(result._object().get("length"), "3")
test(`/\u0041/.source`, "\\u0041")
test(`/\a/.source`, "\\a")

View File

@ -5,63 +5,62 @@ package otto
type _propertyMode int
const (
propertyModeEmpty _propertyMode = 1
propertyModeWrite = 2
propertyModeEnumerate = 4
propertyModeConfigure = 8
)
const (
propertyModeWriteEnumerateConfigure _propertyMode = propertyModeWrite | propertyModeEnumerate | propertyModeConfigure
propertyModeWrite _propertyMode = 0100
propertyModeEnumerate = 0010
propertyModeConfigure = 0001
)
type _propertyGetSet [2]*_object
type _property struct {
Value interface{}
Mode _propertyMode
Mode _propertyMode
}
func (self _property) CanWrite() bool {
return self.Mode & propertyModeWrite != 0
return self.Mode&propertyModeWrite != 0
}
func (self _property) CanEnumerate() bool {
return self.Mode & propertyModeEnumerate != 0
return self.Mode&propertyModeEnumerate != 0
}
func (self _property) CanConfigure() bool {
return self.Mode & propertyModeConfigure != 0
return self.Mode&propertyModeConfigure != 0
}
func (self _property) toDefineProperty() _defineProperty {
property := _defineProperty{
Value: self.Value,
}
mode := self.Mode
if mode & propertyModeEmpty != 0 {
return property
}
if mode & propertyModeWrite != 0 {
property.Write = propertyAttributeTrue
} else {
property.Write = propertyAttributeFalse
}
if mode & propertyModeEnumerate != 0 {
property.Enumerate = propertyAttributeTrue
} else {
property.Enumerate = propertyAttributeFalse
}
if mode & propertyModeConfigure != 0 {
property.Configure = propertyAttributeTrue
} else {
property.Configure = propertyAttributeFalse
{
mode := self.Mode
if mode&propertyModeWrite != 0 {
property.Write = propertyAttributeTrue
} else {
property.Write = propertyAttributeFalse
}
if mode&propertyModeEnumerate != 0 {
property.Enumerate = propertyAttributeTrue
} else {
property.Enumerate = propertyAttributeFalse
}
if mode&propertyModeConfigure != 0 {
property.Configure = propertyAttributeTrue
} else {
property.Configure = propertyAttributeFalse
}
}
return property
}
func (self *_property) Copy() *_property {
property := *self
func (self _property) Copy() *_property {
property := self
return &property
}
@ -69,7 +68,7 @@ func (self *_property) Copy() *_property {
type _valueProperty struct {
Value Value
Mode _propertyMode
Mode _propertyMode
}
// _defineProperty
@ -83,8 +82,8 @@ const (
)
type _defineProperty struct {
Value interface{}
Write _propertyAttributeBoolean
Value interface{}
Write _propertyAttributeBoolean
Enumerate _propertyAttributeBoolean
Configure _propertyAttributeBoolean
}
@ -130,9 +129,9 @@ func (self _defineProperty) IsGenericDescriptor() bool {
func (self _defineProperty) isEmpty() bool {
return self.IsGenericDescriptor() &&
self.Write == propertyAttributeNotSet &&
self.Enumerate == propertyAttributeNotSet &&
self.Configure == propertyAttributeNotSet
self.Write == propertyAttributeNotSet &&
self.Enumerate == propertyAttributeNotSet &&
self.Configure == propertyAttributeNotSet
}
func (self _defineProperty) CopyInto(other *_property) {
@ -161,4 +160,3 @@ func (self _defineProperty) CopyInto(other *_property) {
other.Value = self.Value
}
}

View File

@ -61,7 +61,7 @@ func (self *_runtime) _executionContext(depth int) *_executionContext {
}
func (self *_runtime) EnterFunctionExecutionContext(function *_object, this Value) *_functionEnvironment {
scopeEnvironment := function.Function.Call.ScopeEnvironment()
scopeEnvironment := function._Function.Call.ScopeEnvironment()
if scopeEnvironment == nil {
scopeEnvironment = self.GlobalEnvironment
}
@ -112,7 +112,7 @@ func (self *_runtime) PutValue(reference _reference, value Value) {
if !reference.PutValue(value) {
// Why? -- If reference.Base == nil
strict := false
self.GlobalObject.WriteValue(reference.Name(), value, strict)
self.GlobalObject.set(reference.Name(), value, strict)
}
}
@ -173,7 +173,7 @@ func (self *_runtime) Call(function *_object, this Value, argumentList []Value)
}
}()
returnValue = function.Function.Call.Dispatch(_functionEnvironment, self, this, argumentList)
returnValue = function._Function.Call.Dispatch(_functionEnvironment, self, this, argumentList)
return
}
@ -307,9 +307,9 @@ func testObjectCoercible(value Value) (isObject bool, mustCoerce bool) {
func (self *_runtime) toValue(value interface{}) Value {
switch value := value.(type) {
case func(FunctionCall) Value:
return toValue(self.newNativeFunction(value, 0))
return toValue(self.newNativeFunction(value, 0, "nativeFunction"))
case _nativeFunction:
return toValue(self.newNativeFunction(value, 0))
return toValue(self.newNativeFunction(value, 0, "nativeFunction"))
}
return toValue(value)
}

162
stash.go
View File

@ -1,38 +1,44 @@
package otto
type _stash interface {
CanRead(string) bool
Read(string) Value
CanWrite(string) bool
Write(string, Value)
test(string) bool
get(string) Value
property(string) *_property
Delete(string)
Define(string, _defineProperty) bool
Enumerate(func(string))
writeValuePropertyMap(map[string]_valueProperty)
enumerate(func(string))
canPut(string) bool
put(string, Value)
set(string, Value, _propertyMode)
define(string, _defineProperty) bool
delete(string)
extensible() bool
lock()
unlock()
}
type _propertyStash struct {
canCreate bool
propertyMap map[string]*_property
type _objectStash struct {
_extensible bool
propertyMap map[string]_property
}
func newPropertyStash(canCreate bool) *_propertyStash {
return &_propertyStash{
canCreate: canCreate,
propertyMap: make(map[string]*_property),
func newObjectStash(extensible bool) *_objectStash {
return &_objectStash{
_extensible: extensible,
propertyMap: make(map[string]_property),
}
}
func (self *_propertyStash) CanRead(name string) bool {
func (self *_objectStash) test(name string) bool {
_, exists := self.propertyMap[name]
return exists
}
func (self *_propertyStash) Read(name string) Value {
property := self.propertyMap[name]
func (self *_objectStash) get(name string) Value {
property, exists := self.propertyMap[name]
if property == nil {
if !exists {
return UndefinedValue()
}
@ -49,10 +55,34 @@ func (self *_propertyStash) Read(name string) Value {
panic(hereBeDragons())
}
func (self *_propertyStash) CanWrite(name string) bool {
property, _ := self.propertyMap[name]
func (self *_objectStash) property(name string) *_property {
property, exists := self.propertyMap[name]
if !exists {
return nil
}
return &property
}
func (self _objectStash) index(name string) (_property, bool) {
property := self.property(name)
if property == nil {
return self.canCreate
return _property{}, false
}
return *property, true
}
func (self *_objectStash) enumerate(each func(string)) {
for name, property := range self.propertyMap {
if property.CanEnumerate() {
each(name)
}
}
}
func (self *_objectStash) canPut(name string) bool {
property, exists := self.propertyMap[name]
if !exists {
return self.extensible()
}
switch propertyValue := property.Value.(type) {
case Value:
@ -63,45 +93,40 @@ func (self *_propertyStash) CanWrite(name string) bool {
panic(hereBeDragons())
}
func (self *_propertyStash) Write(name string, value Value) {
property_, _ := self.propertyMap[name]
if property_ != nil {
switch propertyValue := property_.Value.(type) {
func (self *_objectStash) put(name string, value Value) {
property, exists := self.propertyMap[name]
if exists {
switch propertyValue := property.Value.(type) {
case Value:
if property_.CanWrite() {
property_.Value = value
if property.CanWrite() {
property.Value = value
self.propertyMap[name] = property
}
case _propertyGetSet:
if propertyValue[1] != nil {
propertyValue[1].CallSet(name, value)
}
}
} else if self.canCreate {
self.propertyMap[name] = &_property{ value, propertyModeWriteEnumerateConfigure }
} else if self.extensible() {
self.propertyMap[name] = _property{value, 0111} // Write, Enumerate, Configure
}
}
func (self *_propertyStash) property(name string) *_property {
property, _ := self.propertyMap[name]
return property
func (self *_objectStash) set(name string, value Value, mode _propertyMode) {
self.propertyMap[name] = _property{value, mode}
}
func (self *_propertyStash) Delete(name string) {
delete(self.propertyMap, name)
}
func (self *_propertyStash) Define(name string, define _defineProperty) bool {
canCreate := self.canCreate
property_, _ := self.propertyMap[name]
if property_ == nil {
if !canCreate {
// FIME This is wrong, and doesn't work like you think
func (self *_objectStash) define(name string, define _defineProperty) bool {
property, exists := self.index(name)
if !exists {
if !self.extensible() {
return false
}
property_ = &_property{
self.propertyMap[name] = _property{
Value: define.Value,
Mode: define.Mode(),
Mode: define.Mode(),
}
self.propertyMap[name] = property_
return true
}
if define.isEmpty() {
@ -111,31 +136,33 @@ func (self *_propertyStash) Define(name string, define _defineProperty) bool {
// TODO Per 8.12.9.6 - We should shortcut here (returning true) if
// the current and new (define) properties are the same
canConfigure := property_.CanConfigure()
// TODO Use the other stash methods so we write to special properties properly?
canConfigure := property.CanConfigure()
if !canConfigure {
if define.CanConfigure() {
return false
}
if define.Enumerate != propertyAttributeNotSet && define.CanEnumerate() != property_.CanEnumerate() {
if define.Enumerate != propertyAttributeNotSet && define.CanEnumerate() != property.CanEnumerate() {
return false
}
}
value, isDataDescriptor := property_.Value.(Value)
getSet, _ := property_.Value.(_propertyGetSet)
value, isDataDescriptor := property.Value.(Value)
getSet, _ := property.Value.(_propertyGetSet)
if define.IsGenericDescriptor() {
; // GenericDescriptor
// GenericDescriptor
} else if isDataDescriptor != define.IsDataDescriptor() {
var interface_ interface{}
if isDataDescriptor {
property_.Mode = property_.Mode & ^propertyModeWrite
property_.Value = interface_
property.Mode = property.Mode & ^propertyModeWrite
property.Value = interface_
} else {
property_.Mode |= propertyModeWrite
property_.Value = interface_
property.Mode |= propertyModeWrite
property.Value = interface_
}
} else if isDataDescriptor && define.IsDataDescriptor() {
if !canConfigure {
if property_.CanWrite() != define.CanWrite() {
if property.CanWrite() != define.CanWrite() {
return false
} else if !sameValue(value, define.Value.(Value)) {
return false
@ -149,20 +176,23 @@ func (self *_propertyStash) Define(name string, define _defineProperty) bool {
}
}
}
define.CopyInto(property_)
define.CopyInto(&property)
self.propertyMap[name] = property
return true
}
func (self *_propertyStash) Enumerate(each func(string)) {
for name, property_ := range self.propertyMap {
if property_.CanEnumerate() {
each(name)
}
}
func (self *_objectStash) delete(name string) {
delete(self.propertyMap, name)
}
func (self *_propertyStash) writeValuePropertyMap(valuePropertyMap map[string]_valueProperty) {
for name, _valueProperty := range valuePropertyMap {
self.propertyMap[name] = &_property{ Value: _valueProperty.Value, Mode: _valueProperty.Mode }
}
func (self _objectStash) extensible() bool {
return self._extensible
}
func (self *_objectStash) lock() {
self._extensible = false
}
func (self *_objectStash) unlock() {
self._extensible = true
}

View File

@ -8,19 +8,19 @@ import (
func TestStash(t *testing.T) {
Terst(t)
stash := newPropertyStash(true)
IsTrue(stash.CanWrite("xyzzy"))
stash := newObjectStash(true)
IsTrue(stash.canPut("xyzzy"))
stash.Define("xyzzy", _defineProperty{
stash.define("xyzzy", _defineProperty{
Value: toValue("Nothing happens."),
})
IsTrue(stash.CanRead("xyzzy"))
IsTrue(stash.CanWrite("xyzzy"))
IsTrue(stash.test("xyzzy"))
IsTrue(stash.canPut("xyzzy"))
stash.Define("xyzzy", _defineProperty{
stash.define("xyzzy", _defineProperty{
Value: toValue("Something else happens."),
Write: propertyAttributeFalse,
})
IsTrue(stash.CanRead("xyzzy"))
IsFalse(stash.CanWrite("xyzzy"))
IsTrue(stash.test("xyzzy"))
IsFalse(stash.canPut("xyzzy"))
}

View File

@ -2,14 +2,14 @@ package otto
func (runtime *_runtime) newArgumentsObject(argumentList []Value) *_object {
self := runtime.newClassObject("Arguments")
self.Prototype = runtime.Global.ObjectPrototype
self.prototype = runtime.Global.ObjectPrototype
for index, value := range argumentList {
// TODO Write test for runtime.GetValue(value)
// The problem here is possible reference nesting, is this the right place to GetValue?
self.WriteValue(arrayIndexToString(uint(index)), runtime.GetValue(value), false)
self.set(arrayIndexToString(uint(index)), runtime.GetValue(value), false)
}
self.DefineOwnProperty("length", _property{Value: toValue(len(argumentList)), Mode: propertyModeWrite | propertyModeConfigure}.toDefineProperty(), false)
self.stash.set("length", toValue(len(argumentList)), 0101)
return self
}

View File

@ -6,8 +6,8 @@ import (
func (runtime *_runtime) newArrayObject(valueArray []Value) *_object {
self := runtime.newObject()
self.Class = "Array"
self._propertyStash = newArrayStash(valueArray, self._propertyStash)
self.class = "Array"
self.stash = newArrayStash(valueArray, self.stash)
return self
}
@ -26,7 +26,7 @@ func newArrayStash(valueArray []Value, stash _stash) *_arrayStash {
return self
}
func (self *_arrayStash) CanWrite(name string) bool {
func (self *_arrayStash) canPut(name string) bool {
// length
if name == "length" {
return true
@ -38,10 +38,10 @@ func (self *_arrayStash) CanWrite(name string) bool {
return true
}
return self._stash.CanWrite(name)
return self._stash.canPut(name)
}
func (self *_arrayStash) CanRead(name string) bool {
func (self *_arrayStash) test(name string) bool {
// length
if name == "length" {
return true
@ -53,10 +53,10 @@ func (self *_arrayStash) CanRead(name string) bool {
return index < int64(len(self.valueArray)) && self.valueArray[index]._valueType != valueEmpty
}
return self._stash.CanRead(name)
return self._stash.test(name)
}
func (self *_arrayStash) Read(name string) Value {
func (self *_arrayStash) get(name string) Value {
// length
if name == "length" {
return toValue(len(self.valueArray))
@ -74,10 +74,10 @@ func (self *_arrayStash) Read(name string) Value {
return UndefinedValue()
}
return self._stash.Read(name)
return self._stash.get(name)
}
func (self *_arrayStash) Write(name string, value Value) {
func (self *_arrayStash) put(name string, value Value) {
// length
if name == "length" {
value := uint(toUI32(value))
@ -109,7 +109,7 @@ func (self *_arrayStash) Write(name string, value Value) {
return
}
self._stash.Write(name, value)
self._stash.put(name, value)
}
func (self *_arrayStash) property(name string) *_property {
@ -130,14 +130,14 @@ func (self *_arrayStash) property(name string) *_property {
}
return &_property{
Value: value,
Mode: propertyModeWriteEnumerateConfigure, // +Write +Enumerate +Configure
Mode: 0111, // +Write +Enumerate +Configure
}
}
return self._stash.property(name)
}
func (self *_arrayStash) Enumerate(each func(string)) {
func (self *_arrayStash) enumerate(each func(string)) {
// .0, .1, .2, ...
for index, _ := range self.valueArray {
if self.valueArray[index]._valueType == valueEmpty {
@ -146,5 +146,5 @@ func (self *_arrayStash) Enumerate(each func(string)) {
name := strconv.FormatInt(int64(index), 10)
each(name)
}
self._stash.Enumerate(each)
self._stash.enumerate(each)
}

View File

@ -110,19 +110,19 @@ func timeToEpoch(time tme.Time) float64 {
func (runtime *_runtime) newDateObject(epoch float64) *_object {
self := runtime.newObject()
self.Class = "Date"
self.class = "Date"
// TODO Fix this, redundant arguments, etc.
self.Date = &_dateObject{}
self.Date.Set(epoch)
self._Date = &_dateObject{}
self._Date.Set(epoch)
return self
}
func dateObjectOf(_dateObject *_object) *_dateObject {
if _dateObject == nil || _dateObject.Class != "Date" {
if _dateObject == nil || _dateObject.class != "Date" {
panic(newTypeError())
}
return _dateObject.Date
return _dateObject._Date
}
// JavaScript is 0-based, Go is 1-based (15.9.1.4)

View File

@ -3,7 +3,7 @@ package otto
func (runtime *_runtime) newErrorObject(message Value) *_object {
self := runtime.newClassObject("Error")
if message.IsDefined() {
self.WriteValue("message", toValue(toString(message)), false)
self.set("message", toValue(toString(message)), false)
}
return self
}

View File

@ -8,28 +8,28 @@ type _functionObject struct {
Construct _constructFunction
}
func (runtime *_runtime) newNativeFunctionObject(native _nativeFunction, length int) *_object {
func (runtime *_runtime) newNativeFunctionObject(native _nativeFunction, length int, name string) *_object {
self := runtime.newClassObject("Function")
self.Function = &_functionObject{
Call: newNativeCallFunction(native),
self._Function = &_functionObject{
Call: newNativeCallFunction(native, name),
Construct: defaultConstructFunction,
}
self.DefineOwnProperty("length", _property{Mode: 0, Value: toValue(length)}.toDefineProperty(), false)
self.stash.set("length", toValue(length), _propertyMode(0))
return self
}
func (runtime *_runtime) newNodeFunctionObject(node *_functionNode, scopeEnvironment _environment) *_object {
self := runtime.newClassObject("Function")
self.Function = &_functionObject{
self._Function = &_functionObject{
Call: newNodeCallFunction(node, scopeEnvironment),
Construct: defaultConstructFunction,
}
self.DefineOwnValueProperty("length", toValue(len(node.ParameterList)), 0 /* -Write -Configure -Enumerate */, false)
self.stash.set("length", toValue(len(node.ParameterList)), _propertyMode(0))
return self
}
func (self *_object) Call(this Value, argumentList... interface{}) Value {
if self.Function == nil {
if self._Function == nil {
panic(newTypeError("%v is not a function", toValue(self)))
}
return self.runtime.Call(self, this, toValueArray(argumentList...))
@ -37,21 +37,20 @@ func (self *_object) Call(this Value, argumentList... interface{}) Value {
}
func (self *_object) Construct(this Value, argumentList... interface{}) Value {
if self.Function == nil {
if self._Function == nil {
panic(newTypeError("%v is not a function", toValue(self)))
}
return self.Function.Construct(self, this, toValueArray(argumentList...))
return self._Function.Construct(self, this, toValueArray(argumentList...))
}
func defaultConstructFunction(self *_object, this Value, argumentList []Value) Value {
newObject := self.runtime.newObject()
newObject.Class = "Object"
newObject.Extensible = true
prototypeValue := self.Get("prototype")
newObject.class = "Object"
prototypeValue := self.get("prototype")
if !prototypeValue.IsObject() {
prototypeValue = toValue(self.runtime.Global.ObjectPrototype)
}
newObject.Prototype = prototypeValue._object()
newObject.prototype = prototypeValue._object()
newObjectValue := toValue(newObject)
result := self.Call(newObjectValue, argumentList)
if result.IsObject() {
@ -73,11 +72,11 @@ func (self *_object) HasInstance(of Value) bool {
if !of.IsObject() {
panic(newTypeError())
}
prototype := self.Get("prototype")
prototype := self.get("prototype")
if !prototype.IsObject() {
panic(newTypeError())
}
ofPrototype := of._object().Prototype
ofPrototype := of._object().prototype
if ofPrototype == nil {
return false
}
@ -96,37 +95,34 @@ type _callFunction interface {
Dispatch(*_functionEnvironment, *_runtime, Value, []Value) Value
Source() string
ScopeEnvironment() _environment
Sign(_functionSignature)
Signature() _functionSignature
name() string
}
type _callFunctionBase struct {
type _callFunction_ struct {
scopeEnvironment _environment // Can be either Lexical or Variable
signature _functionSignature
_name string
}
func (self _callFunctionBase) ScopeEnvironment() _environment {
func (self _callFunction_) ScopeEnvironment() _environment {
return self.scopeEnvironment
}
func (self *_callFunctionBase) Sign(signature _functionSignature) {
self.signature = signature
}
func (self _callFunctionBase) Signature() _functionSignature {
return self.signature
func (self _callFunction_) name() string {
return self._name
}
// _nativeCallFunction
type _nativeCallFunction struct {
_callFunctionBase
_callFunction_
Native _nativeFunction
}
func newNativeCallFunction(native _nativeFunction) *_nativeCallFunction {
return &_nativeCallFunction{
func newNativeCallFunction(native _nativeFunction, name string) *_nativeCallFunction {
self := &_nativeCallFunction{
Native: native,
}
self._callFunction_._name = name
return self
}
func (self _nativeCallFunction) Dispatch(_ *_functionEnvironment, runtime *_runtime, this Value, argumentList []Value) Value {
@ -143,7 +139,7 @@ func (self _nativeCallFunction) Source() string {
// _nodeCallFunction
type _nodeCallFunction struct {
_callFunctionBase
_callFunction_
node *_functionNode
}
@ -190,7 +186,7 @@ func (self *FunctionCall) thisObject() *_object {
func (self *FunctionCall) thisClassObject(class string) *_object {
thisObject := self.thisObject()
if thisObject.Class != class {
if thisObject.class != class {
panic(newTypeError())
}
return self._thisObject

View File

@ -53,11 +53,11 @@ func (self *_argumentReference) GetBase() *_object {
}
func (self *_argumentReference) GetValue() Value {
return self.Base.GetValue(self.name)
return self.Base.get(self.name)
}
func (self *_argumentReference) PutValue(value Value) bool {
self.Base.WriteValue(self.name, value, self._referenceBase.strict)
self.Base.set(self.name, value, self._referenceBase.strict)
return true
}
@ -86,14 +86,14 @@ func (self *_objectReference) GetValue() Value {
if self.Base == nil {
panic(newReferenceError("notDefined", self.name, self.node))
}
return self.Base.GetValue(self.name)
return self.Base.get(self.name)
}
func (self *_objectReference) PutValue(value Value) bool {
if self.Base == nil {
return false
}
self.Base.WriteValue(self.name, value, self.Strict())
self.Base.set(self.name, value, self.Strict())
return true
}
@ -101,7 +101,7 @@ func (self *_objectReference) Delete() {
if self.Base == nil {
return
}
self.Base.Delete(self.name, self.Strict())
self.Base.delete(self.name, self.Strict())
}
type _primitiveReference struct {
@ -130,11 +130,11 @@ func (self *_primitiveReference) baseAsObject() *_object {
}
func (self *_primitiveReference) GetValue() Value {
return self.baseAsObject().GetValue(self.name)
return self.baseAsObject().get(self.name)
}
func (self *_primitiveReference) PutValue(value Value) bool {
self.baseAsObject().WriteValue(self.name, value, self.Strict())
self.baseAsObject().set(self.name, value, self.Strict())
return true
}

View File

@ -17,7 +17,7 @@ type _regExpObject struct {
func (runtime *_runtime) newRegExpObject(pattern string, flags string) *_object {
self := runtime.newObject()
self.Class = "RegExp"
self.class = "RegExp"
global := false
ignoreCase := false
@ -50,7 +50,7 @@ func (runtime *_runtime) newRegExpObject(pattern string, flags string) *_object
re2pattern = fmt.Sprintf("(?%s:%s)", re2flags, re2pattern)
}
self.RegExp = &_regExpObject{
self._RegExp = &_regExpObject{
RegularExpression: regexp.MustCompile(re2pattern),
Global: global,
IgnoreCase: ignoreCase,
@ -58,29 +58,29 @@ func (runtime *_runtime) newRegExpObject(pattern string, flags string) *_object
Source: pattern,
LastIndex: toValue(0),
}
self._propertyStash = newRegExpStash(self.RegExp, self._propertyStash)
self.stash = newRegExpStash(self._RegExp, self.stash)
return self
}
func execRegExp(this *_object, target string) (match bool, result []int) {
lastIndex := toInteger(this.Get("lastIndex"))
lastIndex := toInteger(this.get("lastIndex"))
index := lastIndex
global := toBoolean(this.Get("global"))
global := toBoolean(this.get("global"))
if !global {
index = 0
}
if 0 > index || index > int64(len(target)) {
} else {
result = this.RegExp.RegularExpression.FindStringSubmatchIndex(target[index:])
result = this._RegExp.RegularExpression.FindStringSubmatchIndex(target[index:])
}
if result == nil {
this.WriteValue("lastIndex", toValue(0), true)
this.set("lastIndex", toValue(0), true)
return // !match
}
match = true
endIndex := result[len(result)-1]
if global {
this.WriteValue("lastIndex", toValue(endIndex), true)
this.set("lastIndex", toValue(endIndex), true)
}
return // match
}
@ -230,15 +230,15 @@ func newRegExpStash(_regExpObject *_regExpObject, stash _stash) *_regExpStash {
return self
}
func (self *_regExpStash) CanRead(name string) bool {
func (self *_regExpStash) test(name string) bool {
switch name {
case "global", "ignoreCase", "multiline", "lastIndex", "source":
return true
}
return self._stash.CanRead(name)
return self._stash.test(name)
}
func (self *_regExpStash) Read(name string) Value {
func (self *_regExpStash) get(name string) Value {
switch name {
case "global":
return toValue(self._regExpObject.Global)
@ -251,10 +251,10 @@ func (self *_regExpStash) Read(name string) Value {
case "source":
return toValue(self._regExpObject.Source)
}
return self._stash.Read(name)
return self._stash.get(name)
}
func (self *_regExpStash) Write(name string, value Value) {
func (self *_regExpStash) put(name string, value Value) {
switch name {
case "global", "ignoreCase", "multiline", "source":
// TODO Is this good enough? Check DefineOwnProperty
@ -263,7 +263,7 @@ func (self *_regExpStash) Write(name string, value Value) {
self._regExpObject.LastIndex = value
return
}
self._stash.Write(name, value)
self._stash.put(name, value)
}
func (self *_regExpStash) property(name string) *_property {
@ -282,7 +282,7 @@ func (self *_regExpStash) property(name string) *_property {
return self._stash.property(name)
}
func (self *_regExpStash) Enumerate(each func(string)) {
func (self *_regExpStash) enumerate(each func(string)) {
// Skip global, ignoreCase, multiline, source, & lastIndex
self._stash.Enumerate(each)
self._stash.enumerate(each)
}

View File

@ -6,7 +6,7 @@ import (
func (runtime *_runtime) newStringObject(value Value) *_object {
self := runtime.newPrimitiveObject("String", toValue(toString(value)))
self._propertyStash = newStringStash(toString(value), self._propertyStash)
self.stash = newStringStash(toString(value), self.stash)
return self
}
@ -23,7 +23,7 @@ func newStringStash(value string, stash _stash) *_stringStash {
return self
}
func (self *_stringStash) CanRead(name string) bool {
func (self *_stringStash) test(name string) bool {
// .length
if name == "length" {
return true
@ -35,10 +35,10 @@ func (self *_stringStash) CanRead(name string) bool {
return true
}
return self._stash.CanRead(name)
return self._stash.test(name)
}
func (self *_stringStash) Read(name string) Value {
func (self *_stringStash) get(name string) Value {
// .length
if name == "length" {
return toValue(len(string(self.value)))
@ -50,7 +50,7 @@ func (self *_stringStash) Read(name string) Value {
return toValue(string(self.value[index]))
}
return self._stash.Read(name)
return self._stash.get(name)
}
func (self *_stringStash) property(name string) *_property {
@ -74,11 +74,11 @@ func (self *_stringStash) property(name string) *_property {
return self._stash.property(name)
}
func (self *_stringStash) Enumerate(each func(string)) {
func (self *_stringStash) enumerate(each func(string)) {
// .0, .1, .2, ...
for index, _ := range self.value {
name := strconv.FormatInt(int64(index), 10)
each(name)
}
self._stash.Enumerate(each)
self._stash.enumerate(each)
}

View File

@ -75,7 +75,7 @@ func (value Value) IsNull() bool {
func (value Value) isCallable() bool {
switch value := value.value.(type) {
case *_object:
return value.Function != nil
return value._Function != nil
}
return false
}
@ -157,7 +157,7 @@ func (value Value) IsFunction() bool {
if value._valueType != valueObject {
return false
}
return value.value.(*_object).Class == "Function"
return value.value.(*_object).class == "Function"
}
// Class will return the class string of the value or the empty string if value is not an object.
@ -177,56 +177,56 @@ func (value Value) Class() string {
if value._valueType != valueObject {
return ""
}
return value.value.(*_object).Class
return value.value.(*_object).class
}
func (value Value) isArray() bool {
if value._valueType != valueObject {
return false
}
return value.value.(*_object).Class == "Array"
return value.value.(*_object).class == "Array"
}
func (value Value) isStringObject() bool {
if value._valueType != valueObject {
return false
}
return value.value.(*_object).Class == "String"
return value.value.(*_object).class == "String"
}
func (value Value) isBooleanObject() bool {
if value._valueType != valueObject {
return false
}
return value.value.(*_object).Class == "Boolean"
return value.value.(*_object).class == "Boolean"
}
func (value Value) isNumberObject() bool {
if value._valueType != valueObject {
return false
}
return value.value.(*_object).Class == "Number"
return value.value.(*_object).class == "Number"
}
func (value Value) isDate() bool {
if value._valueType != valueObject {
return false
}
return value.value.(*_object).Class == "Date"
return value.value.(*_object).class == "Date"
}
func (value Value) isRegExp() bool {
if value._valueType != valueObject {
return false
}
return value.value.(*_object).Class == "RegExp"
return value.value.(*_object).class == "RegExp"
}
func (value Value) isError() bool {
if value._valueType != valueObject {
return false
}
return value.value.(*_object).Class == "Error"
return value.value.(*_object).class == "Error"
}
// ---