178 lines
4.8 KiB
Go
178 lines
4.8 KiB
Go
|
package goja
|
||
|
|
||
|
import "github.com/dop251/goja/unistring"
|
||
|
|
||
|
var (
|
||
|
SymHasInstance = newSymbol(asciiString("Symbol.hasInstance"))
|
||
|
SymIsConcatSpreadable = newSymbol(asciiString("Symbol.isConcatSpreadable"))
|
||
|
SymIterator = newSymbol(asciiString("Symbol.iterator"))
|
||
|
SymMatch = newSymbol(asciiString("Symbol.match"))
|
||
|
SymMatchAll = newSymbol(asciiString("Symbol.matchAll"))
|
||
|
SymReplace = newSymbol(asciiString("Symbol.replace"))
|
||
|
SymSearch = newSymbol(asciiString("Symbol.search"))
|
||
|
SymSpecies = newSymbol(asciiString("Symbol.species"))
|
||
|
SymSplit = newSymbol(asciiString("Symbol.split"))
|
||
|
SymToPrimitive = newSymbol(asciiString("Symbol.toPrimitive"))
|
||
|
SymToStringTag = newSymbol(asciiString("Symbol.toStringTag"))
|
||
|
SymUnscopables = newSymbol(asciiString("Symbol.unscopables"))
|
||
|
)
|
||
|
|
||
|
func (r *Runtime) builtin_symbol(call FunctionCall) Value {
|
||
|
var desc String
|
||
|
if arg := call.Argument(0); !IsUndefined(arg) {
|
||
|
desc = arg.toString()
|
||
|
}
|
||
|
return newSymbol(desc)
|
||
|
}
|
||
|
|
||
|
func (r *Runtime) symbolproto_tostring(call FunctionCall) Value {
|
||
|
sym, ok := call.This.(*Symbol)
|
||
|
if !ok {
|
||
|
if obj, ok := call.This.(*Object); ok {
|
||
|
if v, ok := obj.self.(*primitiveValueObject); ok {
|
||
|
if sym1, ok := v.pValue.(*Symbol); ok {
|
||
|
sym = sym1
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if sym == nil {
|
||
|
panic(r.NewTypeError("Method Symbol.prototype.toString is called on incompatible receiver"))
|
||
|
}
|
||
|
return sym.descriptiveString()
|
||
|
}
|
||
|
|
||
|
func (r *Runtime) symbolproto_valueOf(call FunctionCall) Value {
|
||
|
_, ok := call.This.(*Symbol)
|
||
|
if ok {
|
||
|
return call.This
|
||
|
}
|
||
|
|
||
|
if obj, ok := call.This.(*Object); ok {
|
||
|
if v, ok := obj.self.(*primitiveValueObject); ok {
|
||
|
if sym, ok := v.pValue.(*Symbol); ok {
|
||
|
return sym
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
panic(r.NewTypeError("Symbol.prototype.valueOf requires that 'this' be a Symbol"))
|
||
|
}
|
||
|
|
||
|
func (r *Runtime) symbol_for(call FunctionCall) Value {
|
||
|
key := call.Argument(0).toString()
|
||
|
keyStr := key.string()
|
||
|
if v := r.symbolRegistry[keyStr]; v != nil {
|
||
|
return v
|
||
|
}
|
||
|
if r.symbolRegistry == nil {
|
||
|
r.symbolRegistry = make(map[unistring.String]*Symbol)
|
||
|
}
|
||
|
v := newSymbol(key)
|
||
|
r.symbolRegistry[keyStr] = v
|
||
|
return v
|
||
|
}
|
||
|
|
||
|
func (r *Runtime) symbol_keyfor(call FunctionCall) Value {
|
||
|
arg := call.Argument(0)
|
||
|
sym, ok := arg.(*Symbol)
|
||
|
if !ok {
|
||
|
panic(r.NewTypeError("%s is not a symbol", arg.String()))
|
||
|
}
|
||
|
for key, s := range r.symbolRegistry {
|
||
|
if s == sym {
|
||
|
return stringValueFromRaw(key)
|
||
|
}
|
||
|
}
|
||
|
return _undefined
|
||
|
}
|
||
|
|
||
|
func (r *Runtime) thisSymbolValue(v Value) *Symbol {
|
||
|
if sym, ok := v.(*Symbol); ok {
|
||
|
return sym
|
||
|
}
|
||
|
if obj, ok := v.(*Object); ok {
|
||
|
if pVal, ok := obj.self.(*primitiveValueObject); ok {
|
||
|
if sym, ok := pVal.pValue.(*Symbol); ok {
|
||
|
return sym
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
panic(r.NewTypeError("Value is not a Symbol"))
|
||
|
}
|
||
|
|
||
|
func (r *Runtime) createSymbolProto(val *Object) objectImpl {
|
||
|
o := &baseObject{
|
||
|
class: classObject,
|
||
|
val: val,
|
||
|
extensible: true,
|
||
|
prototype: r.global.ObjectPrototype,
|
||
|
}
|
||
|
o.init()
|
||
|
|
||
|
o._putProp("constructor", r.getSymbol(), true, false, true)
|
||
|
o.setOwnStr("description", &valueProperty{
|
||
|
configurable: true,
|
||
|
getterFunc: r.newNativeFunc(func(call FunctionCall) Value {
|
||
|
return r.thisSymbolValue(call.This).desc
|
||
|
}, "get description", 0),
|
||
|
accessor: true,
|
||
|
}, false)
|
||
|
o._putProp("toString", r.newNativeFunc(r.symbolproto_tostring, "toString", 0), true, false, true)
|
||
|
o._putProp("valueOf", r.newNativeFunc(r.symbolproto_valueOf, "valueOf", 0), true, false, true)
|
||
|
o._putSym(SymToPrimitive, valueProp(r.newNativeFunc(r.symbolproto_valueOf, "[Symbol.toPrimitive]", 1), false, false, true))
|
||
|
o._putSym(SymToStringTag, valueProp(newStringValue("Symbol"), false, false, true))
|
||
|
|
||
|
return o
|
||
|
}
|
||
|
|
||
|
func (r *Runtime) createSymbol(val *Object) objectImpl {
|
||
|
o := r.newNativeFuncAndConstruct(val, r.builtin_symbol, func(args []Value, newTarget *Object) *Object {
|
||
|
panic(r.NewTypeError("Symbol is not a constructor"))
|
||
|
}, r.getSymbolPrototype(), "Symbol", _positiveZero)
|
||
|
|
||
|
o._putProp("for", r.newNativeFunc(r.symbol_for, "for", 1), true, false, true)
|
||
|
o._putProp("keyFor", r.newNativeFunc(r.symbol_keyfor, "keyFor", 1), true, false, true)
|
||
|
|
||
|
for _, s := range []*Symbol{
|
||
|
SymHasInstance,
|
||
|
SymIsConcatSpreadable,
|
||
|
SymIterator,
|
||
|
SymMatch,
|
||
|
SymMatchAll,
|
||
|
SymReplace,
|
||
|
SymSearch,
|
||
|
SymSpecies,
|
||
|
SymSplit,
|
||
|
SymToPrimitive,
|
||
|
SymToStringTag,
|
||
|
SymUnscopables,
|
||
|
} {
|
||
|
n := s.desc.(asciiString)
|
||
|
n = n[len("Symbol."):]
|
||
|
o._putProp(unistring.String(n), s, false, false, false)
|
||
|
}
|
||
|
|
||
|
return o
|
||
|
}
|
||
|
|
||
|
func (r *Runtime) getSymbolPrototype() *Object {
|
||
|
ret := r.global.SymbolPrototype
|
||
|
if ret == nil {
|
||
|
ret = &Object{runtime: r}
|
||
|
r.global.SymbolPrototype = ret
|
||
|
ret.self = r.createSymbolProto(ret)
|
||
|
}
|
||
|
return ret
|
||
|
}
|
||
|
|
||
|
func (r *Runtime) getSymbol() *Object {
|
||
|
ret := r.global.Symbol
|
||
|
if ret == nil {
|
||
|
ret = &Object{runtime: r}
|
||
|
r.global.Symbol = ret
|
||
|
ret.self = r.createSymbol(ret)
|
||
|
}
|
||
|
return ret
|
||
|
}
|