예제 #1
0
        private static void GenerateGlobal(Context context, OutputBuffer output, ClassDeclarationSyntax @class)
        {
            output.AppendLine($"public static partial class {@class.Identifier}");
            output.AppendLine("{");
            output.AppendLine("\tprivate static JSObject? __js;");
            output.AppendLine();
            output.AppendLine("\tprivate static JSObject _js");
            output.AppendLine("\t{");
            output.AppendLine("\t\tget");
            output.AppendLine("\t\t{");
            output.AppendLine("\t\t\tif (__js == null)");
            output.AppendLine($"\t\t\t\t__js = (JSObject)Runtime.GetGlobalObject(nameof({@class.Identifier}));");
            output.AppendLine();
            output.AppendLine("\t\t\treturn __js;");
            output.AppendLine("\t\t}");
            output.AppendLine("\t}");
            output.AppendLine();

            output.IncreaseIndent();

            foreach (var member in @class.Members)
            {
                GenerateInterfaceMember(context, output, member, true);
            }

            output.DecreaseIndent();

            output.AppendLine("}");
            output.AppendLine();
        }
예제 #2
0
        private static void GenerateAssemblyInitializer(Context context, OutputBuffer output, string directory)
        {
            var assemblyName = Path.GetFileName(directory.TrimEnd(Path.DirectorySeparatorChar));

            output.AppendLine($"namespace {assemblyName}");
            output.AppendLine("{");

            output.IncreaseIndent();
            output.AppendLine("public static class WasmWranglerAssemblyInitializer");
            output.AppendLine("{");

            output.IncreaseIndent();
            output.AppendLine("public static void Initialize()");
            output.AppendLine("{");

            output.IncreaseIndent();
            context.Wrappers.Sort();

            foreach (var wrapper in context.Wrappers)
            {
                output.AppendLine($"{wrapper}.Initialize();");
            }

            output.DecreaseIndent();

            output.AppendLine("}");
            output.DecreaseIndent();

            output.AppendLine("}");
            output.DecreaseIndent();

            output.AppendLine("}");
            output.AppendLine();
        }
예제 #3
0
        private static void WriteAssemblyInitializer(Context context, string directory)
        {
            var outputFile = Path.Combine(directory, "WasmWranglerAssemblyInitializer.g.cs");

            Console.WriteLine($"Wrting AssemblyInitializer => {outputFile}");

            var output = new OutputBuffer();

            output.AppendLine("// <auto-generated />");
            output.AppendLine("#nullable enable");

            GenerateAssemblyInitializer(context, output, directory);

            File.WriteAllText(outputFile, output.ToString());
        }
예제 #4
0
        private static void GenerateInterfaceMember(Context context, OutputBuffer output, MemberDeclarationSyntax member, bool asStatic)
        {
            switch (member)
            {
            case MethodDeclarationSyntax method:
                GenerateMethod(context, output, method, asStatic);
                break;

            case PropertyDeclarationSyntax property:
                GenerateProperty(context, output, property, asStatic);
                break;

            default:
                throw new InvalidOperationException(CreateErrorMessage(member, $"Unexpected member: {member}"));
            }
        }
예제 #5
0
        private static void WriteBinding(Context context, string inputFile)
        {
            var outputFile = Path.Combine(Path.GetDirectoryName(inputFile) !, Path.GetFileNameWithoutExtension(inputFile) + ".g.cs");

            Console.WriteLine($"{inputFile} => {outputFile}");

            var syntaxTree = CSharpSyntaxTree.ParseText(File.ReadAllText(inputFile));

            var output = new OutputBuffer();

            output.AppendLine("// <auto-generated />");
            output.AppendLine("#nullable enable");

            GenerateSyntaxNodes(context, output, syntaxTree.GetRoot().ChildNodes());

            File.WriteAllText(outputFile, output.ToString());
        }
예제 #6
0
        private static void GenerateSyntaxNodes(Context context, OutputBuffer output, IEnumerable <SyntaxNode> nodes)
        {
            foreach (var node in nodes)
            {
                switch (node)
                {
                case ClassDeclarationSyntax classDeclarationSyntax:
                    GenerateClass(context, output, classDeclarationSyntax);
                    break;

                case NamespaceDeclarationSyntax namespaceDeclarationSyntax:
                    output.AppendLine();
                    output.AppendLine($"namespace {namespaceDeclarationSyntax.Name}");
                    output.AppendLine("{");
                    output.IncreaseIndent();

                    context.CurrentNamespace = namespaceDeclarationSyntax.Name.ToString();

                    GenerateSyntaxNodes(context, output, namespaceDeclarationSyntax.Members);

                    context.CurrentNamespace = "";

                    output.DecreaseIndent();
                    output.AppendLine("}");
                    break;

                //case InterfaceDeclarationSyntax interfaceDeclarationSyntax:
                //    GenerateInterface(context, output, interfaceDeclarationSyntax);
                //    break;

                case UsingDirectiveSyntax usingDirectiveSyntax:
                    output.AppendLine(usingDirectiveSyntax.ToString());
                    break;

                default:
                    throw new InvalidOperationException(CreateErrorMessage(node, $"{node.Kind()} was not expected."));
                }
            }
        }
예제 #7
0
        private static void GenerateClass(Context context, OutputBuffer output, ClassDeclarationSyntax @class)
        {
            var classType  = "";
            var implements = new List <string>();

            foreach (var attribute in @class.AttributeLists.Select(x => x.ToString().Trim('[', ']')))
            {
                switch (attribute)
                {
                case "Global":
                    classType = "Global";
                    break;

                case "Wrapper":
                    classType = "Wrapper";
                    break;
                }

                if (attribute.StartsWith("Implements(") && attribute.EndsWith(")"))
                {
                    var implement = attribute.Substring("Implements(".Length, attribute.Length - "Implements(".Length - ")".Length);
                    implements.Add(implement);
                }
            }

            switch (classType)
            {
            case "Global":
                GenerateGlobal(context, output, @class);
                break;

            case "Wrapper":
                GenerateWrapper(context, output, @class, implements);
                break;

            default:
                throw new InvalidOperationException(CreateErrorMessage(@class, $"Unknown class type: {classType}"));
            }
        }
예제 #8
0
        private static void GenerateProperty(Context context, OutputBuffer output, PropertyDeclarationSyntax property, bool asStatic)
        {
            if (property.HasDocumentation())
            {
                output.AppendLine(property.GetDocumentation(output.GetIndent()));
            }

            if (property.AccessorList == null)
            {
                throw new InvalidOperationException(CreateErrorMessage(property, $"AccessorList was expected."));
            }

            string?wrappedType = null;

            foreach (var attribute in property.AttributeLists.Select(x => x.ToString().Trim('[', ']')))
            {
                if (attribute.StartsWith("Wrap(") && attribute.EndsWith(")"))
                {
                    wrappedType = attribute.Substring("Wrap(".Length, attribute.Length - "Wrap(".Length - ")".Length);
                }
            }

            bool canRead  = property.AccessorList.Accessors.Any(x => x.Keyword.ToString() == "get");
            bool canWrite = property.AccessorList.Accessors.Any(x => x.Keyword.ToString() == "set");

            if (canRead && !canWrite) // readonly
            {
                output.Append($"private ");

                if (asStatic)
                {
                    output.Append("static ");
                }

                output.AppendLine($"{property.Type}? _{property.Identifier};");
                output.AppendLine();
            }

            output.Append($"public ");

            if (asStatic)
            {
                output.Append("static ");
            }

            output.AppendLine($"{property.Type} {property.Identifier}");
            output.AppendLine("{");

            if (canRead && canWrite)
            {
                if (wrappedType == null)
                {
                    output.AppendLine($"\tget => _js.GetObjectProperty<{property.Type}>(nameof({property.Identifier}));");
                    output.AppendLine($"\tset => _js.SetObjectProperty(nameof({property.Identifier}), value);");
                }
                else
                {
                    throw new NotImplementedException("Wrap not implemented for read / write properties.");
                }
            }
            else if (canRead && !canWrite) // readonly
            {
                output.Append($"\tget => _{property.Identifier} ?? (_{property.Identifier} = ");

                if (wrappedType == null)
                {
                    output.Append($"_js.GetObjectProperty<{property.Type}>(nameof({property.Identifier}))");
                }
                else
                {
                    output.Append($"new {property.Type}(_js.GetObjectProperty<JSObject>(nameof({property.Identifier})))");
                }

                output.AppendLine(");");
            }

            output.AppendLine("}");
            output.AppendLine();
        }
예제 #9
0
        private static void GenerateMethod(Context context, OutputBuffer output, MethodDeclarationSyntax method, bool asStatic)
        {
            if (method.HasDocumentation())
            {
                output.AppendLine(method.GetDocumentation(output.GetIndent()));
            }

            output.Append($"public ");

            if (asStatic)
            {
                output.Append("static ");
            }

            output.Append($"{method.ReturnType} {method.Identifier}");

            if (method.TypeParameterList != null)
            {
                output.Append(method.TypeParameterList.ToString());
            }

            output.AppendLine(method.ParameterList.ToString());

            if (method.ConstraintClauses.Any())
            {
                output.AppendLine("\t" + method.ConstraintClauses.ToString());
            }

            output.AppendLine("{");

            if (method.ReturnType.ToString() != "void")
            {
                output.Append($"\tvar result = _js.Invoke(nameof({method.Identifier})");

                foreach (var parameter in method.ParameterList.Parameters)
                {
                    output.Append($", {parameter.Identifier}");
                }

                output.AppendLine(");");
                output.AppendLine();
                output.AppendLine("\tif (result == null)");
                output.AppendLine("\t\treturn null;");
                output.AppendLine();

                var returnType = method.ReturnType.ToString();

                if (returnType.EndsWith("?"))
                {
                    returnType = returnType.TrimEnd('?');
                }

                output.AppendLine($"\treturn JSObjectWrapperFactory.Create<{returnType}>(result);");
            }
            else
            {
                output.Append($"\t_js.Invoke(nameof({method.Identifier})");

                foreach (var parameter in method.ParameterList.Parameters)
                {
                    output.Append($", {parameter.Identifier}");
                }

                output.AppendLine(");");
            }

            output.AppendLine("}");
            output.AppendLine();
        }
예제 #10
0
        private static void GenerateWrapper(Context context, OutputBuffer output, ClassDeclarationSyntax @class, List <string> implements)
        {
            context.Wrappers.Add(context.CurrentNamespace + "." + @class.Identifier.ToString());

            output.Append($"public partial class {@class.Identifier}");

            if (@class.BaseList != null || implements.Any())
            {
                output.Append(" : ");

                if (@class.BaseList != null)
                {
                    output.Append(string.Join(", ", @class.BaseList.Types.Select(x => x.ToString())));
                }

                if (implements.Any())
                {
                    // If we already output the BaseList we need to add a ,
                    if (@class.BaseList != null)
                    {
                        output.Append(", ");
                    }

                    output.Append(string.Join(", ", implements));
                }
            }

            output.AppendLine();
            output.AppendLine("{");

            output.Append("\tinternal static ");

            if (@class.BaseList != null)
            {
                output.Append("new ");
            }

            output.AppendLine($"void Initialize() {{ JSObjectWrapperFactory.RegisterFactory(typeof({@class.Identifier}), x => new {@class.Identifier}(x)); }}");
            output.AppendLine();

            if (@class.BaseList == null)
            {
                output.AppendLine("\tprotected readonly JSObject _js;");
                output.AppendLine();
                output.AppendLine($"\tinternal {@class.Identifier}(object obj)");
                output.AppendLine("\t{");
                output.AppendLine("\t\tif (!(obj is JSObject))");
                output.AppendLine("\t\t\tthrow new WasmWranglerException($\"Expected {nameof(obj)} to be an instance of JSObject.\");");
                output.AppendLine();
                output.AppendLine("\t\t_js = (JSObject)obj;");
                output.AppendLine("\t}");
            }
            else
            {
                output.AppendLine($"\tinternal {@class.Identifier}(object obj) : base(obj) {{ }}");
            }

            output.AppendLine();
            output.IncreaseIndent();

            foreach (var member in @class.Members)
            {
                GenerateInterfaceMember(context, output, member, false);
            }

            output.DecreaseIndent();

            output.AppendLine("}");
            output.AppendLine();
        }
예제 #11
0
 private static void GenerateInterface(Context context, OutputBuffer output, InterfaceDeclarationSyntax @interface)
 {
 }