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

Cleanup of stash, property, and object

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

159
global.go
View File

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

View File

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

296
object.go
View File

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

View File

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

View File

@ -289,7 +289,7 @@ func (self Object) Value() Value {
func (self Object) Get(name string) (Value, error) { func (self Object) Get(name string) (Value, error) {
result := UndefinedValue() result := UndefinedValue()
err := catchPanic(func(){ err := catchPanic(func(){
result = self.object.Get(name) result = self.object.get(name)
}) })
return result, err 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. // or there is an error during conversion of the given value.
func (self Object) Set(name string, value interface{}) (error) { func (self Object) Set(name string, value interface{}) (error) {
err := catchPanic(func(){ 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 return err
} }
@ -319,5 +319,5 @@ func (self Object) Set(name string, value interface{}) (error) {
// RegExp // RegExp
// //
func (self Object) Class() string { func (self Object) Class() string {
return self.object.Class return self.object.class
} }

View File

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

View File

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

View File

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

162
stash.go
View File

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

View File

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

View File

@ -2,14 +2,14 @@ package otto
func (runtime *_runtime) newArgumentsObject(argumentList []Value) *_object { func (runtime *_runtime) newArgumentsObject(argumentList []Value) *_object {
self := runtime.newClassObject("Arguments") self := runtime.newClassObject("Arguments")
self.Prototype = runtime.Global.ObjectPrototype self.prototype = runtime.Global.ObjectPrototype
for index, value := range argumentList { for index, value := range argumentList {
// TODO Write test for runtime.GetValue(value) // TODO Write test for runtime.GetValue(value)
// The problem here is possible reference nesting, is this the right place to GetValue? // 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 return self
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -75,7 +75,7 @@ func (value Value) IsNull() bool {
func (value Value) isCallable() bool { func (value Value) isCallable() bool {
switch value := value.value.(type) { switch value := value.value.(type) {
case *_object: case *_object:
return value.Function != nil return value._Function != nil
} }
return false return false
} }
@ -157,7 +157,7 @@ func (value Value) IsFunction() bool {
if value._valueType != valueObject { if value._valueType != valueObject {
return false 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. // 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 { if value._valueType != valueObject {
return "" return ""
} }
return value.value.(*_object).Class return value.value.(*_object).class
} }
func (value Value) isArray() bool { func (value Value) isArray() bool {
if value._valueType != valueObject { if value._valueType != valueObject {
return false return false
} }
return value.value.(*_object).Class == "Array" return value.value.(*_object).class == "Array"
} }
func (value Value) isStringObject() bool { func (value Value) isStringObject() bool {
if value._valueType != valueObject { if value._valueType != valueObject {
return false return false
} }
return value.value.(*_object).Class == "String" return value.value.(*_object).class == "String"
} }
func (value Value) isBooleanObject() bool { func (value Value) isBooleanObject() bool {
if value._valueType != valueObject { if value._valueType != valueObject {
return false return false
} }
return value.value.(*_object).Class == "Boolean" return value.value.(*_object).class == "Boolean"
} }
func (value Value) isNumberObject() bool { func (value Value) isNumberObject() bool {
if value._valueType != valueObject { if value._valueType != valueObject {
return false return false
} }
return value.value.(*_object).Class == "Number" return value.value.(*_object).class == "Number"
} }
func (value Value) isDate() bool { func (value Value) isDate() bool {
if value._valueType != valueObject { if value._valueType != valueObject {
return false return false
} }
return value.value.(*_object).Class == "Date" return value.value.(*_object).class == "Date"
} }
func (value Value) isRegExp() bool { func (value Value) isRegExp() bool {
if value._valueType != valueObject { if value._valueType != valueObject {
return false return false
} }
return value.value.(*_object).Class == "RegExp" return value.value.(*_object).class == "RegExp"
} }
func (value Value) isError() bool { func (value Value) isError() bool {
if value._valueType != valueObject { if value._valueType != valueObject {
return false return false
} }
return value.value.(*_object).Class == "Error" return value.value.(*_object).class == "Error"
} }
// --- // ---