package goja
import (
"reflect"
)
var mapExportType = reflect .TypeOf ([][2 ]interface {}{})
type mapObject struct {
baseObject
m *orderedMap
}
type mapIterObject struct {
baseObject
iter *orderedMapIter
kind iterationKind
}
func (o *mapIterObject ) next () Value {
if o .iter == nil {
return o .val .runtime .createIterResultObject (_undefined , true )
}
entry := o .iter .next ()
if entry == nil {
o .iter = nil
return o .val .runtime .createIterResultObject (_undefined , true )
}
var result Value
switch o .kind {
case iterationKindKey :
result = entry .key
case iterationKindValue :
result = entry .value
default :
result = o .val .runtime .newArrayValues ([]Value {entry .key , entry .value })
}
return o .val .runtime .createIterResultObject (result , false )
}
func (mo *mapObject ) init () {
mo .baseObject .init ()
mo .m = newOrderedMap (mo .val .runtime .getHash ())
}
func (mo *mapObject ) exportType () reflect .Type {
return mapExportType
}
func (mo *mapObject ) export (ctx *objectExportCtx ) interface {} {
m := make ([][2 ]interface {}, mo .m .size )
ctx .put (mo .val , m )
iter := mo .m .newIter ()
for i := 0 ; i < len (m ); i ++ {
entry := iter .next ()
if entry == nil {
break
}
m [i ][0 ] = exportValue (entry .key , ctx )
m [i ][1 ] = exportValue (entry .value , ctx )
}
return m
}
func (mo *mapObject ) exportToMap (dst reflect .Value , typ reflect .Type , ctx *objectExportCtx ) error {
dst .Set (reflect .MakeMap (typ ))
ctx .putTyped (mo .val , typ , dst .Interface ())
keyTyp := typ .Key ()
elemTyp := typ .Elem ()
iter := mo .m .newIter ()
r := mo .val .runtime
for {
entry := iter .next ()
if entry == nil {
break
}
keyVal := reflect .New (keyTyp ).Elem ()
err := r .toReflectValue (entry .key , keyVal , ctx )
if err != nil {
return err
}
elemVal := reflect .New (elemTyp ).Elem ()
err = r .toReflectValue (entry .value , elemVal , ctx )
if err != nil {
return err
}
dst .SetMapIndex (keyVal , elemVal )
}
return nil
}
func (r *Runtime ) mapProto_clear (call FunctionCall ) Value {
thisObj := r .toObject (call .This )
mo , ok := thisObj .self .(*mapObject )
if !ok {
panic (r .NewTypeError ("Method Map.prototype.clear called on incompatible receiver %s" , r .objectproto_toString (FunctionCall {This : thisObj })))
}
mo .m .clear ()
return _undefined
}
func (r *Runtime ) mapProto_delete (call FunctionCall ) Value {
thisObj := r .toObject (call .This )
mo , ok := thisObj .self .(*mapObject )
if !ok {
panic (r .NewTypeError ("Method Map.prototype.delete called on incompatible receiver %s" , r .objectproto_toString (FunctionCall {This : thisObj })))
}
return r .toBoolean (mo .m .remove (call .Argument (0 )))
}
func (r *Runtime ) mapProto_get (call FunctionCall ) Value {
thisObj := r .toObject (call .This )
mo , ok := thisObj .self .(*mapObject )
if !ok {
panic (r .NewTypeError ("Method Map.prototype.get called on incompatible receiver %s" , r .objectproto_toString (FunctionCall {This : thisObj })))
}
return nilSafe (mo .m .get (call .Argument (0 )))
}
func (r *Runtime ) mapProto_has (call FunctionCall ) Value {
thisObj := r .toObject (call .This )
mo , ok := thisObj .self .(*mapObject )
if !ok {
panic (r .NewTypeError ("Method Map.prototype.has called on incompatible receiver %s" , r .objectproto_toString (FunctionCall {This : thisObj })))
}
if mo .m .has (call .Argument (0 )) {
return valueTrue
}
return valueFalse
}
func (r *Runtime ) mapProto_set (call FunctionCall ) Value {
thisObj := r .toObject (call .This )
mo , ok := thisObj .self .(*mapObject )
if !ok {
panic (r .NewTypeError ("Method Map.prototype.set called on incompatible receiver %s" , r .objectproto_toString (FunctionCall {This : thisObj })))
}
mo .m .set (call .Argument (0 ), call .Argument (1 ))
return call .This
}
func (r *Runtime ) mapProto_entries (call FunctionCall ) Value {
return r .createMapIterator (call .This , iterationKindKeyValue )
}
func (r *Runtime ) mapProto_forEach (call FunctionCall ) Value {
thisObj := r .toObject (call .This )
mo , ok := thisObj .self .(*mapObject )
if !ok {
panic (r .NewTypeError ("Method Map.prototype.forEach called on incompatible receiver %s" , r .objectproto_toString (FunctionCall {This : thisObj })))
}
callbackFn , ok := r .toObject (call .Argument (0 )).self .assertCallable ()
if !ok {
panic (r .NewTypeError ("object is not a function %s" ))
}
t := call .Argument (1 )
iter := mo .m .newIter ()
for {
entry := iter .next ()
if entry == nil {
break
}
callbackFn (FunctionCall {This : t , Arguments : []Value {entry .value , entry .key , thisObj }})
}
return _undefined
}
func (r *Runtime ) mapProto_keys (call FunctionCall ) Value {
return r .createMapIterator (call .This , iterationKindKey )
}
func (r *Runtime ) mapProto_values (call FunctionCall ) Value {
return r .createMapIterator (call .This , iterationKindValue )
}
func (r *Runtime ) mapProto_getSize (call FunctionCall ) Value {
thisObj := r .toObject (call .This )
mo , ok := thisObj .self .(*mapObject )
if !ok {
panic (r .NewTypeError ("Method get Map.prototype.size called on incompatible receiver %s" , r .objectproto_toString (FunctionCall {This : thisObj })))
}
return intToValue (int64 (mo .m .size ))
}
func (r *Runtime ) builtin_newMap (args []Value , newTarget *Object ) *Object {
if newTarget == nil {
panic (r .needNew ("Map" ))
}
proto := r .getPrototypeFromCtor (newTarget , r .global .Map , r .global .MapPrototype )
o := &Object {runtime : r }
mo := &mapObject {}
mo .class = classObject
mo .val = o
mo .extensible = true
o .self = mo
mo .prototype = proto
mo .init ()
if len (args ) > 0 {
if arg := args [0 ]; arg != nil && arg != _undefined && arg != _null {
adder := mo .getStr ("set" , nil )
adderFn := toMethod (adder )
if adderFn == nil {
panic (r .NewTypeError ("Map.set in missing" ))
}
iter := r .getIterator (arg , nil )
i0 := valueInt (0 )
i1 := valueInt (1 )
if adder == r .global .mapAdder {
iter .iterate (func (item Value ) {
itemObj := r .toObject (item )
k := nilSafe (itemObj .self .getIdx (i0 , nil ))
v := nilSafe (itemObj .self .getIdx (i1 , nil ))
mo .m .set (k , v )
})
} else {
iter .iterate (func (item Value ) {
itemObj := r .toObject (item )
k := itemObj .self .getIdx (i0 , nil )
v := itemObj .self .getIdx (i1 , nil )
adderFn (FunctionCall {This : o , Arguments : []Value {k , v }})
})
}
}
}
return o
}
func (r *Runtime ) createMapIterator (mapValue Value , kind iterationKind ) Value {
obj := r .toObject (mapValue )
mapObj , ok := obj .self .(*mapObject )
if !ok {
panic (r .NewTypeError ("Object is not a Map" ))
}
o := &Object {runtime : r }
mi := &mapIterObject {
iter : mapObj .m .newIter (),
kind : kind ,
}
mi .class = classObject
mi .val = o
mi .extensible = true
o .self = mi
mi .prototype = r .getMapIteratorPrototype ()
mi .init ()
return o
}
func (r *Runtime ) mapIterProto_next (call FunctionCall ) Value {
thisObj := r .toObject (call .This )
if iter , ok := thisObj .self .(*mapIterObject ); ok {
return iter .next ()
}
panic (r .NewTypeError ("Method Map Iterator.prototype.next called on incompatible receiver %s" , r .objectproto_toString (FunctionCall {This : thisObj })))
}
func (r *Runtime ) createMapProto (val *Object ) objectImpl {
o := newBaseObjectObj (val , r .global .ObjectPrototype , classObject )
o ._putProp ("constructor" , r .getMap (), true , false , true )
o ._putProp ("clear" , r .newNativeFunc (r .mapProto_clear , "clear" , 0 ), true , false , true )
r .global .mapAdder = r .newNativeFunc (r .mapProto_set , "set" , 2 )
o ._putProp ("set" , r .global .mapAdder , true , false , true )
o ._putProp ("delete" , r .newNativeFunc (r .mapProto_delete , "delete" , 1 ), true , false , true )
o ._putProp ("forEach" , r .newNativeFunc (r .mapProto_forEach , "forEach" , 1 ), true , false , true )
o ._putProp ("has" , r .newNativeFunc (r .mapProto_has , "has" , 1 ), true , false , true )
o ._putProp ("get" , r .newNativeFunc (r .mapProto_get , "get" , 1 ), true , false , true )
o .setOwnStr ("size" , &valueProperty {
getterFunc : r .newNativeFunc (r .mapProto_getSize , "get size" , 0 ),
accessor : true ,
writable : true ,
configurable : true ,
}, true )
o ._putProp ("keys" , r .newNativeFunc (r .mapProto_keys , "keys" , 0 ), true , false , true )
o ._putProp ("values" , r .newNativeFunc (r .mapProto_values , "values" , 0 ), true , false , true )
entriesFunc := r .newNativeFunc (r .mapProto_entries , "entries" , 0 )
o ._putProp ("entries" , entriesFunc , true , false , true )
o ._putSym (SymIterator , valueProp (entriesFunc , true , false , true ))
o ._putSym (SymToStringTag , valueProp (asciiString (classMap ), false , false , true ))
return o
}
func (r *Runtime ) createMap (val *Object ) objectImpl {
o := r .newNativeConstructOnly (val , r .builtin_newMap , r .getMapPrototype (), "Map" , 0 )
r .putSpeciesReturnThis (o )
return o
}
func (r *Runtime ) createMapIterProto (val *Object ) objectImpl {
o := newBaseObjectObj (val , r .getIteratorPrototype (), classObject )
o ._putProp ("next" , r .newNativeFunc (r .mapIterProto_next , "next" , 0 ), true , false , true )
o ._putSym (SymToStringTag , valueProp (asciiString (classMapIterator ), false , false , true ))
return o
}
func (r *Runtime ) getMapIteratorPrototype () *Object {
var o *Object
if o = r .global .MapIteratorPrototype ; o == nil {
o = &Object {runtime : r }
r .global .MapIteratorPrototype = o
o .self = r .createMapIterProto (o )
}
return o
}
func (r *Runtime ) getMapPrototype () *Object {
ret := r .global .MapPrototype
if ret == nil {
ret = &Object {runtime : r }
r .global .MapPrototype = ret
ret .self = r .createMapProto (ret )
}
return ret
}
func (r *Runtime ) getMap () *Object {
ret := r .global .Map
if ret == nil {
ret = &Object {runtime : r }
r .global .Map = ret
ret .self = r .createMap (ret )
}
return ret
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .