Browse Source

Exception support and generator fixes

Krzysztof Krysiński 1 year ago
parent
commit
b8ddee2778

+ 0 - 1
src/PixiEditor.Extensions.Wasm/build/PixiEditor.Extensions.Wasm.targets

@@ -1,7 +1,6 @@
 <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
 <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
   <ItemGroup>
     <_WasiFilePathForFixup Include="$(MSBuildThisFileDirectory)..\native\*.c" />
     <_WasiFilePathForFixup Include="$(MSBuildThisFileDirectory)..\native\*.c" />
-    <!--<WasiAfterRuntimeLoaded Include="attach_internal_calls" />-->
   </ItemGroup>
   </ItemGroup>
 
 
  <!-- <Target Name="GenerateLayouts" AfterTargets="Build" Inputs="bin\Debug\$(TargetFramework)\PixiEditor.Extensions.Wasm.dll" Outputs="$(RootFolder)\Layouts\">
  <!-- <Target Name="GenerateLayouts" AfterTargets="Build" Inputs="bin\Debug\$(TargetFramework)\PixiEditor.Extensions.Wasm.dll" Outputs="$(RootFolder)\Layouts\">

+ 4 - 1
src/PixiEditor.Extensions.Wasm/native/api_interop.c

@@ -37,7 +37,10 @@ void invoke_interop_method(MonoMethod* method, void* params)
 {
 {
     MonoObject* exception = NULL;
     MonoObject* exception = NULL;
     MonoObject* res = mono_runtime_invoke(method, NULL, params, &exception);
     MonoObject* res = mono_runtime_invoke(method, NULL, params, &exception);
-    assert(!exception);
+    if(exception != NULL)
+    {
+        mono_print_unhandled_exception(exception);
+    }
 
 
     free(exception);
     free(exception);
     free(method);
     free(method);

+ 4 - 1
src/PixiEditor.Extensions.WasmRuntime/ApiGroupHandler.cs → src/PixiEditor.Extensions.WasmRuntime/Api/ApiGroupHandler.cs

@@ -1,7 +1,8 @@
 using PixiEditor.Extensions.FlyUI.Elements;
 using PixiEditor.Extensions.FlyUI.Elements;
 using PixiEditor.Extensions.WasmRuntime.Management;
 using PixiEditor.Extensions.WasmRuntime.Management;
+using Wasmtime;
 
 
-namespace PixiEditor.Extensions.WasmRuntime;
+namespace PixiEditor.Extensions.WasmRuntime.Api;
 
 
 // This is a "dummy" class, all properties and methods are never actually used or set, it is used to tell code generators the implementation of the API
 // This is a "dummy" class, all properties and methods are never actually used or set, it is used to tell code generators the implementation of the API
 // Compiler will convert all functions with [ApiFunction] attribute to an actual WASM linker function
 // Compiler will convert all functions with [ApiFunction] attribute to an actual WASM linker function
@@ -10,4 +11,6 @@ internal class ApiGroupHandler
     public ExtensionServices Api { get; }
     public ExtensionServices Api { get; }
     protected LayoutBuilder LayoutBuilder { get; }
     protected LayoutBuilder LayoutBuilder { get; }
     protected ObjectManager NativeObjectManager { get; }
     protected ObjectManager NativeObjectManager { get; }
+    protected Instance? Instance { get; }
+    protected WasmMemoryUtility WasmMemoryUtility { get; }
 }
 }

+ 36 - 0
src/PixiEditor.Extensions.WasmRuntime/Api/FlyUiApi.cs

@@ -0,0 +1,36 @@
+using Avalonia.Threading;
+using PixiEditor.Extensions.FlyUI.Elements;
+
+namespace PixiEditor.Extensions.WasmRuntime.Api;
+
+internal class FlyUIApi : ApiGroupHandler
+{
+    [ApiFunction("subscribe_to_event")]
+    public void SubscribeToEvent(int controlId, string eventName)
+    {
+        LayoutBuilder.ManagedElements[controlId].AddEvent(eventName, (args) =>
+        {
+            var action = Instance.GetAction<int, int>("raise_element_event");
+            var ptr = WasmMemoryUtility.WriteString(eventName);
+
+            action.Invoke(controlId, ptr);
+            WasmMemoryUtility.Free(ptr);
+        });
+    }
+
+    [ApiFunction("state_changed")]
+    public void StateChanged(int controlId, Span<byte> bodySpan)
+    {
+        var element = LayoutBuilder.ManagedElements[controlId];
+        var body = LayoutBuilder.Deserialize(bodySpan, DuplicateResolutionTactic.ReplaceRemoveChildren);
+
+        Dispatcher.UIThread.InvokeAsync(() =>
+        {
+            LayoutBuilder.ManagedElements[controlId] = element;
+            if (element is StatefulContainer statefulElement && body is StatefulContainer statefulBodyElement)
+            {
+                statefulElement.State.SetState(() => statefulElement.State.Content = statefulBodyElement.State.Content);
+            }
+        });
+    }
+}

+ 10 - 0
src/PixiEditor.Extensions.WasmRuntime/Api/LoggerApi.cs

@@ -0,0 +1,10 @@
+namespace PixiEditor.Extensions.WasmRuntime.Api;
+
+internal class LoggerApi : ApiGroupHandler
+{
+    [ApiFunction("log_message")]
+    public void Log(string message)
+    {
+        Console.WriteLine(message.ReplaceLineEndings());
+    }
+}

+ 1 - 1
src/PixiEditor.Extensions.WasmRuntime/WindowingApi.cs → src/PixiEditor.Extensions.WasmRuntime/Api/WindowingApi.cs

@@ -1,7 +1,7 @@
 using PixiEditor.Extensions.FlyUI.Elements;
 using PixiEditor.Extensions.FlyUI.Elements;
 using PixiEditor.Extensions.Windowing;
 using PixiEditor.Extensions.Windowing;
 
 
-namespace PixiEditor.Extensions.WasmRuntime;
+namespace PixiEditor.Extensions.WasmRuntime.Api;
 
 
 internal class WindowingApi : ApiGroupHandler
 internal class WindowingApi : ApiGroupHandler
 {
 {

+ 1 - 44
src/PixiEditor.Extensions.WasmRuntime/WasmExtensionInstance.cs

@@ -35,7 +35,7 @@ public partial class WasmExtensionInstance : Extension
     public void Instantiate()
     public void Instantiate()
     {
     {
         NativeObjectManager = new ObjectManager();
         NativeObjectManager = new ObjectManager();
-        DefinePixiEditorApi();
+        LinkApiFunctions();
         Linker.DefineModule(Store, Module);
         Linker.DefineModule(Store, Module);
 
 
         Instance = Linker.Instantiate(Store, Module);
         Instance = Linker.Instantiate(Store, Module);
@@ -67,47 +67,4 @@ public partial class WasmExtensionInstance : Extension
 
 
         WasmMemoryUtility.Free(ptr);
         WasmMemoryUtility.Free(ptr);
     }
     }
-
-    private void DefinePixiEditorApi()
-    {
-        LinkApiFunctions();
-        Linker.DefineFunction("env", "log_message", (int messageOffset, int messageLength) =>
-        {
-            string messageString = WasmMemoryUtility.GetString(messageOffset, messageLength);
-            Console.WriteLine(messageString.ReplaceLineEndings());
-        });
-
-        Linker.DefineFunction("env", "subscribe_to_event", (int controlId, int eventNameOffset, int eventNameLengthOffset) =>
-        {
-            string eventName = WasmMemoryUtility.GetString(eventNameOffset, eventNameLengthOffset);
-
-            // TODO: Make sure controlId is actually a id and not wasm memory address
-            LayoutBuilder.ManagedElements[controlId].AddEvent(eventName, (args) =>
-            {
-                var action = Instance.GetAction<int, int>("raise_element_event");
-                var ptr = WasmMemoryUtility.WriteString(eventName);
-
-                action.Invoke(controlId, ptr);
-
-                WasmMemoryUtility.Free(ptr);
-            });
-        });
-
-        Linker.DefineFunction("env", "state_changed", (int controlId, int bodyOffset, int bodyLength) =>
-        {
-            Span<byte> arr = memory.GetSpan<byte>(bodyOffset, bodyLength);
-
-            var element = LayoutBuilder.ManagedElements[controlId];
-            var body = LayoutBuilder.Deserialize(arr, DuplicateResolutionTactic.ReplaceRemoveChildren);
-
-            Dispatcher.UIThread.InvokeAsync(() =>
-            {
-                LayoutBuilder.ManagedElements[controlId] = element;
-                if (element is StatefulContainer statefulElement && body is StatefulContainer statefulBodyElement)
-                {
-                    statefulElement.State.SetState(() => statefulElement.State.Content = statefulBodyElement.State.Content);
-                }
-            });
-        });
-    }
 }
 }

+ 20 - 6
src/PixiEditor.WasmApi.Gen/ApiGenerator.cs

@@ -3,7 +3,6 @@ using System.Diagnostics;
 using Microsoft.CodeAnalysis;
 using Microsoft.CodeAnalysis;
 using Microsoft.CodeAnalysis.CSharp;
 using Microsoft.CodeAnalysis.CSharp;
 using Microsoft.CodeAnalysis.CSharp.Syntax;
 using Microsoft.CodeAnalysis.CSharp.Syntax;
-using PixiEditor.Api.Gen;
 
 
 namespace PixiEditor.WasmApi.Gen;
 namespace PixiEditor.WasmApi.Gen;
 
 
@@ -97,10 +96,17 @@ public class ApiGenerator : IIncrementalGenerator
 
 
         foreach (var argSymbol in arguments)
         foreach (var argSymbol in arguments)
         {
         {
-            string lowerType = argSymbol.Type.Name;
-            bool isLengthType = TypeConversionTable.IsLengthType(argSymbol);
-            string paramsString = isLengthType ? $"{argSymbol.Name}Pointer, {argSymbol.Name}Length" : $"{argSymbol.Name}Pointer";
-            syntaxes = syntaxes.Add(SyntaxFactory.ParseStatement($"{argSymbol.Type.ToDisplayString()} {argSymbol.Name} = WasmMemoryUtility.Get{lowerType}({paramsString});"));
+            // For some reason, int are passed as is, not as a pointer
+            if (!TypeConversionTable.IsIntType(argSymbol.Type))
+            {
+                string lowerType = argSymbol.Type.Name;
+                bool isLengthType = TypeConversionTable.IsLengthType(argSymbol);
+                string paramsString = isLengthType
+                    ? $"{argSymbol.Name}Pointer, {argSymbol.Name}Length"
+                    : $"{argSymbol.Name}Pointer";
+                syntaxes = syntaxes.Add(SyntaxFactory.ParseStatement(
+                    $"{argSymbol.Type.ToDisplayString()} {argSymbol.Name} = WasmMemoryUtility.Get{lowerType}({paramsString});"));
+            }
         }
         }
 
 
         return syntaxes;
         return syntaxes;
@@ -128,7 +134,15 @@ public class ApiGenerator : IIncrementalGenerator
                 else
                 else
                 {
                 {
                     var returnType = method.methodSymbol.ReturnType.Name;
                     var returnType = method.methodSymbol.ReturnType.Name;
-                    syntaxes = syntaxes.Add(SyntaxFactory.ParseStatement($"return WasmMemoryUtility.Write{returnType}({returnStatementSyntax.Expression.ToFullString()});"));
+                    string statementString =
+                        $"return WasmMemoryUtility.Write{returnType}({returnStatementSyntax.Expression.ToFullString()});";
+
+                    if (TypeConversionTable.IsIntType(method.methodSymbol.ReturnType))
+                    {
+                        statementString = $"return {returnStatementSyntax.Expression.ToFullString()};";
+                    }
+
+                    syntaxes = syntaxes.Add(SyntaxFactory.ParseStatement(statementString));
                 }
                 }
             }
             }
         }
         }

+ 7 - 33
src/PixiEditor.WasmApi.Gen/MethodBodyRewriter.cs

@@ -7,50 +7,24 @@ namespace PixiEditor.WasmApi.Gen;
 public class MethodBodyRewriter : CSharpSyntaxRewriter
 public class MethodBodyRewriter : CSharpSyntaxRewriter
 {
 {
     public SemanticModel MethodSemanticModel { get; }
     public SemanticModel MethodSemanticModel { get; }
+
     public MethodBodyRewriter(SemanticModel methodSemanticModel)
     public MethodBodyRewriter(SemanticModel methodSemanticModel)
     {
     {
         MethodSemanticModel = methodSemanticModel;
         MethodSemanticModel = methodSemanticModel;
     }
     }
 
 
-    public override SyntaxNode VisitInvocationExpression(InvocationExpressionSyntax node)
-    {
-        /*var methodSymbol = MethodSemanticModel.GetSymbolInfo(node).Symbol as IMethodSymbol;
-
-        var fullyQualifiedName = methodSymbol.ToDisplayString();
-
-        var newInvocation = SyntaxFactory.ParseExpression($"{fullyQualifiedName}({string.Join(", ", node.ArgumentList.Arguments)})");
-
-        return newInvocation;*/
-
-        return base.VisitInvocationExpression(node);
-    }
 
 
-    public override SyntaxNode VisitMemberAccessExpression(MemberAccessExpressionSyntax node)
+    public override SyntaxNode? VisitIdentifierName(IdentifierNameSyntax node)
     {
     {
-        var memberSymbol = MethodSemanticModel.GetSymbolInfo(node).Symbol;
+        var symbol = MethodSemanticModel.GetSymbolInfo(node).Symbol;
 
 
-        if(memberSymbol.Kind != SymbolKind.Field && memberSymbol.Kind != SymbolKind.Method)
+        if (symbol is not INamedTypeSymbol { Kind: SymbolKind.NamedType, TypeKind: TypeKind.Class or TypeKind.Enum } namedTypeSymbol)
         {
         {
-            return base.VisitMemberAccessExpression(node);
-        }
-
-        string fullyQualifiedName = memberSymbol.ToDisplayString();
-
-        if (memberSymbol is { Kind: SymbolKind.Method, IsStatic: false })
-        {
-            var genericArguments = ((IMethodSymbol)memberSymbol).TypeArguments;
-
-            var genericArgumentsString = genericArguments.Length > 0
-                ? $"<{string.Join(", ", genericArguments.Select(x => x.ToDisplayString()))}>"
-                : string.Empty;
-
-            string caller = node.Expression.ToFullString();
-
-            fullyQualifiedName = $"{caller}.{memberSymbol.Name}{genericArgumentsString}";
+            return base.VisitIdentifierName(node);
         }
         }
 
 
-        var newMemberAccess = SyntaxFactory.ParseExpression(fullyQualifiedName);
+        var newIdentifier = SyntaxFactory.ParseName($"{namedTypeSymbol.ToDisplayString()} ");
 
 
-        return newMemberAccess;
+        return newIdentifier;
     }
     }
 }
 }

+ 14 - 5
src/PixiEditor.WasmApi.Gen/TypeConversionTable.cs

@@ -1,18 +1,22 @@
-using System;
-using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis;
 
 
-namespace PixiEditor.Api.Gen;
+namespace PixiEditor.WasmApi.Gen;
 
 
 public static class TypeConversionTable
 public static class TypeConversionTable
 {
 {
     public static string[] ConvertTypeToFunctionParams(IParameterSymbol symbol)
     public static string[] ConvertTypeToFunctionParams(IParameterSymbol symbol)
     {
     {
+        if(IsIntType(symbol.Type))
+        {
+            return [$"int {symbol.Name}"];
+        }
+
         if(IsLengthType(symbol))
         if(IsLengthType(symbol))
         {
         {
-            return [$"int {symbol.Name}Pointer", $"int {symbol.Name}Length"];
+            return[$"int {symbol.Name}Pointer", $"int {symbol.Name}Length"];
         }
         }
 
 
-        return [$"int {symbol.Name}Pointer"];
+        return[$"int {symbol.Name}Pointer"];
     }
     }
 
 
     public static bool IsLengthType(IParameterSymbol symbol)
     public static bool IsLengthType(IParameterSymbol symbol)
@@ -21,4 +25,9 @@ public static class TypeConversionTable
                || symbol.Type.Name.Equals("byte[]", StringComparison.OrdinalIgnoreCase)
                || symbol.Type.Name.Equals("byte[]", StringComparison.OrdinalIgnoreCase)
                || symbol.Type.Name.Equals("span", StringComparison.OrdinalIgnoreCase);
                || symbol.Type.Name.Equals("span", StringComparison.OrdinalIgnoreCase);
     }
     }
+
+    public static bool IsIntType(ITypeSymbol argSymbol)
+    {
+        return argSymbol.Name.Equals("int32", StringComparison.OrdinalIgnoreCase);
+    }
 }
 }