Ejemplo n.º 1
0
        public long AddFunction(FunctionImplementation function)
        {
            // 0. Setting up scope and storage for function
            var scope          = FunctionSymbolResolver.FromBlock(function, _imports, _declarations);
            var storageManager = new StorageManager(scope);
            var context        = new CompilationContext(_nodeCompilers, _linkingInfoFactory, scope, storageManager);

            // 1. Compiling the full function (incl. prologue and epilogue) with the given context
            CompileFunction(function, context);

            // 2. Create function padding in the global "context" (16-byte align function with int3 breakpoints)
            Generator.Write(0xCC);
            Generator.Write(
                Enumerable.Repeat((byte)0xCC, (int)(16 - Generator.StreamPosition % 16)).ToArray()
                );

            // 3. Copy code and linking info from the function context over to the global "context"
            var functionStart = Generator.StreamPosition;

            context.Linking.CopyTo(LinkingInfo, Generator.StreamPosition);
            Generator.Write(context.Generator.GetBufferSpan());

            // 4. Add linking info for the newly compiled function, so that calls to it can get resolved correctly
            LinkingInfo.ResolveFunctionFixes(function.Declaration.Identifier.RawText, functionStart);
            return(functionStart);
        }
Ejemplo n.º 2
0
        private void BuildMethod(FunctionImplementation implementation)
        {
            string name    = VMTranslations.RemovePrefixes(pluginNameVar, implementation.Name.Identifier, false);
            string retType = VMTranslations.RemovePrefixes(pluginNameVar, implementation.ReturnType.Declaration);

            List <string> funcParams = new List <string>();

            foreach (FunctionParameter param in implementation.Parameters)
            {
                string paramType = VMTranslations.RemovePrefixes(pluginNameVar, param.m_Type.Declaration);
                string paramName = Output_CSharp.GetSafeVariableName(param.m_Lvalue.Identifier);

                string paramStr = paramType + " " + paramName;

                if (param is FunctionParameterWithDefault def)
                {
                    string defaultAsStr = Output_CSharp.GetValueAsString(def.m_Default, true);
                    paramStr += " = " + defaultAsStr;
                }

                funcParams.Add(paramStr);
            }

            string parameters = funcParams.Count == 0 ? "" : funcParams.Aggregate((a, b) => a + ", " + b);

            stringBuilder.AppendLine($"{Output_CSharp.GetIndent(2)}public static {retType} {name}({parameters})");
            stringBuilder.AppendLine($"{Output_CSharp.GetIndent(2)}{{");

            BuildImplementation(implementation);

            stringBuilder.AppendLine($"{Output_CSharp.GetIndent(2)}}}");
            stringBuilder.AppendLine();
        }
Ejemplo n.º 3
0
        private void BuildImplementation(FunctionImplementation implementation)
        {
            List <string> vectorDecls = new List <string>();

            foreach (NSSNode node in implementation.m_Block.m_Nodes)
            {
                ProcessImplementationNode(implementation, vectorDecls, node, 3);
            }
        }
Ejemplo n.º 4
0
        private void CompileFunction(FunctionImplementation function, ICompilationContext context)
        {
            foreach (var parameter in function.Declaration.Parameters)
            {
                context.Symbols.DefineLocal(parameter.ParameterIdentifier.RawText, parameter.ParameterType);
            }

            if (function.Declaration.Identifier.RawText == "Main")
            {
                context.Generator.CallDereferenced4(Constants.DummyOffsetInt);
                context.Linking.FixIATEntryOffset(context.Generator.StreamPosition, "kernel32.dll", "GetProcessHeap");
                context.Generator.MovToDereferenced4(Constants.DummyOffsetInt, Register64.RAX);
                context.Linking.FixDataOffset(context.Generator.StreamPosition, Constants.HeapHandleIdentifier);
            }

            context.CompileStatement(function.Body.StatementAsBlock());

            context.Generator.InsertCode(context.Linking, 0, gen => context.Storage.CreatePrologue(gen, function.Declaration));
            context.Linking.ResolveFunctionEpilogueFixes(function.Declaration.Identifier.RawText, context.Generator.StreamPosition);
            context.Storage.CreateEpilogue(context.Generator);
            context.Generator.Ret();
        }
Ejemplo n.º 5
0
 public void setImplementation(FunctionImplementation aFunctionImplementation)
 {
     implementation = aFunctionImplementation;
 }
Ejemplo n.º 6
0
 public BlenderFunction(FunctionImplementation implementation, int minArguments, int maxArguments = Int32.MinValue)
 {
     Implementation = implementation;
     MinArguments   = minArguments;
     MaxArguments   = (maxArguments == Int32.MinValue) ? MinArguments : maxArguments;
 }
Ejemplo n.º 7
0
 public BlenderFunction(FunctionImplementation implementation,int minArguments,int maxArguments = Int32.MinValue)
 {
     Implementation = implementation;
     MinArguments = minArguments;
     MaxArguments = ( maxArguments == Int32.MinValue ) ? MinArguments : maxArguments;
 }
Ejemplo n.º 8
0
        private void ProcessImplementationNode(FunctionImplementation implementation, List <string> vectorDecls, NSSNode node, int depth)
        {
            string expression;

            switch (node)
            {
            case LvalueDeclSingleWithAssignment declAssignment:
                expression = VMTranslations.TryTranslate(pluginNameVar, declAssignment.m_Expression.m_Expression);

                if (declAssignment.m_Lvalue.Identifier == "sFunc")
                {
                    stringBuilder.AppendLine($"{Output_CSharp.GetIndent(depth)}const {declAssignment.m_Type.Declaration} {declAssignment.m_Lvalue.Identifier} = {expression};");
                    stringBuilder.AppendLine($"{Output_CSharp.GetIndent(depth)}VM.NWNX.SetFunction({pluginNameVar}, sFunc);");
                    break;
                }

                stringBuilder.AppendLine($"{Output_CSharp.GetIndent(depth)}{declAssignment.m_Type.Declaration} {declAssignment.m_Lvalue.Identifier} = {expression};");
                break;

            case LvalueAssignment assignment:
                string[] identifier = assignment.m_Lvalue.Identifier.Split('.', 2);
                if (identifier.Length > 1 && vectorDecls.Contains(identifier[0]))
                {
                    identifier[1] = identifier[1].ToUpper();
                }

                expression = VMTranslations.TryTranslate(pluginNameVar, assignment.m_Expression.m_Expression);
                stringBuilder.AppendLine($"{Output_CSharp.GetIndent(depth)}{string.Join('.', identifier)} = {expression};");
                break;

            case LvalueDeclSingle declaration:
                if (declaration.m_Type.GetType() == typeof(StringType))
                {
                    stringBuilder.AppendLine($"{Output_CSharp.GetIndent(depth)}{VMTranslations.RemovePrefixes(pluginNameVar, declaration.m_Type.Declaration)} {declaration.m_Lvalue.Identifier} = \"\";");
                }
                else if (declaration.m_Type is StructType)
                {
                    stringBuilder.AppendLine($"{Output_CSharp.GetIndent(depth)}{VMTranslations.RemovePrefixes(pluginNameVar, declaration.m_Type.Declaration)} {declaration.m_Lvalue.Identifier} = default;");
                }
                else if (declaration.m_Type is VectorType)
                {
                    stringBuilder.AppendLine($"{Output_CSharp.GetIndent(depth)}{VMTranslations.RemovePrefixes(pluginNameVar, declaration.m_Type.Declaration)} {declaration.m_Lvalue.Identifier} = default;");
                    vectorDecls.Add(declaration.m_Lvalue.Identifier);
                }
                else
                {
                    stringBuilder.AppendLine($"{Output_CSharp.GetIndent(depth)}{VMTranslations.RemovePrefixes(pluginNameVar, declaration.m_Type.Declaration)} {declaration.m_Lvalue.Identifier};");
                }
                break;

            case FunctionCall functionCall:
                expression = VMTranslations.TranslateCall(pluginNameVar, functionCall.m_Name.Identifier, functionCall.m_Arguments);
                stringBuilder.AppendLine($"{Output_CSharp.GetIndent(depth)}{expression};");
                break;

            case ReturnStatement returnStatement:
                if (implementation.ReturnType is StructType || implementation.ReturnType is VectorType)
                {
                    stringBuilder.AppendLine($"{Output_CSharp.GetIndent(depth)}return {returnStatement.m_Expression.m_Expression};");
                    break;
                }

                stringBuilder.AppendLine($"{Output_CSharp.GetIndent(depth)}return {implementation.ReturnType.NWNXPopFormat};");
                break;

            case IfStatement ifStatement:
                expression = VMTranslations.TryTranslate(pluginNameVar, ifStatement.m_Expression.m_Expression);

                if (!expression.Contains("==") && !expression.Contains("!=") && !expression.Contains("<") && !expression.Contains(">"))
                {
                    if (expression.StartsWith("!"))
                    {
                        expression = $"{expression.Substring(1)} == FALSE";
                    }
                    else
                    {
                        expression = $"{expression} == TRUE";
                    }
                }

                stringBuilder.AppendLine($"{Output_CSharp.GetIndent(depth)}if ({expression})");
                ProcessImplementationNode(implementation, vectorDecls, ifStatement.m_Action, depth);
                break;

            case ElseStatement elseStatement:
                stringBuilder.AppendLine($"{Output_CSharp.GetIndent(depth)}else");
                ProcessImplementationNode(implementation, vectorDecls, elseStatement.m_Action, depth);
                break;

            case ForLoop forLoop:
                stringBuilder.AppendLine($"{Output_CSharp.GetIndent(depth)}for ({forLoop.m_Pre.m_Expression}; {forLoop.m_Condition.m_Expression}; {forLoop.m_Post.m_Expression})");
                ProcessImplementationNode(implementation, vectorDecls, forLoop.m_Action, depth);
                break;

            case Block block:
                stringBuilder.AppendLine($"{Output_CSharp.GetIndent(depth)}{{");
                foreach (NSSNode childNode in block.m_Nodes)
                {
                    ProcessImplementationNode(implementation, vectorDecls, childNode, depth + 1);
                }

                stringBuilder.AppendLine($"{Output_CSharp.GetIndent(depth)}}}");
                break;
            }
        }
Ejemplo n.º 9
0
        public int GetFromCU(CompilationUnit cu, string className, out string data)
        {
            stringBuilder.Clear();
            pluginNameVar = null;

            stringBuilder.AppendLine("using static NWN.Core.NWScript;");
            stringBuilder.AppendLine();

            stringBuilder.AppendLine("namespace NWN.Core.NWNX");
            stringBuilder.AppendLine("{");

            int attributePos = stringBuilder.Length;

            stringBuilder.AppendLine();
            stringBuilder.AppendLine($"{Output_CSharp.GetIndent(1)}public class {className}");
            stringBuilder.AppendLine($"{Output_CSharp.GetIndent(1)}{{");

            HashSet <FunctionImplementation> implementedMethods = new HashSet <FunctionImplementation>();

            for (int index = 0; index < cu.m_Nodes.Count; index++)
            {
                NSSNode node = cu.m_Nodes[index];
                if (node is LineComment lineComment)
                {
                    string xmlEscapedComment = lineComment.Comment
                                               .Replace("&", "&amp;")
                                               .Replace("\"", "&quot;")
                                               .Replace("'", "&apos;")
                                               .Replace("<", "&lt;")
                                               .Replace(">", "&gt;")
                                               .Replace("/ @}", " @}");

                    if (xmlEscapedComment.Contains("@param"))
                    {
                        string paramName = xmlEscapedComment.Split(' ')[2];
                        stringBuilder.AppendLine($"{Output_CSharp.GetIndent(2)}//{xmlEscapedComment.Replace($"@param {paramName} ", $"<param name=\"{paramName}\">").Replace($"@param {paramName}", $"<param name=\"{paramName}\">")}</param>");
                    }
                    else if (xmlEscapedComment.Contains("@return"))
                    {
                        stringBuilder.AppendLine($"{Output_CSharp.GetIndent(2)}//{xmlEscapedComment.Replace("@return ", $"<returns>").Replace("@return", $"<returns>")}</returns>");
                    }
                    else
                    {
                        stringBuilder.AppendLine($"{Output_CSharp.GetIndent(2)}//" + xmlEscapedComment.Replace("@brief ", ""));
                    }
                }

                if (node is BlockComment blockComment)
                {
                    stringBuilder.AppendLine($"{Output_CSharp.GetIndent(2)}/*");
                    foreach (string line in blockComment.CommentLines)
                    {
                        stringBuilder.AppendLine($"{Output_CSharp.GetIndent(2)}" + line);
                    }

                    stringBuilder.AppendLine($"{Output_CSharp.GetIndent(2)}*/");
                }

                if (node is LvalueDeclSingleWithAssignment lvalueDecl)
                {
                    // First entry is always the plugin name.
                    if (pluginNameVar == null)
                    {
                        if (lvalueDecl.m_Type.GetType() != typeof(StringType))
                        {
                            data = null;
                            return(-1);
                        }

                        pluginNameVar = lvalueDecl.m_Lvalue.Identifier;
                    }

                    string type  = lvalueDecl.m_Type.Declaration;
                    string name  = lvalueDecl.m_Lvalue.Identifier;
                    string value = lvalueDecl.m_Expression.m_Expression;
                    stringBuilder.AppendLine($"{Output_CSharp.GetIndent(2)}public const {type} {name} = {value}{(lvalueDecl.m_Type.GetType() == typeof(FloatType) && !value.EndsWith("f") ? "f" : "")};");
                    if (cu.m_Nodes.Count > index + 2 && !(cu.m_Nodes[index + 1] is LvalueDeclSingleWithAssignment))
                    {
                        stringBuilder.AppendLine();
                    }
                }

                if (pluginNameVar == null)
                {
                    continue;
                }

                if (node is FunctionDeclaration funcDecl)
                {
                    FunctionImplementation funcImpl = GetFunction(cu, funcDecl);
                    if (implementedMethods.Contains(funcImpl))
                    {
                        continue;
                    }

                    BuildMethod(funcImpl);
                    implementedMethods.Add(funcImpl);
                }

                if (node is FunctionImplementation func)
                {
                    if (implementedMethods.Contains(func))
                    {
                        continue;
                    }

                    BuildMethod(func);
                    implementedMethods.Add(func);
                }
            }

            stringBuilder.AppendLine($"{Output_CSharp.GetIndent(1)}}}");

            // Structures
            foreach (StructDeclaration structDeclaration in cu.m_Nodes.OfType <StructDeclaration>())
            {
                stringBuilder.AppendLine();
                stringBuilder.AppendLine($"{Output_CSharp.GetIndent(1)}public struct {VMTranslations.RemovePrefixes(pluginNameVar, structDeclaration.m_Name.Identifier)}");
                stringBuilder.AppendLine($"{Output_CSharp.GetIndent(1)}{{");

                foreach (LvalueDeclSingle dec in structDeclaration.m_Members.OfType <LvalueDeclSingle>())
                {
                    string type = dec.m_Type.Declaration;
                    string name = dec.m_Lvalue.Identifier;
                    stringBuilder.AppendLine($"{Output_CSharp.GetIndent(2)}public {type} {name};");
                }

                stringBuilder.AppendLine($"{Output_CSharp.GetIndent(1)}}}");
            }

            stringBuilder.Append("}");
            stringBuilder.AppendLine();

            if (pluginNameVar == null)
            {
                data = null;
                return(-1);
            }

            stringBuilder.Insert(attributePos, $"{Output_CSharp.GetIndent(1)}[NWNXPlugin({pluginNameVar})]");
            data = stringBuilder.ToString();
            return(0);
        }