Beispiel #1
0
 protected SubroutineSymbol(
     SourceFileSymbol declaringSourceFile,
     string name,
     SubroutineDeclaration declaration) : base(name)
 {
     DeclaringSourceFile = declaringSourceFile;
     Declaration         = declaration;
 }
Beispiel #2
0
 public NsxModuleBuilder(Compilation compilation, SourceFileSymbol sourceFile)
 {
     Compilation  = compilation;
     SourceFile   = sourceFile;
     Diagnostics  = new DiagnosticBuilder();
     _stringHeap  = new TokenMap <string>(512);
     _subroutines = new TokenMap <SubroutineSymbol>(sourceFile.SubroutineCount);
     ConstructSubroutineMap(sourceFile);
     _externalSourceFiles = new TokenMap <SourceFileSymbol>();
 }
Beispiel #3
0
 private void ConstructSubroutineMap(SourceFileSymbol sourceFile)
 {
     foreach (ChapterSymbol chapter in sourceFile.Chapters)
     {
         _subroutines.GetOrAddToken(chapter);
     }
     foreach (SceneSymbol scene in sourceFile.Scenes)
     {
         _subroutines.GetOrAddToken(scene);
     }
     foreach (FunctionSymbol function in sourceFile.Functions)
     {
         _subroutines.GetOrAddToken(function);
     }
 }
Beispiel #4
0
        public SourceModuleSymbol(Compilation compilation, ImmutableArray <SyntaxTree> syntaxTrees)
        {
            Debug.Assert(syntaxTrees.Length > 0);
            Compilation    = compilation;
            RootSourceFile = MakeSourceFileSymbol(syntaxTrees[0]);

            if (syntaxTrees.Length > 1)
            {
                var builder = ImmutableArray.CreateBuilder <SourceFileSymbol>(syntaxTrees.Length - 1);
                for (int i = 1; i < syntaxTrees.Length; i++)
                {
                    SourceFileSymbol sourceFile = MakeSourceFileSymbol(syntaxTrees[i]);
                    builder.Add(sourceFile);
                }

                ReferencedSourceFiles = builder.ToImmutable();
            }
            else
            {
                ReferencedSourceFiles = ImmutableArray <SourceFileSymbol> .Empty;
            }
        }
Beispiel #5
0
        public static void WriteModule(NsxModuleBuilder builder)
        {
            SourceFileSymbol sourceFile  = builder.SourceFile;
            Compilation      compilation = builder.Compilation;
            ReadOnlySpan <SubroutineSymbol> subroutines = builder.Subroutines;

            // Compile subroutines
            using var codeBuffer = PooledBuffer <byte> .Allocate(64 * 1024);

            var codeWriter        = new BufferWriter(codeBuffer);
            var subroutineOffsets = new List <int>(subroutines.Length);

            CompileSubroutines(
                builder,
                sourceFile.Chapters.As <SubroutineSymbol>(),
                ref codeWriter,
                subroutineOffsets
                );
            CompileSubroutines(
                builder,
                sourceFile.Scenes.As <SubroutineSymbol>(),
                ref codeWriter,
                subroutineOffsets
                );
            CompileSubroutines(
                builder,
                sourceFile.Functions.As <SubroutineSymbol>(),
                ref codeWriter,
                subroutineOffsets
                );
            codeWriter.WriteBytes(NsxConstants.TableEndMarker);

            ReadOnlySpan <string> stringHeap     = builder.StringHeap;
            const int             subTableOffset = NsxConstants.NsxHeaderSize;
            int subTableSize    = NsxConstants.TableHeaderSize + 6 + subroutines.Length * sizeof(int);
            int stringTableSize = NsxConstants.TableHeaderSize + 6 + stringHeap.Length * sizeof(int);

            // Build the runtime information table (RTI)
            int rtiTableOffset = NsxConstants.NsxHeaderSize + subTableSize;

            using var rtiBuffer = PooledBuffer <byte> .Allocate(8 * 1024);

            var  rtiWriter          = new BufferWriter(rtiBuffer);
            uint rtiOffsetBlockSize = sourceFile.SubroutineCount * sizeof(ushort);

            using var rtiEntryOffsets = PooledBuffer <byte> .Allocate(rtiOffsetBlockSize);

            var rtiOffsetWriter = new BufferWriter(rtiEntryOffsets);

            WriteRuntimeInformation(
                sourceFile.Chapters.As <SubroutineSymbol>(),
                ref rtiWriter,
                ref rtiOffsetWriter
                );
            WriteRuntimeInformation(
                sourceFile.Scenes.As <SubroutineSymbol>(),
                ref rtiWriter,
                ref rtiOffsetWriter
                );
            WriteRuntimeInformation(
                sourceFile.Functions.As <SubroutineSymbol>(),
                ref rtiWriter,
                ref rtiOffsetWriter
                );
            rtiWriter.WriteBytes(NsxConstants.TableEndMarker);

            int         rtiSize         = NsxConstants.TableHeaderSize + rtiOffsetWriter.Position + rtiWriter.Position;
            Span <byte> rtiHeader       = stackalloc byte[NsxConstants.TableHeaderSize];
            var         rtiHeaderWriter = new BufferWriter(rtiHeader);

            rtiHeaderWriter.WriteBytes(NsxConstants.RtiTableMarker);
            rtiHeaderWriter.WriteUInt16LE((ushort)(rtiSize - NsxConstants.TableHeaderSize));

            int impTableOffset = rtiTableOffset + rtiSize;

            // Build the import table
            ReadOnlySpan <SourceFileSymbol> imports = builder.Imports;

            using var importTable = PooledBuffer <byte> .Allocate(2048);

            var impTableWriter = new BufferWriter(importTable);

            impTableWriter.WriteUInt16LE((ushort)imports.Length);
            for (int i = 0; i < imports.Length; i++)
            {
                impTableWriter.WriteLengthPrefixedUtf8String(imports[i].Name);
            }
            impTableWriter.WriteBytes(NsxConstants.TableEndMarker);

            Span <byte> impHeader       = stackalloc byte[NsxConstants.TableHeaderSize];
            var         impHeaderWriter = new BufferWriter(impHeader);

            impHeaderWriter.WriteBytes(NsxConstants.ImportTableMarker);
            impHeaderWriter.WriteUInt16LE((ushort)impTableWriter.Position);

            int impTableSize      = impHeaderWriter.Position + impTableWriter.Position;
            int stringTableOffset = impTableOffset + impTableSize;
            int codeStart         = stringTableOffset + stringTableSize;

            // Build the subroutine offset table (SUB)
            using var subTable = PooledBuffer <byte> .Allocate((uint) subTableSize);

            var subWriter = new BufferWriter(subTable);

            subWriter.WriteUInt16LE((ushort)subroutines.Length);
            for (int i = 0; i < subroutines.Length; i++)
            {
                subWriter.WriteInt32LE(subroutineOffsets[i] + codeStart);
            }
            subWriter.WriteBytes(NsxConstants.TableEndMarker);

            Span <byte> subHeader       = stackalloc byte[NsxConstants.TableHeaderSize];
            var         subHeaderWriter = new BufferWriter(subHeader);

            subHeaderWriter.WriteBytes(NsxConstants.SubTableMarker);
            subHeaderWriter.WriteUInt16LE((ushort)subWriter.Position);

            // Encode the strings and build the offset table (STR)
            int stringHeapStart = codeStart + codeWriter.Position;

            using var stringHeapBuffer = PooledBuffer <byte> .Allocate(64 * 1024);

            using var stringOffsetTable = PooledBuffer <byte> .Allocate((uint) stringTableSize);

            var strTableWriter = new BufferWriter(stringOffsetTable);

            strTableWriter.WriteUInt16LE((ushort)stringHeap.Length);

            var stringWriter = new BufferWriter(stringHeapBuffer);

            foreach (string s in stringHeap)
            {
                strTableWriter.WriteInt32LE(stringHeapStart + stringWriter.Position);
                stringWriter.WriteLengthPrefixedUtf8String(s);
            }
            strTableWriter.WriteBytes(NsxConstants.TableEndMarker);

            Span <byte> strTableHeader       = stackalloc byte[NsxConstants.TableHeaderSize];
            var         strTableHeaderWriter = new BufferWriter(strTableHeader);

            strTableHeaderWriter.WriteBytes(NsxConstants.StringTableMarker);
            strTableHeaderWriter.WriteUInt16LE((ushort)stringTableSize);

            // Build the NSX header
            using var headerBuffer = PooledBuffer <byte> .Allocate(NsxConstants.NsxHeaderSize);

            var  headerWriter     = new BufferWriter(headerBuffer);
            long modificationTime = compilation.SourceReferenceResolver
                                    .GetModificationTimestamp(sourceFile.FilePath);

            headerWriter.WriteBytes(NsxConstants.NsxMagic);
            headerWriter.WriteInt64LE(modificationTime);
            headerWriter.WriteInt32LE(subTableOffset);
            headerWriter.WriteInt32LE(rtiTableOffset);
            headerWriter.WriteInt32LE(impTableOffset);
            headerWriter.WriteInt32LE(stringTableOffset);
            headerWriter.WriteInt32LE(codeStart);

            // --- Write everything to the stream ---
            string outDir = compilation.OutputDirectory;
            string?subDir = Path.GetDirectoryName(sourceFile.Name);

            if (!string.IsNullOrEmpty(subDir))
            {
                subDir = Path.Combine(outDir, subDir);
                Directory.CreateDirectory(subDir);
            }

            string path = Path.Combine(outDir, Path.ChangeExtension(sourceFile.Name, "nsx"));

            using FileStream fileStream = File.Create(path);
            fileStream.Write(headerWriter.Written);

            fileStream.Write(subHeaderWriter.Written);
            fileStream.Write(subWriter.Written);

            fileStream.Write(rtiHeader);
            fileStream.Write(rtiOffsetWriter.Written);
            fileStream.Write(rtiWriter.Written);

            fileStream.Write(impHeaderWriter.Written);
            fileStream.Write(impTableWriter.Written);

            fileStream.Write(strTableHeaderWriter.Written);
            fileStream.Write(strTableWriter.Written);

            fileStream.Write(codeWriter.Written);
            fileStream.Write(stringWriter.Written);
        }
Beispiel #6
0
 public ushort GetExternalModuleToken(SourceFileSymbol sourceFile)
 {
     return(_externalSourceFiles.GetOrAddToken(sourceFile));
 }