Skip to content

Commit

Permalink
feat: ClrProxy WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
LazuliKao committed Aug 2, 2023
1 parent 48ad84b commit 01a7718
Show file tree
Hide file tree
Showing 19 changed files with 1,229 additions and 32 deletions.
4 changes: 4 additions & 0 deletions src/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ internal class ConfigModules

[JsonPropertyName(FileIoModuleName)]
public bool FileIo { get; set; } = true;
public const string ClrModuleName = "@hosihikari/clr";

[JsonPropertyName(ClrModuleName)]
public bool AllowClr { get; set; } = true;
}

internal static ConfigData Data { get; private set; }
Expand Down
4 changes: 4 additions & 0 deletions src/Loader/SetupContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,9 @@ internal static void SetupContext(JsContextWrapper ctx)
{
Modules.IO.Main.Setup(ctx);
}
if (Config.Data.BuildInModules.AllowClr)
{
Modules.Clr.Main.Setup(ctx);
}
}
}
195 changes: 195 additions & 0 deletions src/Modules/Clr/Main.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
using System.Reflection;
using Hosihikari.VanillaScript.QuickJS;
using Hosihikari.VanillaScript.QuickJS.Extensions;
using Hosihikari.VanillaScript.QuickJS.Extensions.Check;
using Hosihikari.VanillaScript.QuickJS.Helper;
using Hosihikari.VanillaScript.QuickJS.Types;
using Hosihikari.VanillaScript.QuickJS.Wrapper;
using Hosihikari.VanillaScript.QuickJS.Wrapper.Reflect;

namespace Hosihikari.VanillaScript.Modules.Clr;

internal class Main
{
public static void Setup(JsContextWrapper ctx)
{
var module = ctx.NewModule(Config.ConfigModules.ClrModuleName);
ClrModule.Setup(ctx, module);
}
}

internal class ClrModule
{
public static void Setup(JsContextWrapper ctx, JsModuleDefWrapper module)
{
module.AddExportFunction(
"clrUsingStatic",
2,
(_, _, argv) =>
{
argv.InsureArgumentCount(2);
argv[0].InsureTypeString(ctx, out var assemblyName);
argv[1].InsureTypeString(ctx, out var type);
return ctx.NewObject(new StaticTypeProxy(assemblyName, type)).Steal();
}
);
module.AddExportFunction(
"getAllLoadedAssemblyName",
0,
(_, _, argv) =>
{
argv.InsureArgumentCount(0);
//filter null
return ctx.NewArray(
from x in TypeFinder.EnumAllAssemblies()
select x.GetName().Name into x
where !string.IsNullOrWhiteSpace(x)
select x
)
.Steal();
}
);
module.AddExportFunction(
"getAllTypesFromAssembly",
1,
(_, _, argv) =>
{
argv.InsureArgumentCount(1);
argv[0].InsureTypeString(ctx, out var assemblyName);
//filter null
return ctx.NewArray(
from x in TypeFinder.EnumAllType(assemblyName)
select x.FullName into x
where !string.IsNullOrWhiteSpace(x)
select x
)
.Steal();
}
);
}
}

internal class StaticTypeProxy : ClrProxyBase, IDisposable
{
public Type? Type { get; }
private readonly Lazy<StaticFunctionFinder> _staticFunctionFinder;
public StaticFunctionFinder FunctionFinder => _staticFunctionFinder.Value;

public StaticTypeProxy(string assemblyName, string type)
{
Type = new TypeFinder(assemblyName).FindType(type);
_staticFunctionFinder = new Lazy<StaticFunctionFinder>(
() => new StaticFunctionFinder(Type)
);
}

public void Dispose()
{
OnDispose?.Invoke();
}

public event Action? OnDispose;

protected override JsPropertyEnum[] GetOwnPropertyNames(JsContextWrapper ctxInstance) =>
FunctionFinder
.EnumStaticMembers()
.Select(
member =>
new JsPropertyEnum
{
Atom = ctxInstance.NewAtom(member.Name).Steal(),
IsEnumerable = false //todo what is this?
}
)
.ToArray();

protected override bool GetOwnProperty(
JsContextWrapper ctxInstance,
out JsPropertyDescriptor data,
JsAtom propName
)
{
var name = propName.ToString(ctxInstance);
if (!FunctionFinder.TryFindMember(name, out var member))
{
data = default;
return false;
}
//MethodInfo
if (member is MethodInfo method)
{ //todo fix this
data = new JsPropertyDescriptor
{
Flags = JsPropertyFlags.HasGet,
Getter = ctxInstance
.NewJsFunctionObject(
(_, thisObj, argv) =>
{
Log.Logger.Trace("get");
//todo impl
return JsValueCreateHelper.NewInt32(233);
}
)
.Steal(),
};
Log.Logger.Trace("method");
return true;
}
if (member is PropertyInfo property)
{
data = new JsPropertyDescriptor { Flags = JsPropertyFlags.Normal };
if (property.GetMethod is { } getMethod)
{
data.Flags |= JsPropertyFlags.HasGet;
data.Getter = ctxInstance
.NewJsFunctionObject(
(_, thisObj, argv) =>
{
Log.Logger.Trace("get");
//todo impl
return JsValueCreateHelper.Undefined;
}
)
.Steal();
}
if (property.SetMethod is { } setMethod)
{
data.Flags |= JsPropertyFlags.HasSet;
data.Setter = ctxInstance
.NewJsFunctionObject(
(_, thisObj, argv) =>
{
Log.Logger.Trace("set");
//todo impl
return JsValueCreateHelper.Undefined;
}
)
.Steal();
}
return true;
}
if (member is FieldInfo field)
{
var value = field.GetValue(null);
data = new JsPropertyDescriptor
{
Flags = JsPropertyFlags.HasValue,
Value = JsValueCreateHelper.New(value, ctxInstance).Steal()
};
return true;
}
throw new NotImplementedException($"member type {member.Name}:{member.GetType()} not impl");
}

protected override JsValue Invoke(
JsContextWrapper ctxInstance,
JsValue thisVal,
ReadOnlySpan<JsValue> argv,
JsCallFlag flags
)
{
return ctxInstance.ThrowJsError(
new InvalidOperationException("call static type not allowed")
);
}
}
4 changes: 2 additions & 2 deletions src/QuickJS/Extensions/Check/ArgumentCheckExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@ public static void InsureArgumentCount(this ReadOnlySpan<JsValue> @this, int cou
/// <param name="this"></param>
/// <param name="allAllowCount"></param>
/// <exception cref="ArgumentException"></exception>
public static void InsureArgumentCount(
public static int InsureArgumentCount(
this ReadOnlySpan<JsValue> @this,
params int[] allAllowCount
)
{
if (allAllowCount.Contains(@this.Length))
{
return;
return @this.Length;
}
throw new ArgumentException(
$"too many arguments, expected {string.Join(" or ", allAllowCount)}, got {@this.Length}"
Expand Down
28 changes: 28 additions & 0 deletions src/QuickJS/Extensions/JsAtomExtension.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using Hosihikari.VanillaScript.QuickJS.Types;
using Hosihikari.VanillaScript.QuickJS.Wrapper;

namespace Hosihikari.VanillaScript.QuickJS.Extensions;

public static class JsAtomExtension
{
public static unsafe string ToString(this JsAtom atom, JsContext* ctx)
{
return Native.JS_AtomToCString(ctx, atom);
}

public static string ToString(this JsAtom atom, JsContextWrapper ctx)
{
unsafe
{
return Native.JS_AtomToCString(ctx.Context, atom);
}
}

public static unsafe void UnsafeRemoveRefCount(this JsAtom atom, JsContext* ctx)
{
if (atom != default)
{
Native.JS_FreeAtom(ctx, atom);
}
}
}
83 changes: 81 additions & 2 deletions src/QuickJS/Helper/JsValueCreateHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ private static JsValue MkVal(JsTag tag, int val)
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool NewUnmanagedInternal<T>(T val, [NotNullWhen(true)] out JsValue? jsValue)
private static bool NewUnmanagedInternal(object? val, [NotNullWhen(true)] out JsValue? jsValue)
{
//match all unmanaged types
jsValue = val switch
Expand All @@ -35,6 +35,32 @@ private static bool NewUnmanagedInternal<T>(T val, [NotNullWhen(true)] out JsVal
float f => NewFloat64(f),
double d => NewFloat64(d),
decimal dec => NewFloat64((double)dec),
null => Null,
_ => null
};
return jsValue is not null;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool NewUnmanagedInternal<T>(T? val, [NotNullWhen(true)] out JsValue? jsValue)
{
//match all unmanaged types
jsValue = val switch
{
bool b => NewBool(b),
char c => NewCatchOffset(c),
byte b => NewInt32(b),
sbyte sb => NewInt32(sb),
short s => NewInt32(s),
ushort us => NewInt32(us),
int i => NewInt32(i),
uint ui => NewUint32(ui),
long l => NewInt64(l),
ulong ul => NewFloat64(ul),
float f => NewFloat64(f),
double d => NewFloat64(d),
decimal dec => NewFloat64((double)dec),
null => Null,
_ => null
};
return jsValue is not null;
Expand All @@ -47,6 +73,12 @@ public static bool NewUnmanaged<T>(T val, [NotNullWhen(true)] out JsValue? jsVal
return NewUnmanagedInternal(val, out jsValue);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool NewUnmanaged(object val, [NotNullWhen(true)] out JsValue? jsValue)
{
return NewUnmanagedInternal(val, out jsValue);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static JsValue NewUnmanaged<T>(T val)
where T : unmanaged
Expand All @@ -59,7 +91,48 @@ public static JsValue NewUnmanaged<T>(T val)
throw new NotImplementedException($"new {typeof(T)} is not support");
}

public static unsafe AutoDropJsValue New<T>(T val, JsContext* ctx)
public static AutoDropJsValue New(object? val, JsContextWrapper ctx)
{
unsafe
{
return New(val, ctx.Context);
}
}

public static AutoDropJsValue New<T>(T? val, JsContextWrapper ctx)
{
unsafe
{
return New(val, ctx.Context);
}
}

public static unsafe AutoDropJsValue New(object? val, JsContext* ctx)
{
if (NewUnmanagedInternal(val, out var jsValue))
{
return new AutoDropJsValue(jsValue.Value, ctx);
}
return val switch
{
string s => NewString(ctx, s),
string[] ss => NewArray(ctx, ss),
byte[] cc => NewArray(ctx, cc),
sbyte[] sb => NewArray(ctx, sb),
short[] ss => NewArray(ctx, ss),
ushort[] us => NewArray(ctx, us),
int[] ii => NewArray(ctx, ii),
uint[] ui => NewArray(ctx, ui),
long[] ll => NewArray(ctx, ll),
ulong[] ul => NewArray(ctx, ul),
float[] ff => NewArray(ctx, ff),
double[] dd => NewArray(ctx, dd),
decimal[] dec => NewArray(ctx, dec),
_ => throw new NotImplementedException($"new {val.GetType()} is not support")
};
}

public static unsafe AutoDropJsValue New<T>(T? val, JsContext* ctx)
{
if (NewUnmanagedInternal(val, out var jsValue))
{
Expand Down Expand Up @@ -290,6 +363,12 @@ public static unsafe AutoDropJsValue NewObject(JsContext* ctx)
return Native.JS_NewObject(ctx);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe AutoDropJsValue NewObject(JsContext* ctx, JsClassId classId)
{
return Native.JS_NewObjectClass(ctx, classId);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe AutoDropJsValue NewArray(JsContext* ctx)
{
Expand Down
Loading

0 comments on commit 01a7718

Please sign in to comment.