Skip to content

Commit

Permalink
finish up first working version of js and py compatible DynamicObj
Browse files Browse the repository at this point in the history
  • Loading branch information
HLWeil committed Aug 20, 2024
1 parent 897c049 commit 71078db
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 75 deletions.
2 changes: 1 addition & 1 deletion src/DynamicObj/DynObj.fs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ module DynObj =
dyn.TryGetValue name

let remove (dyn:DynamicObj) propName =
DynamicObj.Remove (dyn, propName) |> ignore
DynamicObj.remove (dyn, propName) |> ignore

let format (d:DynamicObj) =

Expand Down
19 changes: 13 additions & 6 deletions src/DynamicObj/DynamicObj.fs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ type DynamicObj() =
// Next check for Public properties via Reflection
| _ -> ReflectionUtils.tryGetPropertyValue this name


member this.GetValue (name) =
this.TryGetValue(name).Value

/// Gets property value
member this.TryGetTypedValue<'a> name =
Expand Down Expand Up @@ -65,7 +68,8 @@ type DynamicObj() =
#endif
#if FABLE_COMPILER_PYTHON
FablePy.setPropertyValue this name value
#else
#endif
#if !FABLE_COMPILER
// Next check the Properties collection for member
match properties.TryGetValue name with
| true,_ -> properties.[name] <- value
Expand All @@ -91,7 +95,8 @@ type DynamicObj() =
|> Seq.filter (fun pd ->
includeInstanceProperties || pd.IsDynamic
)
#else
#endif
#if !FABLE_COMPILER
seq [
if includeInstanceProperties then
yield! ReflectionUtils.getStaticProperties (this)
Expand Down Expand Up @@ -132,7 +137,8 @@ type DynamicObj() =
else
None
)
#else
#endif
#if !FABLE_COMPILER
seq [
if includeInstanceProperties then
for prop in ReflectionUtils.getStaticProperties (this) ->
Expand Down Expand Up @@ -170,10 +176,11 @@ type DynamicObj() =
// this.CopyDynamicPropertiesTo(target)
// target

static member GetValue (lookup:DynamicObj,name) =
lookup.TryGetValue(name).Value

static member Remove (lookup:DynamicObj,name) =
static member getValue (lookup:DynamicObj,name) =
lookup.GetValue(name)

static member remove (lookup:DynamicObj,name) =
lookup.Remove(name)

override this.Equals o =
Expand Down
192 changes: 126 additions & 66 deletions src/DynamicObj/FablePy.fs
Original file line number Diff line number Diff line change
Expand Up @@ -6,67 +6,102 @@ open System.Collections.Generic

module FablePy =

module Dictionary =

let ofSeq (s:seq<KeyValuePair<_,_>>) =
let d = new System.Collections.Generic.Dictionary<_,_>()
s |> Seq.iter (fun kv -> d.Add(kv.Key, kv.Value))
d

let choose (f: 'T -> 'U option) (d:System.Collections.Generic.Dictionary<_,'T>) =
let nd = new System.Collections.Generic.Dictionary<_,'U>()
for kv in d do
match f kv.Value with
| Some v -> nd.Add(kv.Key, v)
| None -> ()
nd

type PropertyObject =
abstract fget : obj
abstract fset : obj

module PropertyObject =

[<Emit("$0.fget")>]
let tryGetGetter (o:PropertyObject) : obj option =
let tryGetGetter (o:PropertyObject) : (obj -> obj) option =
nativeOnly

[<Emit("$0.fset")>]
let tryGetSetter (o:PropertyObject) : obj option =
let tryGetSetter (o:PropertyObject) : (obj -> obj -> unit) option =
nativeOnly

let containsGetter (o:obj) : bool =
let getGetter (o : PropertyObject) : obj -> obj =
match tryGetGetter o with
| Some f -> f
| None -> fun o -> failwith ("Property does not contain getter")

let getSetter (o:PropertyObject) : obj -> obj -> unit =
match tryGetSetter o with
| Some f -> f
| None -> fun s o -> failwith ("Property does not contain setter")

let containsGetter (o:PropertyObject) : bool =
match tryGetGetter o with
| Some _ -> true
| None -> false

let containsSetter (o:obj) : bool =
let containsSetter (o:PropertyObject) : bool =
match tryGetSetter o with
| Some _ -> true
| None -> false

let isWritable (o:obj) : bool =
let isWritable (o:PropertyObject) : bool =
containsSetter o

[<Emit("isinstance($0, property)")>]
let isProperty (o:obj) : bool =
nativeOnly

[<Emit("vars($0)")>]
let getOwnMemberObjects (o:obj) : Dictionary<string,obj> =
nativeOnly
let tryProperty (o:obj) : PropertyObject option =
if isProperty o then
Some (o :?> PropertyObject)
else
None

[<Emit("$0.__class__")>]
let getClass (o:obj) : obj =
[<Emit("getattr($0,$1)")>]
let getPropertyValue (o:obj) (propName:string) =
nativeOnly

let getOwnPropertyObjects (o:obj) : Dictionary<string,obj> =
getOwnMemberObjects o



let getStaticPropertyObjects (o:obj) =
getClass o
|> getOwnPropertyNames
|> Array.filter (fun n -> n <> "constructor")
let createGetter (propName:string) =
fun (o:obj) ->
getPropertyValue o propName

[<Emit("$0.$1 = $2")>]
let setPropertyValue (o:obj) (propName:string) (value:obj) =
[<Emit("setattr($0,$1,$2)")>]
let setPropertyValue (o:obj) (propName:string) (value:obj) : unit =
nativeOnly

let createSetter (propName:string) =
fun (o:obj) (value:obj) ->
setPropertyValue o propName value


[<Emit("vars($0).items()")>]
let getOwnMemberObjects (o:obj) : Dictionary<string,obj> =
nativeOnly

[<Emit("$0.__class__")>]
let getClass (o:obj) : obj =
nativeOnly

let getStaticPropertyObjects (o:obj) : Dictionary<string,PropertyObject> =
getClass o
|> getOwnMemberObjects
|> Dictionary.choose PropertyObject.tryProperty

let removeStaticPropertyValue (o:obj) (propName:string) =
setPropertyValue o propName null

[<Emit("delete $0[$1]")>]
[<Emit("delattr($0,$1)")>]
let deleteDynamicPropertyValue (o:obj) (propName:string) =
nativeOnly

Expand All @@ -79,67 +114,92 @@ module FablePy =
deleteDynamicPropertyValue o propName


[<Emit("$0[$1]")>]
let getPropertyValue (o:obj) (propName:string) =
nativeOnly

let createGetter (propName:string) =
fun (o:obj) ->
getPropertyValue o propName

[<Emit("Object.getOwnPropertyDescriptor($0, $1)")>]
let getPropertyDescriptor (o:obj) (propName:string) =
[<Emit("$0.__dict__[$1]")>]
let getMemberObject (o:obj) (propName:string) =
nativeOnly

let getStaticPropertyDescriptor (o:obj) (propName:string) =
getPropertyDescriptor (getPrototype o) propName

let getStaticPropertyHelpers (o:obj) : PropertyHelper [] =
getStaticPropertyNames o
|> Array.choose (fun n ->
let pd = getStaticPropertyDescriptor o n
if PropertyDescriptor.isFunction pd then
None
else
let isWritable = PropertyDescriptor.isWritable pd
{
Name = n
IsStatic = true
IsDynamic = false
IsMutable = isWritable
IsImmutable = not isWritable
GetValue = createGetter n
SetValue = createSetter n
RemoveValue = createRemover n true
}
|> Some
)

let transpiledPropertyRegex = "^[a-zA-Z]+@[0-9]+$"
let tryGetPropertyObject (o:obj) (propName:string) : PropertyObject option =
match PropertyObject.tryProperty (getMemberObject o propName) with
| Some po -> Some po
| None -> None

let tryGetDynamicPropertyHelper (o:obj) (propName:string) : PropertyHelper option =
match getMemberObject o propName with
| Some _ ->
Some {
Name = propName
IsStatic = false
IsDynamic = true
IsMutable = true
IsImmutable = false
GetValue = createGetter propName
SetValue = createSetter propName
RemoveValue = fun o -> deleteDynamicPropertyValue o propName
}
| None -> None

let tryGetStaticPropertyHelper (o:obj) (propName:string) : PropertyHelper option =
match tryGetPropertyObject (getClass o) propName with
| Some po ->
let isWritable = PropertyObject.isWritable po
Some {
Name = propName
IsStatic = true
IsDynamic = false
IsMutable = isWritable
IsImmutable = not isWritable
GetValue = createGetter propName
SetValue = createSetter propName
RemoveValue = fun o -> removeStaticPropertyValue o propName
}
| None -> None

let transpiledPropertyRegex = "^[a-zA-Z]+_[0-9]+$"

let isTranspiledPropertyHelper (propertyName : string) =
System.Text.RegularExpressions.Regex.IsMatch(propertyName, transpiledPropertyRegex)


let getDynamicPropertyHelpers (o:obj) : PropertyHelper [] =
getOwnPropertyNames o
|> Array.choose (fun n ->
let pd = getPropertyDescriptor o n
if PropertyDescriptor.isFunction pd || isTranspiledPropertyHelper n then
getOwnMemberObjects o
|> Seq.choose (fun kv ->
let n = kv.Key
if isTranspiledPropertyHelper n then
None
else
let isWritable = PropertyDescriptor.isWritable pd
else
{
Name = n
IsStatic = false
IsDynamic = true
IsMutable = isWritable
IsImmutable = not isWritable
IsMutable = true
IsImmutable = false
GetValue = createGetter n
SetValue = createSetter n
RemoveValue = createRemover n false
}
RemoveValue = fun o -> deleteDynamicPropertyValue o n
}
|> Some
)
|> Seq.toArray


let getStaticPropertyHelpers (o:obj) : PropertyHelper [] =
getStaticPropertyObjects o
|> Seq.map (fun kv ->
let n = kv.Key
let po = kv.Value
{
Name = n
IsStatic = true
IsDynamic = false
IsMutable = PropertyObject.isWritable po
IsImmutable = not (PropertyObject.isWritable po)
GetValue = createGetter n
SetValue = createSetter n
RemoveValue = fun o -> removeStaticPropertyValue o n
}
)
|> Seq.toArray

let getPropertyHelpers (o:obj) =
getDynamicPropertyHelpers o
Expand Down
6 changes: 4 additions & 2 deletions src/DynamicObj/ReflectionUtils.fs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ module ReflectionUtils =
#endif
#if FABLE_COMPILER_PYTHON
FablePy.getStaticPropertyHelpers o
#else
#endif
#if !FABLE_COMPILER
let t = o.GetType()
[|
for propInfo in t.GetProperties() -> propInfo
Expand All @@ -29,7 +30,8 @@ module ReflectionUtils =
#endif
#if FABLE_COMPILER_PYTHON
FablePy.getPropertyHelpers o
#else
#endif
#if !FABLE_COMPILER
getStaticProperties (o)
#endif
|> Array.tryFind (fun n -> n.Name = propName)
Expand Down

0 comments on commit 71078db

Please sign in to comment.