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:
parent
c1a21812fe
commit
3c93384f5c
|
|
@ -8,6 +8,8 @@ WITH_otto := --command "$(otto)"
|
|||
test:
|
||||
$(TEST) $(WITH_otto)
|
||||
|
||||
release: otto gauntlet
|
||||
|
||||
test-otto: test
|
||||
|
||||
otto: build
|
||||
|
|
|
|||
194
builtin.go
194
builtin.go
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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
159
global.go
|
|
@ -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)))
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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
296
object.go
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
|
|
|
|||
6
otto.go
6
otto.go
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
18
otto_test.go
18
otto_test.go
|
|
@ -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")
|
||||
|
|
|
|||
76
property.go
76
property.go
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
10
runtime.go
10
runtime.go
|
|
@ -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
162
stash.go
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
10
type_date.go
10
type_date.go
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
20
value.go
20
value.go
|
|
@ -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"
|
||||
}
|
||||
|
||||
// ---
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user