summaryrefslogtreecommitdiff
path: root/source/slang
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2021-04-01 13:39:11 -0400
committerGitHub <noreply@github.com>2021-04-01 10:39:11 -0700
commitfa31d21ba92669a521a7768467246918e3947e02 (patch)
treeaf98a593e24bc6309ac4d11a59562be4b22c93d7 /source/slang
parent3f1632a1450a5879f337b4bd178e48880cd583f8 (diff)
Added compiler-core project (#1775)
* #include an absolute path didn't work - because paths were taken to always be relative. * Split out compiler-core initially with just slang-source-loc.cpp * More lexer, name, token to compiler-core. * Split Lexer and Core diagnostics. * Move slang-file-system to core. * Add slang-file-system to core. * More DownstreamCompiler into compiler-core * Fix typo. * Add compiler-core to bootstrap proj. * Small fixes to premake * For linux try with compiler-core * Remove compiler-core from examples. * Added NameConventionUtil to compiler-core * Add global function to CharUtil to *hopefully* avoid linking issue. * Hack to make linkage of CharUtil work on linux.
Diffstat (limited to 'source/slang')
-rw-r--r--source/slang/slang-ast-support-types.h6
-rwxr-xr-xsource/slang/slang-compiler.cpp4
-rwxr-xr-xsource/slang/slang-compiler.h9
-rw-r--r--source/slang/slang-diagnostic-defs.h16
-rw-r--r--source/slang/slang-diagnostics.cpp544
-rw-r--r--source/slang/slang-diagnostics.h273
-rw-r--r--source/slang/slang-emit-c-like.cpp4
-rw-r--r--source/slang/slang-emit.cpp4
-rw-r--r--source/slang/slang-file-system.cpp888
-rw-r--r--source/slang/slang-file-system.h253
-rw-r--r--source/slang/slang-include-system.h2
-rw-r--r--source/slang/slang-ir-legalize-types.cpp3
-rw-r--r--source/slang/slang-ir.h5
-rw-r--r--source/slang/slang-legalize-types.h3
-rw-r--r--source/slang/slang-lexer.cpp1400
-rw-r--r--source/slang/slang-lexer.h164
-rw-r--r--source/slang/slang-lookup.cpp3
-rw-r--r--source/slang/slang-mangle.cpp2
-rw-r--r--source/slang/slang-name.cpp42
-rw-r--r--source/slang/slang-name.h89
-rw-r--r--source/slang/slang-options.cpp3
-rw-r--r--source/slang/slang-parser.h3
-rw-r--r--source/slang/slang-preprocessor.cpp2
-rw-r--r--source/slang/slang-preprocessor.h2
-rw-r--r--source/slang/slang-repro.cpp2
-rw-r--r--source/slang/slang-repro.h3
-rw-r--r--source/slang/slang-serialize-ir-types.h4
-rw-r--r--source/slang/slang-serialize-misc-type-info.h2
-rw-r--r--source/slang/slang-serialize-reflection.h2
-rw-r--r--source/slang/slang-serialize-source-loc.h4
-rw-r--r--source/slang/slang-serialize.h2
-rw-r--r--source/slang/slang-source-loc.cpp689
-rw-r--r--source/slang/slang-source-loc.h487
-rw-r--r--source/slang/slang-token-defs.h96
-rw-r--r--source/slang/slang-token.cpp24
-rw-r--r--source/slang/slang-token.h140
-rw-r--r--source/slang/slang.cpp5
37 files changed, 68 insertions, 5116 deletions
diff --git a/source/slang/slang-ast-support-types.h b/source/slang/slang-ast-support-types.h
index 1921a101f..168d358d6 100644
--- a/source/slang/slang-ast-support-types.h
+++ b/source/slang/slang-ast-support-types.h
@@ -2,7 +2,10 @@
#define SLANG_AST_SUPPORT_TYPES_H
#include "../core/slang-basic.h"
-#include "slang-lexer.h"
+
+#include "../compiler-core/slang-lexer.h"
+#include "../compiler-core/slang-name.h"
+
#include "slang-profile.h"
#include "slang-type-system-shared.h"
#include "../../slang.h"
@@ -16,7 +19,6 @@
#include "slang-ast-reflect.h"
#include "slang-ref-object-reflect.h"
-#include "slang-name.h"
#include <assert.h>
diff --git a/source/slang/slang-compiler.cpp b/source/slang/slang-compiler.cpp
index 2d0287613..c034f5f7d 100755
--- a/source/slang/slang-compiler.cpp
+++ b/source/slang/slang-compiler.cpp
@@ -10,7 +10,9 @@
#include "slang-check.h"
#include "slang-compiler.h"
-#include "slang-lexer.h"
+
+#include "../compiler-core/slang-lexer.h"
+
#include "slang-lower-to-ir.h"
#include "slang-mangle.h"
#include "slang-parameter-binding.h"
diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h
index 9ef75ab86..b1e3c3a70 100755
--- a/source/slang/slang-compiler.h
+++ b/source/slang/slang-compiler.h
@@ -3,9 +3,11 @@
#include "../core/slang-basic.h"
#include "../core/slang-shared-library.h"
-
-#include "../core/slang-downstream-compiler.h"
#include "../core/slang-archive-file-system.h"
+#include "../core/slang-file-system.h"
+
+#include "../compiler-core/slang-downstream-compiler.h"
+#include "../compiler-core/slang-name.h"
#include "../core/slang-std-writers.h"
@@ -13,12 +15,11 @@
#include "slang-capability.h"
#include "slang-diagnostics.h"
-#include "slang-name.h"
+
#include "slang-preprocessor.h"
#include "slang-profile.h"
#include "slang-syntax.h"
-#include "slang-file-system.h"
#include "slang-include-system.h"
diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h
index 6387ff8b2..ef5a94501 100644
--- a/source/slang/slang-diagnostic-defs.h
+++ b/source/slang/slang-diagnostic-defs.h
@@ -43,7 +43,6 @@ DIAGNOSTIC(-1, Note, doYouForgetToMakeComponentAccessible, "do you forget to mak
DIAGNOSTIC(-1, Note, seeDeclarationOf, "see declaration of '$0'")
DIAGNOSTIC(-1, Note, seeOtherDeclarationOf, "see other declaration of '$0'")
DIAGNOSTIC(-1, Note, seePreviousDeclarationOf, "see previous declaration of '$0'")
-DIAGNOSTIC(-1, Note, seeTokenPasteLocation, "see token pasted location")
DIAGNOSTIC(-1, Note, includeOutput, "include $0")
//
@@ -129,21 +128,6 @@ DIAGNOSTIC( 88, Error, unknownArchiveType, "archive type '%0' is unknown")
DIAGNOSTIC( 100, Error, failedToLoadDownstreamCompiler, "failed to load downstream compiler '$0'")
DIAGNOSTIC(99999, Note, noteFailedToLoadDynamicLibrary, "failed to load dynamic library '$0'")
-
-//
-// 1xxxx - Lexical analysis
-//
-
-DIAGNOSTIC(10000, Error, illegalCharacterPrint, "illegal character '$0'")
-DIAGNOSTIC(10000, Error, illegalCharacterHex, "illegal character (0x$0)")
-DIAGNOSTIC(10001, Error, illegalCharacterLiteral, "illegal character literal")
-
-DIAGNOSTIC(10002, Warning, octalLiteral, "'0' prefix indicates octal literal")
-DIAGNOSTIC(10003, Error, invalidDigitForBase, "invalid digit for base-$1 literal: '$0'")
-
-DIAGNOSTIC(10004, Error, endOfFileInLiteral, "end of file in literal")
-DIAGNOSTIC(10005, Error, newlineInLiteral, "newline in literal")
-
//
// 15xxx - Preprocessing
//
diff --git a/source/slang/slang-diagnostics.cpp b/source/slang/slang-diagnostics.cpp
index 4b450c9a9..4a831aacf 100644
--- a/source/slang/slang-diagnostics.cpp
+++ b/source/slang/slang-diagnostics.cpp
@@ -1,473 +1,15 @@
// slang-diagnostics.cpp
#include "slang-diagnostics.h"
-#include "slang-name.h"
-
#include "../core/slang-memory-arena.h"
#include "../core/slang-dictionary.h"
#include "../core/slang-string-util.h"
-#include "../core/slang-char-util.h"
-#include "../core/slang-name-convention-util.h"
-
-#include <assert.h>
-
-#ifdef _WIN32
-#define WIN32_LEAN_AND_MEAN
-#define NOMINMAX
-#include <Windows.h>
-#undef WIN32_LEAN_AND_MEAN
-#undef NOMINMAX
-#include <d3dcompiler.h>
-#endif
-
-namespace Slang {
-
-void printDiagnosticArg(StringBuilder& sb, char const* str)
-{
- sb << str;
-}
-
-void printDiagnosticArg(StringBuilder& sb, int32_t val)
-{
- sb << val;
-}
-
-void printDiagnosticArg(StringBuilder& sb, uint32_t val)
-{
- sb << val;
-}
-
-void printDiagnosticArg(StringBuilder& sb, int64_t val)
-{
- sb << val;
-}
-
-void printDiagnosticArg(StringBuilder& sb, uint64_t val)
-{
- sb << val;
-}
-
-void printDiagnosticArg(StringBuilder& sb, double val)
-{
- sb << val;
-}
-
-void printDiagnosticArg(StringBuilder& sb, Slang::String const& str)
-{
- sb << str;
-}
-
-void printDiagnosticArg(StringBuilder& sb, Slang::UnownedStringSlice const& str)
-{
- sb.append(str);
-}
-
-
-void printDiagnosticArg(StringBuilder& sb, Name* name)
-{
- sb << getText(name);
-}
-
-
-void printDiagnosticArg(StringBuilder& sb, TokenType tokenType)
-{
- sb << TokenTypeToString(tokenType);
-}
-
-void printDiagnosticArg(StringBuilder& sb, Token const& token)
-{
- sb << token.getContent();
-}
-
-SourceLoc const& getDiagnosticPos(Token const& token)
-{
- return token.loc;
-}
-
-// Take the format string for a diagnostic message, along with its arguments, and turn it into a
-static void formatDiagnosticMessage(StringBuilder& sb, char const* format, int argCount, DiagnosticArg const* const* args)
-{
- char const* spanBegin = format;
- for(;;)
- {
- char const* spanEnd = spanBegin;
- while (int c = *spanEnd)
- {
- if (c == '$')
- break;
- spanEnd++;
- }
-
- sb.Append(spanBegin, int(spanEnd - spanBegin));
- if (!*spanEnd)
- return;
-
- SLANG_ASSERT(*spanEnd == '$');
- spanEnd++;
- int d = *spanEnd++;
- switch (d)
- {
- // A double dollar sign `$$` is used to emit a single `$`
- case '$':
- sb.Append('$');
- break;
-
- // A single digit means to emit the corresponding argument.
- // TODO: support more than 10 arguments, and add options
- // to control formatting, etc.
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- {
- int index = d - '0';
- if (index >= argCount)
- {
- // TODO(tfoley): figure out what a good policy will be for "panic" situations like this
- throw InvalidOperationException("too few arguments for diagnostic message");
- }
- else
- {
- DiagnosticArg const* arg = args[index];
- arg->printFunc(sb, arg->data);
- }
- }
- break;
-
- default:
- throw InvalidOperationException("invalid diagnostic message format");
- break;
- }
-
- spanBegin = spanEnd;
- }
-}
-
-static void formatDiagnostic(const HumaneSourceLoc& humaneLoc, Diagnostic const& diagnostic, StringBuilder& outBuilder)
-{
- outBuilder << humaneLoc.pathInfo.foundPath;
- outBuilder << "(";
- outBuilder << Int32(humaneLoc.line);
- outBuilder << "): ";
-
- outBuilder << getSeverityName(diagnostic.severity);
-
- if (diagnostic.ErrorID >= 0)
- {
- outBuilder << " ";
- outBuilder << diagnostic.ErrorID;
- }
-
- outBuilder << ": ";
- outBuilder << diagnostic.Message;
- outBuilder << "\n";
-}
-
-static void _replaceTabWithSpaces(const UnownedStringSlice& slice, Int tabSize, StringBuilder& out)
-{
- const char* start = slice.begin();
- const char*const end = slice.end();
-
- const Index startLength = out.getLength();
-
- for (const char* cur = start; cur < end; cur++)
- {
- if (*cur == '\t')
- {
- if (start < cur)
- {
- out.append(start, cur);
- }
-
- // The amount of spaces we add depends on the current position.
- const Index lastPosition = out.getLength() - startLength;
- Index tabPosition = lastPosition;
-
- // Strip the tabPosition so it's back to the tab stop
- // Special case if tabSize is a power of 2
- if ((tabSize & (tabSize - 1)) == 0)
- {
- tabPosition = tabPosition & ~Index(tabSize - 1);
- }
- else
- {
- tabPosition -= tabPosition % tabSize;
- }
-
- // Move to next tab
- tabPosition += tabSize;
-
- // The amount of spaces to simulate the tab
- const Index spacesCount = tabPosition - lastPosition;
-
- // Add the spaces
- out.appendRepeatedChar(' ', spacesCount);
-
- // Set the start at the first character past
- start = cur + 1;
- }
- }
-
- if (start < end)
- {
- out.append(start, end);
- }
-}
-
-// Given multi-line text, and a position within the text (as a pointer into the memory of text)
-// extract the line that contains pos
-static UnownedStringSlice _extractLineContainingPosition(const UnownedStringSlice& text, const char* pos)
-{
- SLANG_ASSERT(text.isMemoryContained(pos));
-
- const char*const contentStart = text.begin();
- const char*const contentEnd = text.end();
-
- // We want to determine the start of the line, and the end of the line
- const char* start = pos;
- for (; start > contentStart; --start)
- {
- const char c = *start;
- if (c == '\n' || c == '\r')
- {
- // We want the character after, but we can only do this if not already at pos
- start += int(start < pos);
- break;
- }
- }
- const char* end = pos;
- for (; end < contentEnd; ++end)
- {
- const char c = *end;
- if (c == '\n' || c == '\r')
- {
- break;
- }
- }
-
- return UnownedStringSlice(start, end);
-}
-
-static void _sourceLocationNoteDiagnostic(SourceView* sourceView, SourceLoc sourceLoc, DiagnosticSink::SourceLocationLexer lexer, StringBuilder& sb)
-{
- SourceFile* sourceFile = sourceView->getSourceFile();
- if (!sourceFile)
- {
- return;
- }
-
- UnownedStringSlice content = sourceFile->getContent();
-
- // Make sure the offset is within content.
- // This is important because it's possible to have a 'SourceFile' that doesn't contain any content
- // (for example when reconstructed via serialization with just line offsets, the actual source text 'content' isn't available).
- const int offset = sourceView->getRange().getOffset(sourceLoc);
- if (offset < 0 || offset >= content.getLength())
- {
- return;
- }
-
- // Work out the position of the SourceLoc in the source
- const char*const pos = content.begin() + offset;
-
- UnownedStringSlice line = _extractLineContainingPosition(content, pos);
-
- // Trim any trailing white space
- line = UnownedStringSlice(line.begin(), line.trim().end());
-
- // TODO(JS): The tab size should ideally be configurable from command line.
- // For now just go with 4.
- const Index tabSize = 4;
-
- StringBuilder sourceLine;
- StringBuilder caretLine;
-
- // First work out the sourceLine
- _replaceTabWithSpaces(line, tabSize, sourceLine);
-
- // Now the caretLine which appears underneath the sourceLine
- {
- // Produce the text up to the caret position (at pos), taking into account tabs
- _replaceTabWithSpaces(UnownedStringSlice(line.begin(), pos), tabSize, caretLine);
- // Now make all spaces
- const Index length = caretLine.getLength();
- caretLine.Clear();
- caretLine.appendRepeatedChar(' ', length);
-
- // Add caret
- caretLine << "^";
+#include "../compiler-core/slang-name.h"
+#include "../compiler-core/slang-core-diagnostics.h"
- if (lexer)
- {
- UnownedStringSlice token = lexer(UnownedStringSlice(pos, line.end()));
-
- if (token.getLength() > 1)
- {
- caretLine.appendRepeatedChar('~', token.getLength() - 1);
- }
- }
- }
-
- // We could have handling here for if the line is too long, that we surround the important section
- // will ellipsis for example.
- // For now we just output.
-
- sb << sourceLine << "\n";
- sb << caretLine << "\n";
-}
-
-static void formatDiagnostic(
- DiagnosticSink* sink,
- Diagnostic const& diagnostic,
- StringBuilder& sb)
+namespace Slang
{
- auto sourceManager = sink->getSourceManager();
-
- SourceView* sourceView = nullptr;
- HumaneSourceLoc humaneLoc;
- const auto sourceLoc = diagnostic.loc;
- {
- sourceView = sourceManager->findSourceViewRecursively(sourceLoc);
- if (sourceView)
- {
- humaneLoc = sourceView->getHumaneLoc(sourceLoc);
- }
- formatDiagnostic(humaneLoc, diagnostic, sb);
-
- {
- SourceView* currentView = sourceView;
-
- while (currentView && currentView->getInitiatingSourceLoc().isValid() && currentView->getSourceFile()->getPathInfo().type == PathInfo::Type::TokenPaste)
- {
- SourceView* initiatingView = sourceManager->findSourceView(currentView->getInitiatingSourceLoc());
- if (initiatingView == nullptr)
- {
- break;
- }
-
- const DiagnosticInfo& diagnosticInfo = Diagnostics::seeTokenPasteLocation;
-
- // Turn the message format into a message. For the moment it assumes no parameters.
- StringBuilder msg;
- formatDiagnosticMessage(msg, diagnosticInfo.messageFormat, 0, nullptr);
-
- // Set up the diagnostic.
- Diagnostic initiationDiagnostic;
- initiationDiagnostic.ErrorID = diagnosticInfo.id;
- initiationDiagnostic.Message = msg.ProduceString();
- initiationDiagnostic.loc = sourceView->getInitiatingSourceLoc();
- initiationDiagnostic.severity = diagnosticInfo.severity;
-
- // TODO(JS):
- // Not 100% clear what the best sourceLoc type is most useful here - we will go with default for now
- HumaneSourceLoc pasteHumaneLoc = initiatingView->getHumaneLoc(sourceView->getInitiatingSourceLoc());
-
- // Okay we should output where the token paste took place
- formatDiagnostic(pasteHumaneLoc, initiationDiagnostic, sb);
-
- // Make the initiatingView the current view
- currentView = initiatingView;
- }
- }
- }
-
- // We don't don't output source line information if this is a 'note' as a note is extra information for one
- // of the other main severity types, and so the information should already be output on the initial line
- if (sourceView && sink->isFlagSet(DiagnosticSink::Flag::SourceLocationLine) && diagnostic.severity != Severity::Note)
- {
- _sourceLocationNoteDiagnostic(sourceView, sourceLoc, sink->getSourceLocationLexer(), sb);
- }
-
- if (sourceView && sink->isFlagSet(DiagnosticSink::Flag::VerbosePath))
- {
- auto actualHumaneLoc = sourceView->getHumaneLoc(diagnostic.loc, SourceLocType::Actual);
-
- // Look up the path verbosely (will get the canonical path if necessary)
- actualHumaneLoc.pathInfo.foundPath = sourceView->getSourceFile()->calcVerbosePath();
-
- // Only output if it's actually different
- if (actualHumaneLoc.pathInfo.foundPath != humaneLoc.pathInfo.foundPath ||
- actualHumaneLoc.line != humaneLoc.line ||
- actualHumaneLoc.column != humaneLoc.column)
- {
- formatDiagnostic(actualHumaneLoc, diagnostic, sb);
- }
- }
-}
-
-void DiagnosticSink::diagnoseImpl(SourceLoc const& pos, DiagnosticInfo const& info, int argCount, DiagnosticArg const* const* args)
-{
- StringBuilder sb;
- formatDiagnosticMessage(sb, info.messageFormat, argCount, args);
-
- Diagnostic diagnostic;
- diagnostic.ErrorID = info.id;
- diagnostic.Message = sb.ProduceString();
- diagnostic.loc = pos;
- diagnostic.severity = info.severity;
-
- if (diagnostic.severity >= Severity::Error)
- {
- m_errorCount++;
- }
-
- // Did the client supply a callback for us to use?
- if( writer )
- {
- // If so, pass the error string along to them
- StringBuilder messageBuilder;
- formatDiagnostic(this, diagnostic, messageBuilder);
-
- writer->write(messageBuilder.getBuffer(), messageBuilder.getLength());
- }
- else
- {
- // If the user doesn't have a callback, then just
- // collect our diagnostic messages into a buffer
- formatDiagnostic(this, diagnostic, outputBuffer);
- }
-
- if (diagnostic.severity >= Severity::Fatal)
- {
- // TODO: figure out a better policy for aborting compilation
- throw AbortCompilationException();
- }
-}
-
-void DiagnosticSink::diagnoseRaw(
- Severity severity,
- char const* message)
-{
- return diagnoseRaw(severity, UnownedStringSlice(message));
-}
-
-void DiagnosticSink::diagnoseRaw(
- Severity severity,
- const UnownedStringSlice& message)
-{
- if (severity >= Severity::Error)
- {
- m_errorCount++;
- }
-
- // Did the client supply a callback for us to use?
- if(writer)
- {
- // If so, pass the error string along to them
- writer->write(message.begin(), message.getLength());
- }
- else
- {
- // If the user doesn't have a callback, then just
- // collect our diagnostic messages into a buffer
- outputBuffer.append(message);
- }
-
- if (severity >= Severity::Fatal)
- {
- // TODO: figure out a better policy for aborting compilation
- throw InvalidOperationException();
- }
-}
namespace Diagnostics
{
@@ -476,89 +18,41 @@ namespace Diagnostics
#undef DIAGNOSTIC
}
-static const DiagnosticInfo* const kAllDiagnostics[] =
+static const DiagnosticInfo* const kCompilerDiagnostics[] =
{
#define DIAGNOSTIC(id, severity, name, messageFormat) &Diagnostics::name,
#include "slang-diagnostic-defs.h"
#undef DIAGNOSTIC
};
-class DiagnosticsLookup : public RefObject
+static DiagnosticsLookup* _newDiagnosticsLookup()
{
-public:
- const DiagnosticInfo* findDiagostic(const UnownedStringSlice& slice) const
- {
- const Index* indexPtr = m_map.TryGetValue(slice);
- return indexPtr ? kAllDiagnostics[*indexPtr] : nullptr;
- }
- Index _findDiagnosticIndex(const UnownedStringSlice& slice) const
- {
- const Index* indexPtr = m_map.TryGetValue(slice);
- return indexPtr ? *indexPtr : 0;
- }
- static DiagnosticsLookup* getSingleton()
- {
- static RefPtr<DiagnosticsLookup> singleton = new DiagnosticsLookup;
- return singleton;
- }
-
-protected:
- void _add(const char* name, Index index)
- {
- UnownedStringSlice nameSlice(name);
- m_map.Add(nameSlice, index);
-
- // Add a dashed version (KababCase)
- {
- m_work.Clear();
+ DiagnosticsLookup* lookup = new DiagnosticsLookup(kCompilerDiagnostics, SLANG_COUNT_OF(kCompilerDiagnostics));
- NameConventionUtil::convert(NameConvention::Camel, nameSlice, CharCase::Lower, NameConvention::Kabab, m_work);
-
- UnownedStringSlice dashSlice(m_arena.allocateString(m_work.getBuffer(), m_work.getLength()), m_work.getLength());
- m_map.AddIfNotExists(dashSlice, index);
- }
- }
- void _addAlias(const char* name, const char* diagnosticName)
+ // Add all the diagnostics in 'core'
+ DiagnosticsLookup* coreLookup = getCoreDiagnosticsLookup();
+ if (coreLookup)
{
- const Index index = _findDiagnosticIndex(UnownedStringSlice(diagnosticName));
- SLANG_ASSERT(index >= 0);
- if (index >= 0)
+ for (auto diagnostic : coreLookup->getDiagnostics())
{
- _add(name, index);
+ lookup->add(diagnostic);
}
}
- DiagnosticsLookup();
- StringBuilder m_work;
- Dictionary<UnownedStringSlice, Index> m_map;
- MemoryArena m_arena;
-};
+ // Add the alias
+ lookup->addAlias("overlappingBindings", "parameterBindingsOverlap");
+ return lookup;
+}
-DiagnosticsLookup::DiagnosticsLookup():
- m_arena(2048)
+static DiagnosticsLookup* _getDiagnosticLookupSingleton()
{
- // TODO: We should eventually have a more formal system for associating individual
- // diagnostics, or groups of diagnostics, with user-exposed names for use when
- // enabling/disabling warnings (or turning warnings into errors, etc.).
- //
- // For now we build a map from diagnostic name to it's entry. Two entries are typically
- // added - the 'original name' as associated with the diagnostic in lowerCamel, and
- // a dashified version.
-
- for (Index i = 0; i < SLANG_COUNT_OF(kAllDiagnostics); ++i)
- {
- const DiagnosticInfo* diagnostic = kAllDiagnostics[i];
- _add(diagnostic->name, i);
- }
-
- // Add any aliases
- _addAlias("overlappingBindings", "parameterBindingsOverlap");
+ static RefPtr<DiagnosticsLookup> s_lookup = _newDiagnosticsLookup();
+ return s_lookup;
}
DiagnosticInfo const* findDiagnosticByName(UnownedStringSlice const& name)
{
- return DiagnosticsLookup::getSingleton()->findDiagostic(name);
+ return _getDiagnosticLookupSingleton()->findDiagostic(name);
}
-
} // namespace Slang
diff --git a/source/slang/slang-diagnostics.h b/source/slang/slang-diagnostics.h
index 05080989a..05411a90a 100644
--- a/source/slang/slang-diagnostics.h
+++ b/source/slang/slang-diagnostics.h
@@ -1,280 +1,17 @@
-#ifndef RASTER_RENDERER_COMPILE_ERROR_H
-#define RASTER_RENDERER_COMPILE_ERROR_H
+#ifndef SLANG_DIAGNOSTICS_H
+#define SLANG_DIAGNOSTICS_H
#include "../core/slang-basic.h"
#include "../core/slang-writer.h"
-#include "slang-source-loc.h"
-#include "slang-token.h"
+#include "../compiler-core/slang-source-loc.h"
+#include "../compiler-core/slang-diagnostic-sink.h"
+#include "../compiler-core/slang-token.h"
#include "../../slang.h"
namespace Slang
{
- enum class Severity
- {
- Note,
- Warning,
- Error,
- Fatal,
- Internal,
- };
-
- // TODO(tfoley): move this into a source file...
- inline const char* getSeverityName(Severity severity)
- {
- switch (severity)
- {
- case Severity::Note: return "note";
- case Severity::Warning: return "warning";
- case Severity::Error: return "error";
- case Severity::Fatal: return "fatal error";
- case Severity::Internal: return "internal error";
- default: return "unknown error";
- }
- }
-
- // A structure to be used in static data describing different
- // diagnostic messages.
- struct DiagnosticInfo
- {
- int id;
- Severity severity;
- char const* name; ///< Unique name
- char const* messageFormat;
- };
-
- class Diagnostic
- {
- public:
- String Message;
- SourceLoc loc;
- int ErrorID;
- Severity severity;
-
- Diagnostic()
- {
- ErrorID = -1;
- }
- Diagnostic(
- const String & msg,
- int id,
- const SourceLoc & pos,
- Severity severity)
- : severity(severity)
- {
- Message = msg;
- ErrorID = id;
- loc = pos;
- }
- };
-
- class Name;
-
- //enum class CodeGenTarget;
-
- //enum class Stage : SlangStage;
- //enum class ProfileVersion;
-
- void printDiagnosticArg(StringBuilder& sb, char const* str);
-
- void printDiagnosticArg(StringBuilder& sb, int32_t val);
- void printDiagnosticArg(StringBuilder& sb, uint32_t val);
-
- void printDiagnosticArg(StringBuilder& sb, int64_t val);
- void printDiagnosticArg(StringBuilder& sb, uint64_t val);
-
- void printDiagnosticArg(StringBuilder& sb, double val);
-
- void printDiagnosticArg(StringBuilder& sb, Slang::String const& str);
- void printDiagnosticArg(StringBuilder& sb, Slang::UnownedStringSlice const& str);
- void printDiagnosticArg(StringBuilder& sb, Name* name);
-
- void printDiagnosticArg(StringBuilder& sb, TokenType tokenType);
- void printDiagnosticArg(StringBuilder& sb, Token const& token);
-
- struct IRInst;
- void printDiagnosticArg(StringBuilder& sb, IRInst* irObject);
-
- template<typename T>
- void printDiagnosticArg(StringBuilder& sb, RefPtr<T> ptr)
- {
- printDiagnosticArg(sb, ptr.Ptr());
- }
-
- inline SourceLoc const& getDiagnosticPos(SourceLoc const& pos) { return pos; }
-
- SourceLoc const& getDiagnosticPos(Token const& token);
-
-
- template<typename T>
- SourceLoc getDiagnosticPos(RefPtr<T> const& ptr)
- {
- return getDiagnosticPos(ptr.Ptr());
- }
-
- struct DiagnosticArg
- {
- void* data;
- void (*printFunc)(StringBuilder&, void*);
-
- template<typename T>
- struct Helper
- {
- static void printFunc(StringBuilder& sb, void* data) { printDiagnosticArg(sb, *(T*)data); }
- };
-
- template<typename T>
- DiagnosticArg(T const& arg)
- : data((void*)&arg)
- , printFunc(&Helper<T>::printFunc)
- {}
- };
-
-
- class DiagnosticSink
- {
- public:
- /// Flags to control some aspects of Diagnostic sink behavior
- typedef uint32_t Flags;
- struct Flag
- {
- enum Enum: Flags
- {
- VerbosePath = 0x1, ///< Will display a more verbose path (if available) - such as a canonical or absolute path
- SourceLocationLine = 0x2, ///< If set will display the location line if source is available
- };
- };
-
- /// Used by diagnostic sink to be able to underline tokens. If not defined on the DiagnosticSink,
- /// will only display a caret at the SourceLoc
- typedef UnownedStringSlice(*SourceLocationLexer)(const UnownedStringSlice& text);
-
- /// Get the total amount of errors that have taken place on this DiagnosticSink
- SLANG_FORCE_INLINE int getErrorCount() { return m_errorCount; }
-
- void diagnoseDispatch(SourceLoc const& pos, DiagnosticInfo const& info)
- {
- diagnoseImpl(pos, info, 0, nullptr);
- }
-
- void diagnoseDispatch(SourceLoc const& pos, DiagnosticInfo const& info, DiagnosticArg const& arg0)
- {
- DiagnosticArg const* args[] = { &arg0 };
- diagnoseImpl(pos, info, 1, args);
- }
-
- void diagnoseDispatch(SourceLoc const& pos, DiagnosticInfo const& info, DiagnosticArg const& arg0, DiagnosticArg const& arg1)
- {
- DiagnosticArg const* args[] = { &arg0, &arg1 };
- diagnoseImpl(pos, info, 2, args);
- }
-
- void diagnoseDispatch(SourceLoc const& pos, DiagnosticInfo const& info, DiagnosticArg const& arg0, DiagnosticArg const& arg1, DiagnosticArg const& arg2)
- {
- DiagnosticArg const* args[] = { &arg0, &arg1, &arg2 };
- diagnoseImpl(pos, info, 3, args);
- }
-
- void diagnoseDispatch(SourceLoc const& pos, DiagnosticInfo const& info, DiagnosticArg const& arg0, DiagnosticArg const& arg1, DiagnosticArg const& arg2, DiagnosticArg const& arg3)
- {
- DiagnosticArg const* args[] = { &arg0, &arg1, &arg2, &arg3 };
- diagnoseImpl(pos, info, 4, args);
- }
-
- template<typename P, typename... Args>
- void diagnose(P const& pos, DiagnosticInfo const& info, Args const&... args )
- {
- diagnoseDispatch(getDiagnosticPos(pos), info, args...);
- }
-
- // Add a diagnostic with raw text
- // (used when we get errors from a downstream compiler)
- void diagnoseRaw(Severity severity, char const* message);
- void diagnoseRaw(Severity severity, const UnownedStringSlice& message);
-
- /// During propagation of an exception for an internal
- /// error, note that this source location was involved
- void noteInternalErrorLoc(SourceLoc const& loc);
-
- /// Create a blob containing diagnostics if there were any errors.
- /// *note* only works if writer is not set, the blob is created from outputBuffer
- SlangResult getBlobIfNeeded(ISlangBlob** outBlob);
-
- /// Get the source manager used
- SourceManager* getSourceManager() const { return m_sourceManager; }
- /// Set the source manager used for lookup of source locs
- void setSourceManager(SourceManager* inSourceManager) { m_sourceManager = inSourceManager; }
-
- /// Get the flags
- Flags getFlags() const { return m_flags; }
- /// Set a flag
- void setFlag(Flag::Enum flag) { m_flags |= Flags(flag); }
- /// Reset a flag
- void resetFlag(Flag::Enum flag) { m_flags &= ~Flags(flag); }
- /// Test if flag is set
- bool isFlagSet(Flag::Enum flag) { return (m_flags & Flags(flag)) != 0; }
-
- /// Get the (optional) diagnostic sink lexer. This is used to
- /// improve quality of highlighting a locations token. If not set, will just have a single
- /// character caret at location
- SourceLocationLexer getSourceLocationLexer() const { return m_sourceLocationLexer; }
-
- /// Ctor
- DiagnosticSink(SourceManager* sourceManager, SourceLocationLexer sourceLocationLexer)
- : m_sourceManager(sourceManager),
- m_sourceLocationLexer(sourceLocationLexer)
- {
- // If we have a source location lexer, we'll by default enable source location output
- if (sourceLocationLexer)
- {
- setFlag(Flag::SourceLocationLine);
- }
- }
-
- // Public members
-
- /// The outputBuffer will contain any diagnostics *iff* the writer is *not* set
- StringBuilder outputBuffer;
- /// If a writer is set output will *not* be written to the outputBuffer
- ISlangWriter* writer = nullptr;
-
- protected:
- void diagnoseImpl(SourceLoc const& pos, DiagnosticInfo const& info, int argCount, DiagnosticArg const* const* args);
-
- int m_errorCount = 0;
- int m_internalErrorLocsNoted = 0;
-
- Flags m_flags = 0;
-
- // The source manager to use when mapping source locations to file+line info
- SourceManager* m_sourceManager = nullptr;
-
- SourceLocationLexer m_sourceLocationLexer;
- };
-
- /// An `ISlangWriter` that writes directly to a diagnostic sink.
- class DiagnosticSinkWriter : public AppendBufferWriter
- {
- public:
- typedef AppendBufferWriter Super;
-
- DiagnosticSinkWriter(DiagnosticSink* sink)
- : Super(WriterFlag::IsStatic)
- , m_sink(sink)
- {}
-
- // ISlangWriter
- SLANG_NO_THROW virtual SlangResult SLANG_MCALL write(const char* chars, size_t numChars) SLANG_OVERRIDE
- {
- m_sink->diagnoseRaw(Severity::Note, UnownedStringSlice(chars, chars+numChars));
- return SLANG_OK;
- }
-
- private:
- DiagnosticSink* m_sink = nullptr;
- };
-
DiagnosticInfo const* findDiagnosticByName(UnownedStringSlice const& name);
namespace Diagnostics
diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp
index a0fa71fee..1b0fe7c44 100644
--- a/source/slang/slang-emit-c-like.cpp
+++ b/source/slang/slang-emit-c-like.cpp
@@ -2,6 +2,8 @@
#include "slang-emit-c-like.h"
#include "../core/slang-writer.h"
+#include "../compiler-core/slang-name.h"
+
#include "slang-ir-bind-existentials.h"
#include "slang-ir-dce.h"
#include "slang-ir-entry-point-uniforms.h"
@@ -17,7 +19,7 @@
#include "slang-legalize-types.h"
#include "slang-lower-to-ir.h"
#include "slang-mangle.h"
-#include "slang-name.h"
+
#include "slang-syntax.h"
#include "slang-type-layout.h"
#include "slang-visitor.h"
diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp
index c97412cf0..01b682a39 100644
--- a/source/slang/slang-emit.cpp
+++ b/source/slang/slang-emit.cpp
@@ -4,6 +4,8 @@
#include "../core/slang-writer.h"
#include "../core/slang-type-text-util.h"
+#include "../compiler-core/slang-name.h"
+
#include "slang-ir-bind-existentials.h"
#include "slang-ir-byte-address-legalize.h"
#include "slang-ir-collect-global-uniforms.h"
@@ -33,7 +35,7 @@
#include "slang-legalize-types.h"
#include "slang-lower-to-ir.h"
#include "slang-mangle.h"
-#include "slang-name.h"
+
#include "slang-syntax.h"
#include "slang-type-layout.h"
#include "slang-visitor.h"
diff --git a/source/slang/slang-file-system.cpp b/source/slang/slang-file-system.cpp
deleted file mode 100644
index 992ae4155..000000000
--- a/source/slang/slang-file-system.cpp
+++ /dev/null
@@ -1,888 +0,0 @@
-#include "slang-file-system.h"
-
-#include "../../slang-com-ptr.h"
-#include "../core/slang-io.h"
-#include "../core/slang-string-util.h"
-
-namespace Slang
-{
-
-// Allocate static const storage for the various interface IDs that the Slang API needs to expose
-static const Guid IID_ISlangUnknown = SLANG_UUID_ISlangUnknown;
-static const Guid IID_ISlangFileSystem = SLANG_UUID_ISlangFileSystem;
-static const Guid IID_ISlangFileSystemExt = SLANG_UUID_ISlangFileSystemExt;
-static const Guid IID_ISlangMutableFileSystem = SLANG_UUID_ISlangMutableFileSystem;
-
-static const Guid IID_SlangCacheFileSystem = SLANG_UUID_CacheFileSystem;
-
-SLANG_FORCE_INLINE static SlangResult _checkExt(FileSystemStyle style) { return Index(style) >= Index(FileSystemStyle::Ext) ? SLANG_OK : SLANG_E_NOT_IMPLEMENTED; }
-SLANG_FORCE_INLINE static SlangResult _checkMutable(FileSystemStyle style) { return Index(style) >= Index(FileSystemStyle::Mutable) ? SLANG_OK : SLANG_E_NOT_IMPLEMENTED; }
-
-SLANG_FORCE_INLINE static bool _canCast(FileSystemStyle style, const Guid& guid)
-{
- if (guid == IID_ISlangUnknown || guid == IID_ISlangFileSystem)
- {
- return true;
- }
- else if (guid == IID_ISlangFileSystemExt)
- {
- return Index(style) >= Index(FileSystemStyle::Ext);
- }
- else if (guid == IID_ISlangMutableFileSystem)
- {
- return Index(style) >= Index(FileSystemStyle::Mutable);
- }
- return false;
-}
-
-static FileSystemStyle _getFileSystemStyle(ISlangFileSystem* system, ComPtr<ISlangFileSystem>& out)
-{
- SLANG_ASSERT(system);
-
- FileSystemStyle style = FileSystemStyle::Load;
-
- if (SLANG_SUCCEEDED(system->queryInterface(IID_ISlangMutableFileSystem, (void**)out.writeRef())))
- {
- style = FileSystemStyle::Mutable;
- }
- else if (SLANG_SUCCEEDED(system->queryInterface(IID_ISlangFileSystemExt, (void**)out.writeRef())))
- {
- style = FileSystemStyle::Ext;
- }
- else
- {
- style = FileSystemStyle::Load;
- out = system;
- }
-
- SLANG_ASSERT(out);
- return style;
-}
-
-// Cacluate a combined path, just using Path:: string processing
-static SlangResult _calcCombinedPath(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** pathOut)
-{
- String relPath;
- switch (fromPathType)
- {
- case SLANG_PATH_TYPE_FILE:
- {
- relPath = Path::combine(Path::getParentDirectory(fromPath), path);
- break;
- }
- case SLANG_PATH_TYPE_DIRECTORY:
- {
- relPath = Path::combine(fromPath, path);
- break;
- }
- }
-
- *pathOut = StringUtil::createStringBlob(relPath).detach();
- return SLANG_OK;
-}
-
-/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! OSFileSystem !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
-
-/* static */OSFileSystem OSFileSystem::g_load(FileSystemStyle::Load);
-/* static */OSFileSystem OSFileSystem::g_ext(FileSystemStyle::Ext);
-/* static */OSFileSystem OSFileSystem::g_mutable(FileSystemStyle::Mutable);
-
-ISlangUnknown* OSFileSystem::getInterface(const Guid& guid)
-{
- return _canCast(m_style, guid) ? static_cast<ISlangFileSystem*>(this) : nullptr;
-}
-
-static String _fixPathDelimiters(const char* pathIn)
-{
-#if SLANG_WINDOWS_FAMILY
- return pathIn;
-#else
- // To allow windows style \ delimiters on other platforms, we convert to our standard delimiter
- String path(pathIn);
- return StringUtil::calcCharReplaced(pathIn, '\\', Path::kPathDelimiter);
-#endif
-}
-
-SlangResult OSFileSystem::getFileUniqueIdentity(const char* pathIn, ISlangBlob** outUniqueIdentity)
-{
- SLANG_RETURN_ON_FAIL(_checkExt(m_style));
-
- // By default we use the canonical path to uniquely identify a file
- return getCanonicalPath(pathIn, outUniqueIdentity);
-}
-
-SlangResult OSFileSystem::getCanonicalPath(const char* path, ISlangBlob** outCanonicalPath)
-{
- SLANG_RETURN_ON_FAIL(_checkExt(m_style));
-
- String canonicalPath;
- SLANG_RETURN_ON_FAIL(Path::getCanonical(_fixPathDelimiters(path), canonicalPath));
- *outCanonicalPath = StringUtil::createStringBlob(canonicalPath).detach();
- return SLANG_OK;
-}
-
-SlangResult OSFileSystem::getSimplifiedPath(const char* pathIn, ISlangBlob** outSimplifiedPath)
-{
- SLANG_RETURN_ON_FAIL(_checkExt(m_style));
-
- String simplifiedPath = Path::simplify(pathIn);
- *outSimplifiedPath = StringUtil::createStringBlob(simplifiedPath).detach();
- return SLANG_OK;
-}
-
-SlangResult OSFileSystem::calcCombinedPath(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** pathOut)
-{
- SLANG_RETURN_ON_FAIL(_checkExt(m_style));
-
- // Don't need to fix delimiters - because combine path handles both path delimiter types
- return _calcCombinedPath(fromPathType, fromPath, path, pathOut);
-}
-
-SlangResult SLANG_MCALL OSFileSystem::getPathType(const char* pathIn, SlangPathType* pathTypeOut)
-{
- SLANG_RETURN_ON_FAIL(_checkExt(m_style));
-
- return Path::getPathType(_fixPathDelimiters(pathIn), pathTypeOut);
-}
-
-
-SlangResult OSFileSystem::loadFile(char const* pathIn, ISlangBlob** outBlob)
-{
- // Default implementation that uses the `core` libraries facilities for talking to the OS filesystem.
- //
- // TODO: we might want to conditionally compile these in, so that
- // a user could create a build of Slang that doesn't include any OS
- // filesystem calls.
-
- const String path = _fixPathDelimiters(pathIn);
- if (!File::exists(path))
- {
- return SLANG_E_NOT_FOUND;
- }
-
- ScopedAllocation alloc;
- SLANG_RETURN_ON_FAIL(File::readAllBytes(path, alloc));
- *outBlob = RawBlob::moveCreate(alloc).detach();
- return SLANG_OK;
-}
-
-SlangResult OSFileSystem::enumeratePathContents(const char* path, FileSystemContentsCallBack callback, void* userData)
-{
- SLANG_RETURN_ON_FAIL(_checkExt(m_style));
-
- struct Visitor : Path::Visitor
- {
- void accept(Path::Type type, const UnownedStringSlice& filename) SLANG_OVERRIDE
- {
- m_buffer.Clear();
- m_buffer.append(filename);
-
- SlangPathType pathType;
- switch (type)
- {
- case Path::Type::File: pathType = SLANG_PATH_TYPE_FILE; break;
- case Path::Type::Directory: pathType = SLANG_PATH_TYPE_DIRECTORY; break;
- default: return;
- }
-
- m_callback(pathType, m_buffer.getBuffer(), m_userData);
- }
-
- Visitor(FileSystemContentsCallBack callback, void* userData) :
- m_callback(callback),
- m_userData(userData)
- {
- }
- StringBuilder m_buffer;
- FileSystemContentsCallBack m_callback;
- void* m_userData;
- };
-
- Visitor visitor(callback, userData);
- Path::find(path, nullptr, &visitor);
-
- return SLANG_OK;
-}
-
-SlangResult OSFileSystem::saveFile(const char* pathIn, const void* data, size_t size)
-{
- SLANG_RETURN_ON_FAIL(_checkMutable(m_style));
-
- const String path = _fixPathDelimiters(pathIn);
-
- try
- {
- FileStream stream(pathIn, FileMode::Create, FileAccess::Write, FileShare::ReadWrite);
-
- int64_t numWritten = stream.write(data, size);
-
- if (numWritten != int64_t(size))
- {
- return SLANG_FAIL;
- }
-
- }
- catch (const IOException&)
- {
- return SLANG_E_CANNOT_OPEN;
- }
-
- return SLANG_OK;
-}
-
-SlangResult OSFileSystem::remove(const char* path)
-{
- SLANG_RETURN_ON_FAIL(_checkMutable(m_style));
- return Path::remove(path);
-}
-
-SlangResult OSFileSystem::createDirectory(const char* path)
-{
- SLANG_RETURN_ON_FAIL(_checkMutable(m_style));
- return Path::createDirectory(path);
-}
-
-// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CacheFileSystem !!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-/* static */ const Result CacheFileSystem::s_compressedResultToResult[] =
-{
- SLANG_E_UNINITIALIZED,
- SLANG_OK, ///< Ok
- SLANG_E_NOT_FOUND, ///< File not found
- SLANG_E_CANNOT_OPEN, ///< CannotOpen,
- SLANG_FAIL, ///< Fail
-};
-
-/* static */CacheFileSystem::CompressedResult CacheFileSystem::toCompressedResult(Result res)
-{
- if (SLANG_SUCCEEDED(res))
- {
- return CompressedResult::Ok;
- }
- switch (res)
- {
- case SLANG_E_CANNOT_OPEN: return CompressedResult::CannotOpen;
- case SLANG_E_NOT_FOUND: return CompressedResult::NotFound;
- default: return CompressedResult::Fail;
- }
-}
-
-SLANG_NO_THROW SlangResult SLANG_MCALL CacheFileSystem::queryInterface(SlangUUID const& uuid, void** outObject)
-{
- if (uuid == IID_SlangCacheFileSystem)
- {
- *outObject = this;
- return SLANG_OK;
- }
-
- if (_canCast(FileSystemStyle::Ext, uuid))
- {
- addReference();
- *outObject = static_cast<ISlangFileSystemExt*>(this);
- return SLANG_OK;
- }
- return SLANG_E_NO_INTERFACE;
-}
-
-CacheFileSystem::CacheFileSystem(ISlangFileSystem* fileSystem, UniqueIdentityMode uniqueIdentityMode, PathStyle pathStyle)
-{
- setInnerFileSystem(fileSystem, uniqueIdentityMode, pathStyle);
-}
-
-CacheFileSystem::~CacheFileSystem()
-{
- for (const auto& pair : m_uniqueIdentityMap)
- {
- PathInfo* pathInfo = pair.Value;
- delete pathInfo;
- }
-}
-
-void CacheFileSystem::setInnerFileSystem(ISlangFileSystem* fileSystem, UniqueIdentityMode uniqueIdentityMode, PathStyle pathStyle)
-{
- m_fileSystem = fileSystem;
-
- m_uniqueIdentityMode = uniqueIdentityMode;
- m_pathStyle = pathStyle;
-
- m_fileSystemExt.setNull();
-
- if (fileSystem)
- {
- // Try to get the more sophisticated interface
- fileSystem->queryInterface(IID_ISlangFileSystemExt, (void**)m_fileSystemExt.writeRef());
- }
-
- switch (m_uniqueIdentityMode)
- {
- case UniqueIdentityMode::Default:
- case UniqueIdentityMode::FileSystemExt:
- {
- // If it's not a complete file system, we will default to SimplifyAndHash style by default
- m_uniqueIdentityMode = m_fileSystemExt ? UniqueIdentityMode::FileSystemExt : UniqueIdentityMode::SimplifyPathAndHash;
- break;
- }
- default: break;
- }
-
- if (pathStyle == PathStyle::Default)
- {
- // We'll assume it's simplify-able
- m_pathStyle = PathStyle::Simplifiable;
- // If we have fileSystemExt, we defer to that
- if (m_fileSystemExt)
- {
- // We just defer to the m_fileSystem
- m_pathStyle = PathStyle::FileSystemExt;
- }
- }
-
- // It can't be default
- SLANG_ASSERT(m_uniqueIdentityMode != UniqueIdentityMode::Default);
-}
-
-void CacheFileSystem::clearCache()
-{
- for (const auto& pair : m_uniqueIdentityMap)
- {
- PathInfo* pathInfo = pair.Value;
- delete pathInfo;
- }
-
- m_uniqueIdentityMap.Clear();
- m_pathMap.Clear();
-
- if (m_fileSystemExt)
- {
- m_fileSystemExt->clearCache();
- }
-}
-
-
-// Determines if we can simplify a path for a given mode
-static bool _canSimplifyPath(CacheFileSystem::UniqueIdentityMode mode)
-{
- typedef CacheFileSystem::UniqueIdentityMode UniqueIdentityMode;
- switch (mode)
- {
- case UniqueIdentityMode::SimplifyPath:
- case UniqueIdentityMode::SimplifyPathAndHash:
- {
- return true;
- }
- default:
- {
- return false;
- }
- }
-}
-
-SlangResult CacheFileSystem::enumeratePathContents(const char* path, FileSystemContentsCallBack callback, void* userData)
-{
- if (m_fileSystemExt)
- {
- return m_fileSystemExt->enumeratePathContents(path, callback, userData);
- }
-
- // Okay.. the contents of the 'cache' *is* the filesystem. So lets iterate over that
- // This will win no prizes for efficiency, but that is unlikely to matter for typical usage
-
- if (!_canSimplifyPath(m_uniqueIdentityMode))
- {
- // As it stands if we can't simplify paths, it's kind of hard to make this
- // all work. As we use the simplified path cache
- return SLANG_E_NOT_IMPLEMENTED;
- }
-
- // Simplify the path
- String simplifiedPath = Path::simplify(path);
-
- // If the simplified path is just a . then we don't have any prefix
- if (simplifiedPath == ".")
- {
- simplifiedPath = "";
- }
-
- for (auto& pair : m_pathMap)
- {
- // NOTE! The currentPath can be a *non* simplified path (the m_pathMap is the cache of paths simplified and other to a file/directory)
- // Also note that there will always be the simplified version of the path in cache.
- const String& currentPath = pair.Key;
-
- // If it doesn't start with simplified path, then it can't be a hit
- if (!currentPath.startsWith(simplifiedPath))
- {
- continue;
- }
-
- UnownedStringSlice remaining(currentPath.getBuffer() + simplifiedPath.getLength(), currentPath.end());
-
- // If it starts with a / delimiter strip it
- if (remaining.getLength() > 0 && remaining[0] == '/')
- {
- remaining = UnownedStringSlice(remaining.begin() + 1, remaining.end());
- }
-
- // If it has a path separator then it's either not simplified - so we ignore (we only want to invoke on the simplified path version as there is only one
- // of these for every PathInfo)
- // or it is a child file/directory, and so we ignore that too.
- if (remaining.indexOf('/') >= 0 || remaining.indexOf('\\') >= 0)
- {
- continue;
- }
-
- // We *know* that remaining comes from the end of currentPath .We also know currentPath is zero terminated.
- // So we can just use (normally this would be a problem because UnownedStringSlice is generally *not* followed by zero termination.
- const char* foundPath = remaining.begin();
- // Let's check that fact...
- SLANG_ASSERT(foundPath[remaining.getLength()] == 0);
-
- PathInfo* pathInfo = pair.Value;
-
- SlangPathType pathType;
- if (SLANG_FAILED(_getPathType(pathInfo, currentPath.getBuffer(), &pathType)))
- {
- continue;
- }
-
- callback(pathType, foundPath, userData);
- }
-
- return SLANG_OK;
-}
-
-
-SlangResult CacheFileSystem::_calcUniqueIdentity(const String& path, String& outUniqueIdentity, ComPtr<ISlangBlob>& outFileContents)
-{
- switch (m_uniqueIdentityMode)
- {
- case UniqueIdentityMode::FileSystemExt:
- {
- // Try getting the uniqueIdentity by asking underlying file system
- ComPtr<ISlangBlob> uniqueIdentity;
- SLANG_RETURN_ON_FAIL(m_fileSystemExt->getFileUniqueIdentity(path.getBuffer(), uniqueIdentity.writeRef()));
- // Get the path as a string
- outUniqueIdentity = StringUtil::getString(uniqueIdentity);
- return SLANG_OK;
- }
- case UniqueIdentityMode::Path:
- {
- outUniqueIdentity = path;
- return SLANG_OK;
- }
- case UniqueIdentityMode::SimplifyPath:
- {
- outUniqueIdentity = Path::simplify(path);
- // If it still has relative elements can't uniquely identify, so give up
- return Path::hasRelativeElement(outUniqueIdentity) ? SLANG_FAIL : SLANG_OK;
- }
- case UniqueIdentityMode::SimplifyPathAndHash:
- case UniqueIdentityMode::Hash:
- {
- // If we don't have a file system -> assume cannot be found
- if (m_fileSystem == nullptr)
- {
- return SLANG_E_NOT_FOUND;
- }
-
- // I can only see if this is the same file as already loaded by loading the file and doing a hash
- Result res = m_fileSystem->loadFile(path.getBuffer(), outFileContents.writeRef());
- if (SLANG_FAILED(res) || outFileContents == nullptr)
- {
- return SLANG_FAIL;
- }
-
- // Calculate the hash on the contents
- const uint64_t hash = getHashCode64((const char*)outFileContents->getBufferPointer(), outFileContents->getBufferSize());
-
- String hashString = Path::getFileName(path);
- hashString = hashString.toLower();
-
- hashString.append(':');
-
- // The uniqueIdentity is a combination of name and hash
- hashString.append(hash, 16);
-
- outUniqueIdentity = hashString;
- return SLANG_OK;
- }
- }
-
- return SLANG_FAIL;
-}
-
-CacheFileSystem::PathInfo* CacheFileSystem::_resolveUniqueIdentityCacheInfo(const String& path)
-{
- // Use the path to produce uniqueIdentity information
- ComPtr<ISlangBlob> fileContents;
- String uniqueIdentity;
-
- SlangResult res = _calcUniqueIdentity(path, uniqueIdentity, fileContents);
- if (SLANG_FAILED(res))
- {
- // Was not able to create a uniqueIdentity - return failure as nullptr
- return nullptr;
- }
-
- // Now try looking up by uniqueIdentity path. If not found, add a new result
- PathInfo* pathInfo = nullptr;
- if (!m_uniqueIdentityMap.TryGetValue(uniqueIdentity, pathInfo))
- {
- // Create with found uniqueIdentity
- pathInfo = new PathInfo(uniqueIdentity);
- m_uniqueIdentityMap.Add(uniqueIdentity, pathInfo);
- }
-
- // At this point they must have same uniqueIdentity
- SLANG_ASSERT(pathInfo->getUniqueIdentity() == uniqueIdentity);
-
- // If we have the file contents (because of calc-ing uniqueIdentity), and there isn't a read file blob already
- // store the data as if read, so doesn't get read again
- if (fileContents && !pathInfo->m_fileBlob)
- {
- pathInfo->m_fileBlob = fileContents;
- pathInfo->m_loadFileResult = CompressedResult::Ok;
- }
-
- return pathInfo;
-}
-
-CacheFileSystem::PathInfo* CacheFileSystem::_resolveSimplifiedPathCacheInfo(const String& path)
-{
- // If we can simplify the path, try looking up in path cache with simplified path (as long as it's different!)
- if (_canSimplifyPath(m_uniqueIdentityMode))
- {
- const String simplifiedPath = Path::simplify(path);
- // Only lookup if the path is different - because otherwise will recurse forever...
- if (simplifiedPath != path)
- {
- // This is a recursive call - and will ensure the simplified path is added to the cache
- return _resolvePathCacheInfo(simplifiedPath);
- }
- }
-
- return _resolveUniqueIdentityCacheInfo(path);
-}
-
-CacheFileSystem::PathInfo* CacheFileSystem::_resolvePathCacheInfo(const String& path)
-{
- // Lookup in path cache
- PathInfo* pathInfo;
- if (m_pathMap.TryGetValue(path, pathInfo))
- {
- // Found so done
- return pathInfo;
- }
-
- // Try getting or creating taking into account possible path simplification
- pathInfo = _resolveSimplifiedPathCacheInfo(path);
- // Always add the result to the path cache (even if null)
- m_pathMap.Add(path, pathInfo);
- return pathInfo;
-}
-
-SlangResult CacheFileSystem::loadFile(char const* pathIn, ISlangBlob** blobOut)
-{
- *blobOut = nullptr;
- String path(pathIn);
- PathInfo* info = _resolvePathCacheInfo(path);
- if (!info)
- {
- return SLANG_FAIL;
- }
-
- if (info->m_loadFileResult == CompressedResult::Uninitialized)
- {
- info->m_loadFileResult = toCompressedResult(m_fileSystem->loadFile(path.getBuffer(), info->m_fileBlob.writeRef()));
- }
-
- *blobOut = info->m_fileBlob;
- if (*blobOut)
- {
- (*blobOut)->addRef();
- }
- return toResult(info->m_loadFileResult);
-}
-
-SlangResult CacheFileSystem::getFileUniqueIdentity(const char* path, ISlangBlob** outUniqueIdentity)
-{
- PathInfo* info = _resolvePathCacheInfo(path);
- if (!info)
- {
- return SLANG_E_NOT_FOUND;
- }
- info->m_uniqueIdentity->addRef();
- *outUniqueIdentity = info->m_uniqueIdentity;
- return SLANG_OK;
-}
-
-SlangResult CacheFileSystem::calcCombinedPath(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** pathOut)
-{
- // Just defer to contained implementation
- switch (m_pathStyle)
- {
- case PathStyle::FileSystemExt:
- {
- return m_fileSystemExt->calcCombinedPath(fromPathType, fromPath, path, pathOut);
- }
- default:
- {
- // Just use the default implementation
- return _calcCombinedPath(fromPathType, fromPath, path, pathOut);
- }
- }
-}
-
-SlangResult CacheFileSystem::_getPathType(PathInfo* info, const char* inPath, SlangPathType* outPathType)
-{
- if (info->m_getPathTypeResult == CompressedResult::Uninitialized)
- {
- if (m_fileSystemExt)
- {
- info->m_getPathTypeResult = toCompressedResult(m_fileSystemExt->getPathType(inPath, &info->m_pathType));
- }
- else
- {
- // Okay try to load the file
- if (info->m_loadFileResult == CompressedResult::Uninitialized)
- {
- info->m_loadFileResult = toCompressedResult(m_fileSystem->loadFile(inPath, info->m_fileBlob.writeRef()));
- }
-
- // Make the getPathResult the same as the load result
- info->m_getPathTypeResult = info->m_loadFileResult;
- // Just set to file... the result is what matters in this case
- info->m_pathType = SLANG_PATH_TYPE_FILE;
- }
- }
-
- *outPathType = info->m_pathType;
- return toResult(info->m_getPathTypeResult);
-}
-
-SlangResult CacheFileSystem::getPathType(const char* inPath, SlangPathType* outPathType)
-{
- PathInfo* info = _resolvePathCacheInfo(inPath);
- if (!info)
- {
- return SLANG_E_NOT_FOUND;
- }
-
- return _getPathType(info, inPath, outPathType);
-}
-
-SlangResult CacheFileSystem::getSimplifiedPath(const char* path, ISlangBlob** outSimplifiedPath)
-{
- // If we have a ISlangFileSystemExt we can just pass on the request to it
- switch (m_pathStyle)
- {
- case PathStyle::FileSystemExt:
- {
- return m_fileSystemExt->getSimplifiedPath(path, outSimplifiedPath);
- }
- case PathStyle::Simplifiable:
- {
- String simplifiedPath = Path::simplify(path);
- *outSimplifiedPath = StringUtil::createStringBlob(simplifiedPath).detach();
- return SLANG_OK;
- }
- default: return SLANG_E_NOT_IMPLEMENTED;
- }
-}
-
-SlangResult CacheFileSystem::getCanonicalPath(const char* path, ISlangBlob** outCanonicalPath)
-{
- // A file must exist to get a canonical path...
- PathInfo* info = _resolvePathCacheInfo(path);
- if (!info)
- {
- return SLANG_E_NOT_FOUND;
- }
-
- // We don't have this -> so read it ...
- if (info->m_getCanonicalPathResult == CompressedResult::Uninitialized)
- {
- if (!m_fileSystemExt)
- {
- return SLANG_E_NOT_IMPLEMENTED;
- }
-
- // Try getting the canonicalPath by asking underlying file system
- ComPtr<ISlangBlob> canonicalPathBlob;
- SlangResult res = m_fileSystemExt->getCanonicalPath(path, canonicalPathBlob.writeRef());
-
- if (SLANG_SUCCEEDED(res))
- {
- // Get the path as a string
- String canonicalPath = StringUtil::getString(canonicalPathBlob);
- if (canonicalPath.getLength() > 0)
- {
- info->m_canonicalPath = new StringBlob(canonicalPath);
- }
- else
- {
- res = SLANG_FAIL;
- }
- }
-
- // Save the result
- info->m_getCanonicalPathResult = toCompressedResult(res);
- }
-
- if (info->m_canonicalPath)
- {
- info->m_canonicalPath->addRef();
- }
- *outCanonicalPath = info->m_canonicalPath;
- return SLANG_OK;
-}
-
-/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! RelativeFileSystem !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
-
-RelativeFileSystem::RelativeFileSystem(ISlangFileSystem* fileSystem, const String& relativePath, bool stripPath) :
- m_relativePath(relativePath),
- m_stripPath(stripPath)
-{
- m_style = _getFileSystemStyle(fileSystem, m_fileSystem);
-}
-
-ISlangUnknown* RelativeFileSystem::getInterface(const Guid& guid)
-{
- return _canCast(m_style, guid) ? static_cast<ISlangMutableFileSystem*>(this) : nullptr;
-}
-
-SlangResult RelativeFileSystem::_calcCombinedPathInner(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** outPath)
-{
- ISlangFileSystemExt* fileSystem = _getExt();
- if (fileSystem)
- {
- return fileSystem->calcCombinedPath(fromPathType, fromPath, path, outPath);
- }
- else
- {
- return _calcCombinedPath(fromPathType, fromPath, path, outPath);
- }
-}
-
-SlangResult RelativeFileSystem::_getFixedPath(const char* path, String& outPath)
-{
- ComPtr<ISlangBlob> blob;
- if (m_stripPath)
- {
- String strippedPath = Path::getFileName(path);
- SLANG_RETURN_ON_FAIL(_calcCombinedPathInner(SLANG_PATH_TYPE_DIRECTORY, m_relativePath.getBuffer(), strippedPath.getBuffer(), blob.writeRef()));
- }
- else
- {
- SLANG_RETURN_ON_FAIL(_calcCombinedPathInner(SLANG_PATH_TYPE_DIRECTORY, m_relativePath.getBuffer(), path, blob.writeRef()));
- }
-
- outPath = StringUtil::getString(blob);
- return SLANG_OK;
-}
-
-SlangResult RelativeFileSystem::loadFile(char const* path, ISlangBlob** outBlob)
-{
- String fixedPath;
- SLANG_RETURN_ON_FAIL(_getFixedPath(path, fixedPath));
- return m_fileSystem->loadFile(fixedPath.getBuffer(), outBlob);
-}
-
-SlangResult RelativeFileSystem::getFileUniqueIdentity(const char* path, ISlangBlob** outUniqueIdentity)
-{
- auto fileSystem = _getExt();
- if (!fileSystem) return SLANG_E_NOT_IMPLEMENTED;
-
- String fixedPath;
- SLANG_RETURN_ON_FAIL(_getFixedPath(path, fixedPath));
- return fileSystem->getFileUniqueIdentity(fixedPath.getBuffer(), outUniqueIdentity);
-}
-
-SlangResult RelativeFileSystem::calcCombinedPath(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** outPath)
-{
- auto fileSystem = _getExt();
- if (!fileSystem) return SLANG_E_NOT_IMPLEMENTED;
-
- String fixedFromPath;
- SLANG_RETURN_ON_FAIL(_getFixedPath(fromPath, fixedFromPath));
-
- return fileSystem->calcCombinedPath(fromPathType, fixedFromPath.getBuffer(), path, outPath);
-}
-
-SlangResult RelativeFileSystem::getPathType(const char* path, SlangPathType* outPathType)
-{
- auto fileSystem = _getExt();
- if (!fileSystem) return SLANG_E_NOT_IMPLEMENTED;
-
- String fixedPath;
- SLANG_RETURN_ON_FAIL(_getFixedPath(path, fixedPath));
- return fileSystem->getPathType(fixedPath.getBuffer(), outPathType);
-}
-
-SlangResult RelativeFileSystem::getSimplifiedPath(const char* path, ISlangBlob** outSimplifiedPath)
-{
- auto fileSystem = _getExt();
- if (!fileSystem) return SLANG_E_NOT_IMPLEMENTED;
-
- return fileSystem->getSimplifiedPath(path, outSimplifiedPath);
-}
-
-SlangResult RelativeFileSystem::getCanonicalPath(const char* path, ISlangBlob** outCanonicalPath)
-{
- auto fileSystem = _getExt();
- if (!fileSystem) return SLANG_E_NOT_IMPLEMENTED;
-
- String fixedPath;
- SLANG_RETURN_ON_FAIL(_getFixedPath(path, fixedPath));
- return fileSystem->getCanonicalPath(fixedPath.getBuffer(), outCanonicalPath);
-}
-
-void RelativeFileSystem::clearCache()
-{
- auto fileSystem = _getExt();
- if (!fileSystem) return;
-
- fileSystem->clearCache();
-}
-
-SlangResult RelativeFileSystem::enumeratePathContents(const char* path, FileSystemContentsCallBack callback, void* userData)
-{
- auto fileSystem = _getExt();
- if (!fileSystem) return SLANG_E_NOT_IMPLEMENTED;
-
- String fixedPath;
- SLANG_RETURN_ON_FAIL(_getFixedPath(path, fixedPath));
- return fileSystem->enumeratePathContents(fixedPath.getBuffer(), callback, userData);
-}
-
-SlangResult RelativeFileSystem::saveFile(const char* path, const void* data, size_t size)
-{
- auto fileSystem = _getMutable();
- if (!fileSystem) return SLANG_E_NOT_IMPLEMENTED;
-
- String fixedPath;
- SLANG_RETURN_ON_FAIL(_getFixedPath(path, fixedPath));
- return fileSystem->saveFile(fixedPath.getBuffer(), data, size);
-}
-
-SlangResult RelativeFileSystem::remove(const char* path)
-{
- auto fileSystem = _getMutable();
- if (!fileSystem) return SLANG_E_NOT_IMPLEMENTED;
-
- String fixedPath;
- SLANG_RETURN_ON_FAIL(_getFixedPath(path, fixedPath));
- return fileSystem->remove(fixedPath.getBuffer());
-}
-
-SlangResult RelativeFileSystem::createDirectory(const char* path)
-{
- auto fileSystem = _getMutable();
- if (!fileSystem) return SLANG_E_NOT_IMPLEMENTED;
-
- String fixedPath;
- SLANG_RETURN_ON_FAIL(_getFixedPath(path, fixedPath));
- return fileSystem->createDirectory(fixedPath.getBuffer());
-}
-
-}
diff --git a/source/slang/slang-file-system.h b/source/slang/slang-file-system.h
deleted file mode 100644
index d5145404d..000000000
--- a/source/slang/slang-file-system.h
+++ /dev/null
@@ -1,253 +0,0 @@
-#ifndef SLANG_FILE_SYSTEM_H_INCLUDED
-#define SLANG_FILE_SYSTEM_H_INCLUDED
-
-#include "../../slang.h"
-#include "../../slang-com-helper.h"
-#include "../../slang-com-ptr.h"
-
-#include "../core/slang-blob.h"
-
-#include "../core/slang-string-util.h"
-#include "../core/slang-dictionary.h"
-
-namespace Slang
-{
-
-enum class FileSystemStyle
-{
- Load, ///< Equivalent to ISlangFileSystem
- Ext, ///< Equivalent to ISlangFileSystemExt
- Mutable, ///< Equivalent to ISlangModifyableFileSystem
-};
-
-// Can be used for all styles of file system
-class OSFileSystem : public ISlangMutableFileSystem
-{
-public:
- // ISlangUnknown
- // override ref counting, as DefaultFileSystem is singleton
- SLANG_IUNKNOWN_QUERY_INTERFACE
- SLANG_NO_THROW uint32_t SLANG_MCALL addRef() SLANG_OVERRIDE { return 1; }
- SLANG_NO_THROW uint32_t SLANG_MCALL release() SLANG_OVERRIDE { return 1; }
-
- // ISlangFileSystem
- virtual SLANG_NO_THROW SlangResult SLANG_MCALL loadFile(char const* path, ISlangBlob** outBlob) SLANG_OVERRIDE;
-
- // ISlangFileSystemExt
- virtual SLANG_NO_THROW SlangResult SLANG_MCALL getFileUniqueIdentity(const char* path, ISlangBlob** uniqueIdentityOut) SLANG_OVERRIDE;
- virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcCombinedPath(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** pathOut) SLANG_OVERRIDE;
- virtual SLANG_NO_THROW SlangResult SLANG_MCALL getPathType(const char* path, SlangPathType* pathTypeOut) SLANG_OVERRIDE;
- virtual SLANG_NO_THROW SlangResult SLANG_MCALL getSimplifiedPath(const char* path, ISlangBlob** outSimplifiedPath) SLANG_OVERRIDE;
- virtual SLANG_NO_THROW SlangResult SLANG_MCALL getCanonicalPath(const char* path, ISlangBlob** outCanonicalPath) SLANG_OVERRIDE;
- virtual SLANG_NO_THROW void SLANG_MCALL clearCache() SLANG_OVERRIDE {}
- virtual SLANG_NO_THROW SlangResult SLANG_MCALL enumeratePathContents(const char* path, FileSystemContentsCallBack callback, void* userData) SLANG_OVERRIDE;
-
- // ISlangModifyableFileSystem
- virtual SLANG_NO_THROW SlangResult SLANG_MCALL saveFile(const char* path, const void* data, size_t size) SLANG_OVERRIDE;
- virtual SLANG_NO_THROW SlangResult SLANG_MCALL remove(const char* path) SLANG_OVERRIDE;
- virtual SLANG_NO_THROW SlangResult SLANG_MCALL createDirectory(const char* path) SLANG_OVERRIDE;
-
- /// Get a default instance
- static ISlangFileSystem* getLoadSingleton() { return &g_load; }
- static ISlangFileSystemExt* getExtSingleton() { return &g_ext; }
- static ISlangMutableFileSystem* getMutableSingleton() { return &g_mutable; }
-
-private:
-
- /// Make so not constructible
- OSFileSystem(FileSystemStyle style):
- m_style(style)
- {}
-
- virtual ~OSFileSystem() {}
-
- ISlangUnknown* getInterface(const Guid& guid);
-
- FileSystemStyle m_style;
-
- static OSFileSystem g_load;
- static OSFileSystem g_ext;
- static OSFileSystem g_mutable;
-};
-
- #define SLANG_UUID_CacheFileSystem { 0x2f4d1d03, 0xa0d1, 0x434b, { 0x87, 0x7a, 0x65, 0x5, 0xa4, 0xa0, 0x9a, 0x3b } };
-
-/* Wraps an underlying ISlangFileSystem or ISlangFileSystemExt and provides caching,
-as well as emulation of methods if only has ISlangFileSystem interface. Will query capabilities
-of the interface on the constructor.
-
-NOTE! That this behavior is the same as previously in that....
-1) calcRelativePath, just returns the path as processed by the Path:: methods
-2) getUniqueIdentity behavior depends on the UniqueIdentityMode.
-*/
-class CacheFileSystem: public ISlangFileSystemExt, public RefObject
-{
- public:
-
- enum class PathStyle
- {
- Default, ///< Pass to say use the default
- Simplifiable, ///< It can be simplified by Path::Simplify
- FileSystemExt, ///< Use file system
- };
-
- enum UniqueIdentityMode
- {
- Default, ///< If passed, will default to the others depending on what kind of ISlangFileSystem is passed in
- Path, ///< Just use the path as is (old style slang behavior)
- SimplifyPath, ///< Use the input path 'simplified' (ie removing . and .. aspects)
- Hash, ///< Use hashing
- SimplifyPathAndHash, ///< Tries simplifying path first, and if that doesn't work it hashes
- FileSystemExt, ///< Use the file system extended interface.
- };
-
- /* Cannot change order/add members without changing s_compressedResultToResult */
- enum class CompressedResult: uint8_t
- {
- Uninitialized, ///< Holds no value
- Ok, ///< Ok
- NotFound, ///< File not found
- CannotOpen, ///< Cannot open
- Fail, ///< Generic failure
- CountOf,
- };
-
- struct PathInfo
- {
- PathInfo(const String& uniqueIdentity)
- {
- m_uniqueIdentity = new StringBlob(uniqueIdentity);
- m_uniqueIdentity->addRef();
-
- m_loadFileResult = CompressedResult::Uninitialized;
- m_getPathTypeResult = CompressedResult::Uninitialized;
- m_getCanonicalPathResult = CompressedResult::Uninitialized;
-
- m_pathType = SLANG_PATH_TYPE_FILE;
- }
-
- /// Get the unique identity path as a string
- const String& getUniqueIdentity() const { SLANG_ASSERT(m_uniqueIdentity); return m_uniqueIdentity->getString(); }
-
- RefPtr<StringBlob> m_uniqueIdentity;
- CompressedResult m_loadFileResult;
- CompressedResult m_getPathTypeResult;
- CompressedResult m_getCanonicalPathResult;
-
- SlangPathType m_pathType;
- ComPtr<ISlangBlob> m_fileBlob;
- RefPtr<StringBlob> m_canonicalPath;
- };
-
- Dictionary<String, PathInfo*>& getPathMap() { return m_pathMap; }
- Dictionary<String, PathInfo*>& getUniqueMap() { return m_uniqueIdentityMap; }
-
- // ISlangUnknown
- SLANG_NO_THROW SlangResult SLANG_MCALL queryInterface(SlangUUID const& uuid, void** outObject) SLANG_OVERRIDE;
- SLANG_REF_OBJECT_IUNKNOWN_ADD_REF
- SLANG_REF_OBJECT_IUNKNOWN_RELEASE
-
- // ISlangFileSystem
- virtual SLANG_NO_THROW SlangResult SLANG_MCALL loadFile(char const* path, ISlangBlob** outBlob) SLANG_OVERRIDE;
-
- // ISlangFileSystemExt
- virtual SLANG_NO_THROW SlangResult SLANG_MCALL getFileUniqueIdentity(const char* path, ISlangBlob** outUniqueIdentity) SLANG_OVERRIDE;
- virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcCombinedPath(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** pathOut) SLANG_OVERRIDE;
- virtual SLANG_NO_THROW SlangResult SLANG_MCALL getPathType(const char* path, SlangPathType* outPathType) SLANG_OVERRIDE;
- virtual SLANG_NO_THROW SlangResult SLANG_MCALL getSimplifiedPath(const char* path, ISlangBlob** outSimplifiedPath) SLANG_OVERRIDE;
- virtual SLANG_NO_THROW SlangResult SLANG_MCALL getCanonicalPath(const char* path, ISlangBlob** outCanonicalPath) SLANG_OVERRIDE;
- virtual SLANG_NO_THROW void SLANG_MCALL clearCache() SLANG_OVERRIDE;
- virtual SLANG_NO_THROW SlangResult SLANG_MCALL enumeratePathContents(const char* path, FileSystemContentsCallBack callback, void* userData) SLANG_OVERRIDE;
-
- /// Get the unique identity mode
- UniqueIdentityMode getUniqueIdentityMode() const { return m_uniqueIdentityMode; }
- /// Get the path style
- PathStyle getPathStyle() const { return m_pathStyle; }
-
- /// Set the inner file system
- void setInnerFileSystem(ISlangFileSystem* fileSystem, UniqueIdentityMode uniqueIdentityMode = UniqueIdentityMode::Default, PathStyle pathStyle = PathStyle::Default);
-
- /// Ctor
- CacheFileSystem(ISlangFileSystem* fileSystem, UniqueIdentityMode uniqueIdentityMode = UniqueIdentityMode::Default, PathStyle pathStyle = PathStyle::Default);
- /// Dtor
- virtual ~CacheFileSystem();
-
- static CompressedResult toCompressedResult(Result res);
- static Result toResult(CompressedResult compRes) { return s_compressedResultToResult[int(compRes)]; }
- static const Result s_compressedResultToResult[int(CompressedResult::CountOf)];
-
-protected:
-
- /// Given a path, works out a uniqueIdentity, based on the uniqueIdentityMode. outFileContents will be set if file had to be read to produce the uniqueIdentity (ie with Hash)
- SlangResult _calcUniqueIdentity(const String& path, String& outUniqueIdentity, ComPtr<ISlangBlob>& outFileContents);
-
- /// For a given path gets a PathInfo. Can return nullptr, if it is not possible to create the PathInfo for some reason
- PathInfo* _resolvePathCacheInfo(const String& path);
- /// Turns the path into a uniqueIdentity, and then tries to look up in the uniqueIdentityMap.
- PathInfo* _resolveUniqueIdentityCacheInfo(const String& path);
- /// Will simplify the path (if possible) to lookup on the pathCache else will create on uniqueIdentityMap
- PathInfo* _resolveSimplifiedPathCacheInfo(const String& path);
-
- SlangResult _getPathType(PathInfo* pathInfo, const char* inPath, SlangPathType* pathTypeOut);
-
- /* TODO: This may be improved by mapping to a ISlangBlob. This makes output fast and easy, and if constructed
- as a StringBlob, we can just static_cast to get as a string to use internally, instead of constantly converting.
- It is probably the case we cannot do dynamic_cast on ISlangBlob if we don't know where constructed -> if outside of slang codebase
- doing such a cast can cause an exception. So we *never* want to do dynamic cast from blobs which could be created by external code. */
-
- Dictionary<String, PathInfo*> m_pathMap; ///< Maps a path to a PathInfo (and unique identity)
- Dictionary<String, PathInfo*> m_uniqueIdentityMap; ///< Maps a unique identity for a file to its contents. This OWNs the PathInfo.
-
- UniqueIdentityMode m_uniqueIdentityMode; ///< Determines how the 'uniqueIdentity' is produced. Cannot be Default in usage.
- PathStyle m_pathStyle; ///< Style of paths
-
- ComPtr<ISlangFileSystem> m_fileSystem; ///< Must always be set
- ComPtr<ISlangFileSystemExt> m_fileSystemExt; ///< Optionally set -> if nullptr will fall back on the m_fileSystem and emulate all the other methods of ISlangFileSystemExt
-};
-
-class RelativeFileSystem : public ISlangMutableFileSystem, public RefObject
-{
-public:
- SLANG_REF_OBJECT_IUNKNOWN_ALL
-
- // ISlangFileSystem
- virtual SLANG_NO_THROW SlangResult SLANG_MCALL loadFile(char const* path, ISlangBlob** outBlob) SLANG_OVERRIDE;
-
- // ISlangFileSystemExt
- virtual SLANG_NO_THROW SlangResult SLANG_MCALL getFileUniqueIdentity(const char* path, ISlangBlob** outUniqueIdentity) SLANG_OVERRIDE;
- virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcCombinedPath(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** pathOut) SLANG_OVERRIDE;
- virtual SLANG_NO_THROW SlangResult SLANG_MCALL getPathType(const char* path, SlangPathType* outPathType) SLANG_OVERRIDE;
- virtual SLANG_NO_THROW SlangResult SLANG_MCALL getSimplifiedPath(const char* path, ISlangBlob** outSimplifiedPath) SLANG_OVERRIDE;
- virtual SLANG_NO_THROW SlangResult SLANG_MCALL getCanonicalPath(const char* path, ISlangBlob** outCanonicalPath) SLANG_OVERRIDE;
- virtual SLANG_NO_THROW void SLANG_MCALL clearCache() SLANG_OVERRIDE;
- virtual SLANG_NO_THROW SlangResult SLANG_MCALL enumeratePathContents(const char* path, FileSystemContentsCallBack callback, void* userData) SLANG_OVERRIDE;
-
- // ISlangModifyableFileSystem
- virtual SLANG_NO_THROW SlangResult SLANG_MCALL saveFile(const char* path, const void* data, size_t size) SLANG_OVERRIDE;
- virtual SLANG_NO_THROW SlangResult SLANG_MCALL remove(const char* path) SLANG_OVERRIDE;
- virtual SLANG_NO_THROW SlangResult SLANG_MCALL createDirectory(const char* path) SLANG_OVERRIDE;
-
- RelativeFileSystem(ISlangFileSystem* fileSystem, const String& relativePath, bool stripPath = false);
-
-protected:
-
- ISlangFileSystemExt* _getExt() { return Index(m_style) >= Index(FileSystemStyle::Ext) ? reinterpret_cast<ISlangFileSystemExt*>(m_fileSystem.get()) : nullptr; }
- ISlangMutableFileSystem* _getMutable() { return Index(m_style) >= Index(FileSystemStyle::Mutable) ? reinterpret_cast<ISlangMutableFileSystem*>(m_fileSystem.get()) : nullptr; }
-
- SlangResult _calcCombinedPathInner(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** pathOut);
-
- SlangResult _getFixedPath(const char* path, String& outPath);
-
- ISlangUnknown* getInterface(const Guid& guid);
-
- bool m_stripPath;
-
- FileSystemStyle m_style;
- ComPtr<ISlangFileSystem> m_fileSystem; ///< NOTE! Has to match what's in style, such style can be reached via reinterpret_cast
-
- String m_relativePath;
-};
-
-}
-
-#endif // SLANG_FILE_SYSTEM_H_INCLUDED
diff --git a/source/slang/slang-include-system.h b/source/slang/slang-include-system.h
index 3b368b70d..70f6dd81e 100644
--- a/source/slang/slang-include-system.h
+++ b/source/slang/slang-include-system.h
@@ -2,7 +2,7 @@
#define SLANG_INCLUDE_SYSTEM_H
// slang-include-system.h
-#include "slang-source-loc.h"
+#include "../compiler-core/slang-source-loc.h"
namespace Slang
{
diff --git a/source/slang/slang-ir-legalize-types.cpp b/source/slang/slang-ir-legalize-types.cpp
index 5d26741c0..9b95e069d 100644
--- a/source/slang/slang-ir-legalize-types.cpp
+++ b/source/slang/slang-ir-legalize-types.cpp
@@ -10,12 +10,13 @@
// fully specialized (no more generics/interfaces), so
// that the concrete type of everything is known.
+#include "../compiler-core/slang-name.h"
+
#include "slang-ir.h"
#include "slang-ir-clone.h"
#include "slang-ir-insts.h"
#include "slang-legalize-types.h"
#include "slang-mangle.h"
-#include "slang-name.h"
namespace Slang
{
diff --git a/source/slang/slang-ir.h b/source/slang/slang-ir.h
index ce3a5c29a..b27542424 100644
--- a/source/slang/slang-ir.h
+++ b/source/slang/slang-ir.h
@@ -8,11 +8,10 @@
//
#include "../core/slang-basic.h"
-
-#include "slang-source-loc.h"
-
#include "../core/slang-memory-arena.h"
+#include "../compiler-core/slang-source-loc.h"
+
#include "slang-type-system-shared.h"
namespace Slang {
diff --git a/source/slang/slang-legalize-types.h b/source/slang/slang-legalize-types.h
index 1201f669d..8f2a7572f 100644
--- a/source/slang/slang-legalize-types.h
+++ b/source/slang/slang-legalize-types.h
@@ -27,7 +27,8 @@
#include "slang-ir-insts.h"
#include "slang-syntax.h"
#include "slang-type-layout.h"
-#include "slang-name.h"
+
+#include "../compiler-core/slang-name.h"
namespace Slang
{
diff --git a/source/slang/slang-lexer.cpp b/source/slang/slang-lexer.cpp
deleted file mode 100644
index 6c8e9474a..000000000
--- a/source/slang/slang-lexer.cpp
+++ /dev/null
@@ -1,1400 +0,0 @@
-// slang-lexer.cpp
-#include "slang-lexer.h"
-
-// This file implements the lexer/scanner, which is responsible for taking a raw stream of
-// input bytes and turning it into semantically useful tokens.
-//
-
-#include "slang-name.h"
-#include "slang-source-loc.h"
-
-#include <assert.h>
-
-namespace Slang
-{
- Token TokenReader::getEndOfFileToken()
- {
- return Token(TokenType::EndOfFile, UnownedStringSlice::fromLiteral(""), SourceLoc());
- }
-
- const Token* TokenList::begin() const
- {
- SLANG_ASSERT(m_tokens.getCount());
- return &m_tokens[0];
- }
-
- const Token* TokenList::end() const
- {
- SLANG_ASSERT(m_tokens.getCount());
- SLANG_ASSERT(m_tokens[m_tokens.getCount() - 1].type == TokenType::EndOfFile);
- return &m_tokens[m_tokens.getCount() - 1];
- }
-
- TokenSpan::TokenSpan()
- : m_begin(nullptr)
- , m_end (nullptr)
- {}
-
- TokenReader::TokenReader()
- : m_cursor(nullptr)
- , m_end (nullptr)
- {}
-
-
- Token& TokenReader::peekToken()
- {
- return m_nextToken;
- }
-
- TokenType TokenReader::peekTokenType() const
- {
- return m_nextToken.type;
- }
-
- SourceLoc TokenReader::peekLoc() const
- {
- return m_nextToken.loc;
- }
-
- Token TokenReader::advanceToken()
- {
- if (!m_cursor)
- return getEndOfFileToken();
-
- Token token = m_nextToken;
- if (m_cursor < m_end)
- {
- m_cursor++;
- m_nextToken = *m_cursor;
- }
- else
- m_nextToken.type = TokenType::EndOfFile;
- return token;
- }
-
- // Lexer
-
- void Lexer::initialize(
- SourceView* sourceView,
- DiagnosticSink* sink,
- NamePool* namePool,
- MemoryArena* memoryArena,
- OptionFlags optionFlags)
- {
- m_sourceView = sourceView;
- m_sink = sink;
- m_namePool = namePool;
- m_memoryArena = memoryArena;
-
- auto content = sourceView->getContent();
-
- m_begin = content.begin();
- m_cursor = content.begin();
- m_end = content.end();
-
- // Set the start location
- m_startLoc = sourceView->getRange().begin;
-
- m_tokenFlags = TokenFlag::AtStartOfLine | TokenFlag::AfterWhitespace;
- m_lexerFlags = 0;
- m_optionFlags = optionFlags;
- }
-
- Lexer::~Lexer()
- {
- }
-
- enum { kEOF = -1 };
-
- // Get the next input byte, without any handling of
- // escaped newlines, non-ASCII code points, source locations, etc.
- static int _peekRaw(Lexer* lexer)
- {
- // If we are at the end of the input, return a designated end-of-file value
- if(lexer->m_cursor == lexer->m_end)
- return kEOF;
-
- // Otherwise, just look at the next byte
- return *lexer->m_cursor;
- }
-
- // Read one input byte without any special handling (similar to `peekRaw`)
- static int _advanceRaw(Lexer* lexer)
- {
- // The logic here is basically the same as for `peekRaw()`,
- // escape we advance `cursor` if we aren't at the end.
-
- if (lexer->m_cursor == lexer->m_end)
- return kEOF;
-
- return *lexer->m_cursor++;
- }
-
- // When the cursor is already at the first byte of an end-of-line sequence,
- // consume one or two bytes that compose the sequence.
- //
- // Basically, a newline is one of:
- //
- // "\n"
- // "\r"
- // "\r\n"
- // "\n\r"
- //
- // We always look for the longest match possible.
- //
- static void _handleNewLineInner(Lexer* lexer, int c)
- {
- SLANG_ASSERT(c == '\n' || c == '\r');
-
- int d = _peekRaw(lexer);
- if( (c ^ d) == ('\n' ^ '\r') )
- {
- _advanceRaw(lexer);
- }
- }
-
- // Look ahead one code point, dealing with complications like
- // escaped newlines.
- static int _peek(Lexer* lexer)
- {
- // Look at the next raw byte, and decide what to do
- int c = _peekRaw(lexer);
-
- if(c == '\\')
- {
- // We might have a backslash-escaped newline.
- // Look at the next byte (if any) to see.
- //
- // Note(tfoley): We are assuming a null-terminated input here,
- // so that we can safely look at the next byte without issue.
- int d = lexer->m_cursor[1];
- switch (d)
- {
- case '\r': case '\n':
- {
- // The newline was escaped, so return the code point after *that*
-
- int e = lexer->m_cursor[2];
- if ((d ^ e) == ('\r' ^ '\n'))
- return lexer->m_cursor[3];
- return e;
- }
-
- default:
- break;
- }
- }
- // TODO: handle UTF-8 encoding for non-ASCII code points here
-
- // Default case is to just hand along the byte we read as an ASCII code point.
- return c;
- }
-
- // Get the next code point from the input, and advance the cursor.
- static int _advance(Lexer* lexer)
- {
- // We are going to loop, but only as a way of handling
- // escaped line endings.
- for (;;)
- {
- // If we are at the end of the input, then the task is easy.
- if (lexer->m_cursor == lexer->m_end)
- return kEOF;
-
- // Look at the next raw byte, and decide what to do
- int c = *lexer->m_cursor++;
-
- if (c == '\\')
- {
- // We might have a backslash-escaped newline.
- // Look at the next byte (if any) to see.
- //
- // Note(tfoley): We are assuming a null-terminated input here,
- // so that we can safely look at the next byte without issue.
- int d = *lexer->m_cursor;
- switch (d)
- {
- case '\r': case '\n':
- // handle the end-of-line for our source location tracking
- lexer->m_cursor++;
- _handleNewLineInner(lexer, d);
-
- lexer->m_tokenFlags |= TokenFlag::ScrubbingNeeded;
-
- // Now try again, looking at the character after the
- // escaped newline.
- continue;
-
- default:
- break;
- }
- }
-
- // TODO: Need to handle non-ASCII code points.
-
- // Default case is to return the raw byte we saw.
- return c;
- }
- }
-
- static void _handleNewLine(Lexer* lexer)
- {
- int c = _advance(lexer);
- _handleNewLineInner(lexer, c);
- }
-
- static void _lexLineComment(Lexer* lexer)
- {
- for(;;)
- {
- switch(_peek(lexer))
- {
- case '\n': case '\r': case kEOF:
- return;
-
- default:
- _advance(lexer);
- continue;
- }
- }
- }
-
- static void _lexBlockComment(Lexer* lexer)
- {
- for(;;)
- {
- switch(_peek(lexer))
- {
- case kEOF:
- // TODO(tfoley) diagnostic!
- return;
-
- case '\n': case '\r':
- _handleNewLine(lexer);
- continue;
-
- case '*':
- _advance(lexer);
- switch( _peek(lexer) )
- {
- case '/':
- _advance(lexer);
- return;
-
- default:
- continue;
- }
-
- default:
- _advance(lexer);
- continue;
- }
- }
- }
-
- static void _lexHorizontalSpace(Lexer* lexer)
- {
- for(;;)
- {
- switch(_peek(lexer))
- {
- case ' ': case '\t':
- _advance(lexer);
- continue;
-
- default:
- return;
- }
- }
- }
-
- static void _lexIdentifier(Lexer* lexer)
- {
- for(;;)
- {
- int c = _peek(lexer);
- if(('a' <= c ) && (c <= 'z')
- || ('A' <= c) && (c <= 'Z')
- || ('0' <= c) && (c <= '9')
- || (c == '_'))
- {
- _advance(lexer);
- continue;
- }
-
- return;
- }
- }
-
- static SourceLoc _getSourceLoc(Lexer* lexer)
- {
- return lexer->m_startLoc + (lexer->m_cursor - lexer->m_begin);
- }
-
- static void _lexDigits(Lexer* lexer, int base)
- {
- for(;;)
- {
- int c = _peek(lexer);
-
- int digitVal = 0;
- switch(c)
- {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- digitVal = c - '0';
- break;
-
- case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
- if(base <= 10) return;
- digitVal = 10 + c - 'a';
- break;
-
- case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
- if(base <= 10) return;
- digitVal = 10 + c - 'A';
- break;
-
- default:
- // Not more digits!
- return;
- }
-
- if(digitVal >= base)
- {
- char buffer[] = { (char) c, 0 };
- lexer->m_sink->diagnose(_getSourceLoc(lexer), Diagnostics::invalidDigitForBase, buffer, base);
- }
-
- _advance(lexer);
- }
- }
-
- static TokenType _maybeLexNumberSuffix(Lexer* lexer, TokenType tokenType)
- {
- // Be liberal in what we accept here, so that figuring out
- // the semantics of a numeric suffix is left up to the parser
- // and semantic checking logic.
- //
- for( ;;)
- {
- int c = _peek(lexer);
-
- // Accept any alphanumeric character, plus underscores.
- if(('a' <= c ) && (c <= 'z')
- || ('A' <= c) && (c <= 'Z')
- || ('0' <= c) && (c <= '9')
- || (c == '_'))
- {
- _advance(lexer);
- continue;
- }
-
- // Stop at the first character that isn't
- // alphanumeric.
- return tokenType;
- }
- }
-
- static bool _isNumberExponent(int c, int base)
- {
- switch( c )
- {
- default:
- return false;
-
- case 'e': case 'E':
- if(base != 10) return false;
- break;
-
- case 'p': case 'P':
- if(base != 16) return false;
- break;
- }
-
- return true;
- }
-
- static bool _maybeLexNumberExponent(Lexer* lexer, int base)
- {
- if(!_isNumberExponent(_peek(lexer), base))
- return false;
-
- // we saw an exponent marker
- _advance(lexer);
-
- // Now start to read the exponent
- switch( _peek(lexer) )
- {
- case '+': case '-':
- _advance(lexer);
- break;
- }
-
- // TODO(tfoley): it would be an error to not see digits here...
-
- _lexDigits(lexer, 10);
-
- return true;
- }
-
- static TokenType _lexNumberAfterDecimalPoint(Lexer* lexer, int base)
- {
- _lexDigits(lexer, base);
- _maybeLexNumberExponent(lexer, base);
-
- return _maybeLexNumberSuffix(lexer, TokenType::FloatingPointLiteral);
- }
-
- static TokenType _lexNumber(Lexer* lexer, int base)
- {
- // TODO(tfoley): Need to consider whehter to allow any kind of digit separator character.
-
- TokenType tokenType = TokenType::IntegerLiteral;
-
- // At the start of things, we just concern ourselves with digits
- _lexDigits(lexer, base);
-
- if( _peek(lexer) == '.' )
- {
- tokenType = TokenType::FloatingPointLiteral;
-
- _advance(lexer);
- _lexDigits(lexer, base);
- }
-
- if( _maybeLexNumberExponent(lexer, base))
- {
- tokenType = TokenType::FloatingPointLiteral;
- }
-
- _maybeLexNumberSuffix(lexer, tokenType);
- return tokenType;
- }
-
- static int _maybeReadDigit(char const** ioCursor, int base)
- {
- auto& cursor = *ioCursor;
-
- for(;;)
- {
- int c = *cursor;
- switch(c)
- {
- default:
- return -1;
-
- // TODO: need to decide on digit separator characters
- case '_':
- cursor++;
- continue;
-
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- cursor++;
- return c - '0';
-
- case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
- if(base > 10)
- {
- cursor++;
- return 10 + c - 'a';
- }
- return -1;
-
- case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
- if(base > 10)
- {
- cursor++;
- return 10 + c - 'A';
- }
- return -1;
- }
- }
- }
-
- static int _readOptionalBase(char const** ioCursor)
- {
- auto& cursor = *ioCursor;
- if( *cursor == '0' )
- {
- cursor++;
- switch(*cursor)
- {
- case 'x': case 'X':
- cursor++;
- return 16;
-
- case 'b': case 'B':
- cursor++;
- return 2;
-
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- return 8;
-
- default:
- return 10;
- }
- }
-
- return 10;
- }
-
-
-
- IntegerLiteralValue getIntegerLiteralValue(Token const& token, UnownedStringSlice* outSuffix)
- {
- IntegerLiteralValue value = 0;
-
- const UnownedStringSlice content = token.getContent();
-
- char const* cursor = content.begin();
- char const* end = content.end();
-
- int base = _readOptionalBase(&cursor);
-
- for( ;;)
- {
- int digit = _maybeReadDigit(&cursor, base);
- if(digit < 0)
- break;
-
- value = value*base + digit;
- }
-
- if(outSuffix)
- {
- *outSuffix = UnownedStringSlice(cursor, end);
- }
-
- return value;
- }
-
- FloatingPointLiteralValue getFloatingPointLiteralValue(Token const& token, UnownedStringSlice* outSuffix)
- {
- FloatingPointLiteralValue value = 0;
-
- const UnownedStringSlice content = token.getContent();
-
- char const* cursor = content.begin();
- char const* end = content.end();
-
- int radix = _readOptionalBase(&cursor);
-
- bool seenDot = false;
- FloatingPointLiteralValue divisor = 1;
- for( ;;)
- {
- if(*cursor == '.')
- {
- cursor++;
- seenDot = true;
- continue;
- }
-
- int digit = _maybeReadDigit(&cursor, radix);
- if(digit < 0)
- break;
-
- value = value*radix + digit;
-
- if(seenDot)
- {
- divisor *= radix;
- }
- }
-
- // Now read optional exponent
- if(_isNumberExponent(*cursor, radix))
- {
- cursor++;
-
- bool exponentIsNegative = false;
- switch(*cursor)
- {
- default:
- break;
-
- case '-':
- exponentIsNegative = true;
- cursor++;
- break;
-
- case '+':
- cursor++;
- break;
- }
-
- int exponentRadix = 10;
- int exponent = 0;
-
- for(;;)
- {
- int digit = _maybeReadDigit(&cursor, exponentRadix);
- if(digit < 0)
- break;
-
- exponent = exponent*exponentRadix + digit;
- }
-
- FloatingPointLiteralValue exponentBase = 10;
- if(radix == 16)
- {
- exponentBase = 2;
- }
-
- FloatingPointLiteralValue exponentValue = pow(exponentBase, exponent);
-
- if( exponentIsNegative )
- {
- divisor *= exponentValue;
- }
- else
- {
- value *= exponentValue;
- }
- }
-
- value /= divisor;
-
- if(outSuffix)
- {
- *outSuffix = UnownedStringSlice(cursor, end);
- }
-
- return value;
- }
-
- static void _lexStringLiteralBody(Lexer* lexer, char quote)
- {
- for(;;)
- {
- int c = _peek(lexer);
- if(c == quote)
- {
- _advance(lexer);
- return;
- }
-
- switch(c)
- {
- case kEOF:
- lexer->m_sink->diagnose(_getSourceLoc(lexer), Diagnostics::endOfFileInLiteral);
- return;
-
- case '\n': case '\r':
- lexer->m_sink->diagnose(_getSourceLoc(lexer), Diagnostics::newlineInLiteral);
- return;
-
- case '\\':
- // Need to handle various escape sequence cases
- _advance(lexer);
- switch(_peek(lexer))
- {
- case '\'':
- case '\"':
- case '\\':
- case '?':
- case 'a':
- case 'b':
- case 'f':
- case 'n':
- case 'r':
- case 't':
- case 'v':
- _advance(lexer);
- break;
-
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7':
- // octal escape: up to 3 characters
- _advance(lexer);
- for(int ii = 0; ii < 3; ++ii)
- {
- int d = _peek(lexer);
- if(('0' <= d) && (d <= '7'))
- {
- _advance(lexer);
- continue;
- }
- else
- {
- break;
- }
- }
- break;
-
- case 'x':
- // hexadecimal escape: any number of characters
- _advance(lexer);
- for(;;)
- {
- int d = _peek(lexer);
- if(('0' <= d) && (d <= '9')
- || ('a' <= d) && (d <= 'f')
- || ('A' <= d) && (d <= 'F'))
- {
- _advance(lexer);
- continue;
- }
- else
- {
- break;
- }
- }
- break;
-
- // TODO: Unicode escape sequences
-
- }
- break;
-
- default:
- _advance(lexer);
- continue;
- }
- }
- }
-
- String getStringLiteralTokenValue(Token const& token)
- {
- SLANG_ASSERT(token.type == TokenType::StringLiteral
- || token.type == TokenType::CharLiteral);
-
- const UnownedStringSlice content = token.getContent();
-
- char const* cursor = content.begin();
- char const* end = content.end();
- SLANG_UNREFERENCED_VARIABLE(end);
-
- auto quote = *cursor++;
- SLANG_ASSERT(quote == '\'' || quote == '"');
-
- StringBuilder valueBuilder;
- for(;;)
- {
- SLANG_ASSERT(cursor != end);
-
- auto c = *cursor++;
-
- // If we see a closing quote, then we are at the end of the string literal
- if(c == quote)
- {
- SLANG_ASSERT(cursor == end);
- return valueBuilder.ProduceString();
- }
-
- // Characters that don't being escape sequences are easy;
- // just append them to the buffer and move on.
- if(c != '\\')
- {
- valueBuilder.Append(c);
- continue;
- }
-
- // Now we look at another character to figure out the kind of
- // escape sequence we are dealing with:
-
- char d = *cursor++;
-
- switch(d)
- {
- // Simple characters that just needed to be escaped
- case '\'':
- case '\"':
- case '\\':
- case '?':
- valueBuilder.Append(d);
- continue;
-
- // Traditional escape sequences for special characters
- case 'a': valueBuilder.Append('\a'); continue;
- case 'b': valueBuilder.Append('\b'); continue;
- case 'f': valueBuilder.Append('\f'); continue;
- case 'n': valueBuilder.Append('\n'); continue;
- case 'r': valueBuilder.Append('\r'); continue;
- case 't': valueBuilder.Append('\t'); continue;
- case 'v': valueBuilder.Append('\v'); continue;
-
- // Octal escape: up to 3 characterws
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7':
- {
- cursor--;
- int value = 0;
- for(int ii = 0; ii < 3; ++ii)
- {
- d = *cursor;
- if(('0' <= d) && (d <= '7'))
- {
- value = value*8 + (d - '0');
-
- cursor++;
- continue;
- }
- else
- {
- break;
- }
- }
-
- // TODO: add support for appending an arbitrary code point?
- valueBuilder.Append((char) value);
- }
- continue;
-
- // Hexadecimal escape: any number of characters
- case 'x':
- {
- cursor--;
- int value = 0;
- for(;;)
- {
- d = *cursor++;
- int digitValue = 0;
- if(('0' <= d) && (d <= '9'))
- {
- digitValue = d - '0';
- }
- else if( ('a' <= d) && (d <= 'f') )
- {
- digitValue = d - 'a';
- }
- else if( ('A' <= d) && (d <= 'F') )
- {
- digitValue = d - 'A';
- }
- else
- {
- cursor--;
- break;
- }
-
- value = value*16 + digitValue;
- }
-
- // TODO: add support for appending an arbitrary code point?
- valueBuilder.Append((char) value);
- }
- continue;
-
- // TODO: Unicode escape sequences
-
- }
- }
- }
-
- String getFileNameTokenValue(Token const& token)
- {
- const UnownedStringSlice content = token.getContent();
-
- // A file name usually doesn't process escape sequences
- // (this is import on Windows, where `\\` is a valid
- // path separator character).
-
- // Just trim off the first and last characters to remove the quotes
- // (whether they were `""` or `<>`.
- return String(content.begin() + 1, content.end() - 1);
- }
-
-
-
- static TokenType _lexTokenImpl(Lexer* lexer, LexerFlags effectiveFlags)
- {
- if(effectiveFlags & kLexerFlag_ExpectDirectiveMessage)
- {
- for(;;)
- {
- switch(_peek(lexer))
- {
- default:
- _advance(lexer);
- continue;
-
- case kEOF: case '\r': case '\n':
- break;
- }
- break;
- }
- return TokenType::DirectiveMessage;
- }
-
- switch(_peek(lexer))
- {
- default:
- break;
-
- case kEOF:
- if((effectiveFlags & kLexerFlag_InDirective) != 0)
- return TokenType::EndOfDirective;
- return TokenType::EndOfFile;
-
- case '\r': case '\n':
- if((effectiveFlags & kLexerFlag_InDirective) != 0)
- return TokenType::EndOfDirective;
- _handleNewLine(lexer);
- return TokenType::NewLine;
-
- case ' ': case '\t':
- _lexHorizontalSpace(lexer);
- return TokenType::WhiteSpace;
-
- case '.':
- _advance(lexer);
- switch(_peek(lexer))
- {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- return _lexNumberAfterDecimalPoint(lexer, 10);
-
- // TODO(tfoley): handle ellipsis (`...`)
-
- default:
- return TokenType::Dot;
- }
-
- case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- return _lexNumber(lexer, 10);
-
- case '0':
- {
- auto loc = _getSourceLoc(lexer);
- _advance(lexer);
- switch(_peek(lexer))
- {
- default:
- return _maybeLexNumberSuffix(lexer, TokenType::IntegerLiteral);
-
- case '.':
- _advance(lexer);
- return _lexNumberAfterDecimalPoint(lexer, 10);
-
- case 'x': case 'X':
- _advance(lexer);
- return _lexNumber(lexer, 16);
-
- case 'b': case 'B':
- _advance(lexer);
- return _lexNumber(lexer, 2);
-
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- lexer->m_sink->diagnose(loc, Diagnostics::octalLiteral);
- return _lexNumber(lexer, 8);
- }
- }
-
- case 'a': case 'b': case 'c': case 'd': case 'e':
- case 'f': case 'g': case 'h': case 'i': case 'j':
- case 'k': case 'l': case 'm': case 'n': case 'o':
- case 'p': case 'q': case 'r': case 's': case 't':
- case 'u': case 'v': case 'w': case 'x': case 'y':
- case 'z':
- case 'A': case 'B': case 'C': case 'D': case 'E':
- case 'F': case 'G': case 'H': case 'I': case 'J':
- case 'K': case 'L': case 'M': case 'N': case 'O':
- case 'P': case 'Q': case 'R': case 'S': case 'T':
- case 'U': case 'V': case 'W': case 'X': case 'Y':
- case 'Z':
- case '_':
- _lexIdentifier(lexer);
- return TokenType::Identifier;
-
- case '\"':
- _advance(lexer);
- _lexStringLiteralBody(lexer, '\"');
- return TokenType::StringLiteral;
-
- case '\'':
- _advance(lexer);
- _lexStringLiteralBody(lexer, '\'');
- return TokenType::CharLiteral;
-
- case '+':
- _advance(lexer);
- switch(_peek(lexer))
- {
- case '+': _advance(lexer); return TokenType::OpInc;
- case '=': _advance(lexer); return TokenType::OpAddAssign;
- default:
- return TokenType::OpAdd;
- }
-
- case '-':
- _advance(lexer);
- switch(_peek(lexer))
- {
- case '-': _advance(lexer); return TokenType::OpDec;
- case '=': _advance(lexer); return TokenType::OpSubAssign;
- case '>': _advance(lexer); return TokenType::RightArrow;
- default:
- return TokenType::OpSub;
- }
-
- case '*':
- _advance(lexer);
- switch(_peek(lexer))
- {
- case '=': _advance(lexer); return TokenType::OpMulAssign;
- default:
- return TokenType::OpMul;
- }
-
- case '/':
- _advance(lexer);
- switch(_peek(lexer))
- {
- case '=': _advance(lexer); return TokenType::OpDivAssign;
- case '/': _advance(lexer); _lexLineComment(lexer); return TokenType::LineComment;
- case '*': _advance(lexer); _lexBlockComment(lexer); return TokenType::BlockComment;
- default:
- return TokenType::OpDiv;
- }
-
- case '%':
- _advance(lexer);
- switch(_peek(lexer))
- {
- case '=': _advance(lexer); return TokenType::OpModAssign;
- default:
- return TokenType::OpMod;
- }
-
- case '|':
- _advance(lexer);
- switch(_peek(lexer))
- {
- case '|': _advance(lexer); return TokenType::OpOr;
- case '=': _advance(lexer); return TokenType::OpOrAssign;
- default:
- return TokenType::OpBitOr;
- }
-
- case '&':
- _advance(lexer);
- switch(_peek(lexer))
- {
- case '&': _advance(lexer); return TokenType::OpAnd;
- case '=': _advance(lexer); return TokenType::OpAndAssign;
- default:
- return TokenType::OpBitAnd;
- }
-
- case '^':
- _advance(lexer);
- switch(_peek(lexer))
- {
- case '=': _advance(lexer); return TokenType::OpXorAssign;
- default:
- return TokenType::OpBitXor;
- }
-
- case '>':
- _advance(lexer);
- switch(_peek(lexer))
- {
- case '>':
- _advance(lexer);
- switch(_peek(lexer))
- {
- case '=': _advance(lexer); return TokenType::OpShrAssign;
- default: return TokenType::OpRsh;
- }
- case '=': _advance(lexer); return TokenType::OpGeq;
- default:
- return TokenType::OpGreater;
- }
-
- case '<':
- _advance(lexer);
- switch(_peek(lexer))
- {
- case '<':
- _advance(lexer);
- switch(_peek(lexer))
- {
- case '=': _advance(lexer); return TokenType::OpShlAssign;
- default: return TokenType::OpLsh;
- }
- case '=': _advance(lexer); return TokenType::OpLeq;
- default:
- return TokenType::OpLess;
- }
-
- case '=':
- _advance(lexer);
- switch(_peek(lexer))
- {
- case '=': _advance(lexer); return TokenType::OpEql;
- default:
- return TokenType::OpAssign;
- }
-
- case '!':
- _advance(lexer);
- switch(_peek(lexer))
- {
- case '=': _advance(lexer); return TokenType::OpNeq;
- default:
- return TokenType::OpNot;
- }
-
- case '#':
- _advance(lexer);
- switch(_peek(lexer))
- {
- case '#': _advance(lexer); return TokenType::PoundPound;
- default:
- return TokenType::Pound;
- }
-
- case '~': _advance(lexer); return TokenType::OpBitNot;
-
- case ':':
- {
- _advance(lexer);
- if (_peek(lexer) == ':')
- {
- _advance(lexer);
- return TokenType::Scope;
- }
- return TokenType::Colon;
- }
- case ';': _advance(lexer); return TokenType::Semicolon;
- case ',': _advance(lexer); return TokenType::Comma;
-
- case '{': _advance(lexer); return TokenType::LBrace;
- case '}': _advance(lexer); return TokenType::RBrace;
- case '[': _advance(lexer); return TokenType::LBracket;
- case ']': _advance(lexer); return TokenType::RBracket;
- case '(': _advance(lexer); return TokenType::LParent;
- case ')': _advance(lexer); return TokenType::RParent;
-
- case '?': _advance(lexer); return TokenType::QuestionMark;
- case '@': _advance(lexer); return TokenType::At;
- case '$': _advance(lexer); return TokenType::Dollar;
-
- }
-
- // TODO(tfoley): If we ever wanted to support proper Unicode
- // in identifiers, etc., then this would be the right place
- // to perform a more expensive dispatch based on the actual
- // code point (and not just the first byte).
-
- {
- // If none of the above cases matched, then we have an
- // unexpected/invalid character.
-
- auto loc = _getSourceLoc(lexer);
- int c = _advance(lexer);
- if(!(effectiveFlags & kLexerFlag_IgnoreInvalid))
- {
- auto sink = lexer->m_sink;
- if(c >= 0x20 && c <= 0x7E)
- {
- char buffer[] = { (char) c, 0 };
- sink->diagnose(loc, Diagnostics::illegalCharacterPrint, buffer);
- }
- else
- {
- // Fallback: print as hexadecimal
- sink->diagnose(loc, Diagnostics::illegalCharacterHex, String((unsigned char)c, 16));
- }
- }
-
- return TokenType::Invalid;
- }
- }
-
- Token Lexer::lexToken(LexerFlags extraFlags)
- {
- auto& flags = m_tokenFlags;
- for(;;)
- {
- Token token;
- token.loc = _getSourceLoc(this);
-
- char const* textBegin = m_cursor;
-
- auto tokenType = _lexTokenImpl(this, m_lexerFlags | extraFlags);
-
- // The low-level lexer produces tokens for things we want
- // to ignore, such as white space, so we skip them here.
- switch(tokenType)
- {
- case TokenType::Invalid:
- flags = 0;
- continue;
-
- case TokenType::NewLine:
- flags = TokenFlag::AtStartOfLine | TokenFlag::AfterWhitespace;
- continue;
-
- case TokenType::WhiteSpace:
- {
- flags |= TokenFlag::AfterWhitespace;
- continue;
- }
- case TokenType::BlockComment:
- case TokenType::LineComment:
- {
- flags |= TokenFlag::AfterWhitespace;
- if (m_optionFlags & OptionFlag::TokenizeComments)
- {
- // We don't break here, and use the normal token adding logic
- // because we want the behavior to be identical (in terms of flags etc)
- // as if TokenizeComments is not enabled
- char const* textEnd = m_cursor;
-
- token.type = tokenType;
- token.flags = m_tokenFlags;
- token.setContent(UnownedStringSlice(textBegin, textEnd));
-
- return token;
- }
-
- continue;
- }
-
- // We don't want to skip the end-of-file token, but we *do*
- // want to make sure it has appropriate flags to make our life easier
- case TokenType::EndOfFile:
- flags |= TokenFlag::AtStartOfLine | TokenFlag::AfterWhitespace;
- break;
-
- // We will also do some book-keeping around preprocessor directives here:
- //
- // If we see a `#` at the start of a line, then we are entering a
- // preprocessor directive.
- case TokenType::Pound:
- if((flags & TokenFlag::AtStartOfLine) != 0)
- m_lexerFlags |= kLexerFlag_InDirective;
- break;
- //
- // And if we saw an end-of-line during a directive, then we are
- // now leaving that directive.
- //
- case TokenType::EndOfDirective:
- m_lexerFlags &= ~kLexerFlag_InDirective;
- break;
-
- default:
- break;
- }
-
- token.type = tokenType;
-
- char const* textEnd = m_cursor;
-
- // Note(tfoley): `StringBuilder::Append()` seems to crash when appending zero bytes
- if(textEnd != textBegin)
- {
- // "scrubbing" token value here to remove escaped newlines...
- //
- // Only perform this work if we encountered an escaped newline
- // while lexing this token (e.g., keep a flag on the lexer), or
- // do it on-demand when the actual value of the token is needed.
- if (m_tokenFlags & TokenFlag::ScrubbingNeeded)
- {
- // Allocate space that will always be more than enough for stripped contents
- char* startDst = (char*)m_memoryArena->allocateUnaligned(textEnd - textBegin);
- char* dst = startDst;
-
- auto tt = textBegin;
- while (tt != textEnd)
- {
- char c = *tt++;
- if (c == '\\')
- {
- char d = *tt;
- switch (d)
- {
- case '\r': case '\n':
- {
- tt++;
- char e = *tt;
- if ((d ^ e) == ('\r' ^ '\n'))
- {
- tt++;
- }
- }
- continue;
-
- default:
- break;
- }
- }
- *dst++ = c;
- }
- token.setContent(UnownedStringSlice(startDst, dst));
- }
- else
- {
- token.setContent(UnownedStringSlice(textBegin, textEnd));
- }
- }
-
- token.flags = flags;
-
- m_tokenFlags = 0;
-
- if (tokenType == TokenType::Identifier)
- {
- token.setName(m_namePool->getName(token.getContent()));
- }
-
- return token;
- }
- }
-
- TokenList Lexer::lexAllTokens()
- {
- TokenList tokenList;
- for(;;)
- {
- Token token = lexToken();
- tokenList.add(token);
-
- if(token.type == TokenType::EndOfFile)
- return tokenList;
- }
- }
-
- /* static */UnownedStringSlice Lexer::sourceLocationLexer(const UnownedStringSlice& in)
- {
- Lexer lexer;
-
- SourceManager sourceManager;
- sourceManager.initialize(nullptr, nullptr);
-
- auto sourceFile = sourceManager.createSourceFileWithString(PathInfo::makeUnknown(), in);
- auto sourceView = sourceManager.createSourceView(sourceFile, nullptr, SourceLoc::fromRaw(0));
-
- DiagnosticSink sink(&sourceManager, nullptr);
-
- MemoryArena arena;
-
- RootNamePool rootNamePool;
- NamePool namePool;
- namePool.setRootNamePool(&rootNamePool);
-
- lexer.initialize(sourceView, &sink, &namePool, &arena);
-
- Token tok = lexer.lexToken();
-
- if (tok.type == TokenType::Invalid)
- {
- return UnownedStringSlice();
- }
-
- const int offset = sourceView->getRange().getOffset(tok.loc);
-
- SLANG_ASSERT(offset >= 0 && offset <= in.getLength());
- SLANG_ASSERT(Index(offset + tok.charsCount) <= in.getLength());
-
- return UnownedStringSlice(in.begin() + offset, in.begin() + offset + tok.charsCount);
- }
-
-}
diff --git a/source/slang/slang-lexer.h b/source/slang/slang-lexer.h
deleted file mode 100644
index f1fe89516..000000000
--- a/source/slang/slang-lexer.h
+++ /dev/null
@@ -1,164 +0,0 @@
-#ifndef SLANG_LEXER_H
-#define SLANG_LEXER_H
-
-#include "../core/slang-basic.h"
-#include "slang-diagnostics.h"
-
-namespace Slang
-{
- struct NamePool;
-
- //
-
- struct TokenList
- {
- const Token* begin() const;
- const Token* end() const;
-
- SLANG_FORCE_INLINE void add(const Token& token) { m_tokens.add(token); }
-
- List<Token> m_tokens;
- };
-
- struct TokenSpan
- {
- TokenSpan();
- TokenSpan(
- TokenList const& tokenList)
- : m_begin(tokenList.begin())
- , m_end (tokenList.end ())
- {}
-
- const Token* begin() const { return m_begin; }
- const Token* end () const { return m_end ; }
-
- int getCount() { return (int)(m_end - m_begin); }
-
- const Token* m_begin;
- const Token* m_end;
- };
-
- struct TokenReader
- {
- Token m_nextToken;
- TokenReader();
- explicit TokenReader(TokenSpan const& tokens)
- : m_cursor(tokens.begin())
- , m_end (tokens.end ())
- , m_nextToken(tokens.begin() ? *tokens.begin() : getEndOfFileToken())
- {}
- explicit TokenReader(TokenList const& tokens)
- : m_cursor(tokens.begin())
- , m_end (tokens.end ())
- , m_nextToken(tokens.begin() ? *tokens.begin() : getEndOfFileToken())
- {}
- struct ParsingCursor
- {
- Token nextToken;
- const Token* tokenReaderCursor = nullptr;
- };
- ParsingCursor getCursor()
- {
- ParsingCursor rs;
- rs.nextToken = m_nextToken;
- rs.tokenReaderCursor = m_cursor;
- return rs;
- }
- void setCursor(ParsingCursor cursor)
- {
- m_cursor = cursor.tokenReaderCursor;
- m_nextToken = cursor.nextToken;
- }
- bool isAtCursor(const ParsingCursor& cursor) const
- {
- return cursor.tokenReaderCursor == m_cursor;
- }
- bool isAtEnd() const { return m_cursor == m_end; }
- Token& peekToken();
- TokenType peekTokenType() const;
- SourceLoc peekLoc() const;
-
- Token advanceToken();
-
- int getCount() { return (int)(m_end - m_cursor); }
-
- const Token* m_cursor;
- const Token* m_end;
- static Token getEndOfFileToken();
- };
-
- typedef unsigned int LexerFlags;
- enum
- {
- kLexerFlag_InDirective = 1 << 0, ///< Turn end-of-line and end-of-file into end-of-directive
- kLexerFlag_ExpectFileName = 1 << 1, ///< Support `<>` style strings for file paths
- kLexerFlag_IgnoreInvalid = 1 << 2, ///< Suppress errors about invalid/unsupported characters
- kLexerFlag_ExpectDirectiveMessage = 1 << 3, ///< Don't lexer ordinary tokens, and instead consume rest of line as a string
- };
-
- struct Lexer
- {
- typedef uint32_t OptionFlags;
- struct OptionFlag
- {
- enum Enum : OptionFlags
- {
- TokenizeComments = 1 << 0, ///< If set comments will be output to the token stream
- };
- };
-
- void initialize(
- SourceView* sourceView,
- DiagnosticSink* sink,
- NamePool* namePool,
- MemoryArena* memoryArena,
- OptionFlags optionFlags = 0);
-
- ~Lexer();
-
- /// Runs the lexer to try and extract a single token, which is returned.
- /// This can be used by the DiagnosticSink to be able to display more appropriate
- /// information when displaying a source location - such as underscoring the
- /// token at that location.
- ///
- /// NOTE! This function is relatively slow, and is designed for use around this specific
- /// purpose. It does not return a token or a token type, because that information is
- /// not needed by the DiagnosticSink.
- static UnownedStringSlice sourceLocationLexer(const UnownedStringSlice& in);
-
- Token lexToken(LexerFlags extraFlags = 0);
-
- TokenList lexAllTokens();
-
- SourceView* m_sourceView;
- DiagnosticSink* m_sink;
- NamePool* m_namePool;
-
- char const* m_cursor;
-
- char const* m_begin;
- char const* m_end;
-
- /// The starting sourceLoc (same as first location of SourceView)
- SourceLoc m_startLoc;
-
- TokenFlags m_tokenFlags;
- LexerFlags m_lexerFlags;
- OptionFlags m_optionFlags;
-
- MemoryArena* m_memoryArena;
- };
-
-
- // Helper routines for extracting values from tokens
- String getStringLiteralTokenValue(Token const& token);
- String getFileNameTokenValue(Token const& token);
-
- typedef int64_t IntegerLiteralValue;
- typedef double FloatingPointLiteralValue;
-
- IntegerLiteralValue getIntegerLiteralValue(Token const& token, UnownedStringSlice* outSuffix = 0);
- FloatingPointLiteralValue getFloatingPointLiteralValue(Token const& token, UnownedStringSlice* outSuffix = 0);
-}
-
-#endif
diff --git a/source/slang/slang-lookup.cpp b/source/slang/slang-lookup.cpp
index c50364201..f41d8ff3b 100644
--- a/source/slang/slang-lookup.cpp
+++ b/source/slang/slang-lookup.cpp
@@ -1,6 +1,7 @@
// slang-lookup.cpp
#include "slang-lookup.h"
-#include "slang-name.h"
+
+#include "../compiler-core/slang-name.h"
namespace Slang {
diff --git a/source/slang/slang-mangle.cpp b/source/slang/slang-mangle.cpp
index a08b05a5d..ed38a1261 100644
--- a/source/slang/slang-mangle.cpp
+++ b/source/slang/slang-mangle.cpp
@@ -1,6 +1,6 @@
#include "slang-mangle.h"
-#include "slang-name.h"
+#include "../compiler-core/slang-name.h"
#include "slang-syntax.h"
namespace Slang
diff --git a/source/slang/slang-name.cpp b/source/slang/slang-name.cpp
deleted file mode 100644
index b6035982b..000000000
--- a/source/slang/slang-name.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-// slang-name.cpp
-#include "slang-name.h"
-
-namespace Slang {
-
-String getText(Name* name)
-{
- if (!name) return String();
- return name->text;
-}
-
-UnownedStringSlice getUnownedStringSliceText(Name* name)
-{
- return name ? name->text.getUnownedSlice() : UnownedStringSlice();
-}
-
-const char* getCstr(Name* name)
-{
- return name ? name->text.getBuffer() : nullptr;
-}
-
-Name* NamePool::getName(String const& text)
-{
- RefPtr<Name> name;
- if (rootPool->names.TryGetValue(text, name))
- return name;
-
- name = new Name();
- name->text = text;
- rootPool->names.Add(text, name);
- return name;
-}
-
-Name* NamePool::tryGetName(String const& text)
-{
- RefPtr<Name> name;
- if (rootPool->names.TryGetValue(text, name))
- return name;
- return nullptr;
-}
-
-} // namespace Slang
diff --git a/source/slang/slang-name.h b/source/slang/slang-name.h
deleted file mode 100644
index cf702686b..000000000
--- a/source/slang/slang-name.h
+++ /dev/null
@@ -1,89 +0,0 @@
-// slang-name.h
-#ifndef SLANG_NAME_H_INCLUDED
-#define SLANG_NAME_H_INCLUDED
-
-// This file defines the `Name` type, used to represent
-// the name of types, variables, etc. in the AST.
-
-#include "../core/slang-basic.h"
-
-namespace Slang {
-
-// The `Name` type is used to represent the name of a type, variable, etc.
-//
-// The key benefit of using `Name`s instead of raw strings is that `Name`s
-// can be compared for equality just by testing pointer equality. Names
-// also don't require any memory management; you can just retain an ordinary
-// pointer to one and not deal with reference-counting overhead.
-//
-// In order to provide these benefits, a `Name` can only be created using
-// a `NamePool` that owns the allocations for all the names (so they get
-// cleaned up when the pool is deleted), and which is responsible for
-// ensuring the uniqueness of name objects.
-//
-class Name : public RefObject
-{
-public:
- // The raw text of the name.
- //
- // Note that at some point in the future we might have other categories
- // of name than "simple" names, and so this might change to a structured
- // ADT instead of a simple string.
- String text;
-};
-
-// Get the textual string representation of a name
-// (e.g., so that it can be printed).
-String getText(Name* name);
-
-/// Get the text as unowned string slice
-UnownedStringSlice getUnownedStringSliceText(Name* name);
-
-// Get a name as a C style string, or nullptr if name is nullptr
-const char* getCstr(Name* name);
-
-// A `RootNamePool` is used to store and look up names.
-// If two systems need to work together with names, and be sure that they
-// get equivalent names for a string like `"Foo"`, then they need to use
-// the same root name pool (directly or indirectly).
-//
-struct RootNamePool
-{
- // The mapping from text strings to the corresponding name.
- Dictionary<String, RefPtr<Name> > names;
-};
-
-// A `NamePool` is effectively a way of storing a subset of the
-// names that have been created through a `RootNamePool`.
-//
-// The intention is that eventually we will add the ability to clean
-// up a `NamePool`, and remove the names it created from the corresponding
-// `RootNamePool` *if* those names are no longer in use.
-//
-// The goal of such an approach would be to ensure that the memory
-// usage of a `Session` can't bloat over time just because of multiple
-// `CompileRequest`s being created, used, and then destroyed (each time
-// adding just a few more strings to the name mapping).
-//
-struct NamePool
-{
- // Find or create the `Name` that represents the given `text`.
- Name* getName(String const& text);
- // Try find the `Name` that represents the given `text`.
- // If the name does not exist, return nullptr
- Name* tryGetName(String const& text);
- // Set the parent name pool to use for lookup
- void setRootNamePool(RootNamePool* rootNamePool)
- {
- this->rootPool = rootNamePool;
- }
-
- //
-
- // The root name pool to use for storage/lookup
- RootNamePool* rootPool = nullptr;
-};
-
-} // namespace Slang
-
-#endif
diff --git a/source/slang/slang-options.cpp b/source/slang/slang-options.cpp
index fcc2e0e4c..b88fa9bca 100644
--- a/source/slang/slang-options.cpp
+++ b/source/slang/slang-options.cpp
@@ -10,11 +10,10 @@
#include "slang-compiler.h"
#include "slang-profile.h"
-#include "slang-file-system.h"
-
#include "slang-repro.h"
#include "slang-serialize-ir.h"
+#include "../core/slang-file-system.h"
#include "../core/slang-type-text-util.h"
#include "../core/slang-hex-dump-util.h"
diff --git a/source/slang/slang-parser.h b/source/slang/slang-parser.h
index a1077d4a7..0ec2dcb8a 100644
--- a/source/slang/slang-parser.h
+++ b/source/slang/slang-parser.h
@@ -1,7 +1,8 @@
#ifndef SLANG_PARSER_H
#define SLANG_PARSER_H
-#include "slang-lexer.h"
+#include "../compiler-core/slang-lexer.h"
+
#include "slang-compiler.h"
#include "slang-syntax.h"
diff --git a/source/slang/slang-preprocessor.cpp b/source/slang/slang-preprocessor.cpp
index f9d18332d..bc78e4d31 100644
--- a/source/slang/slang-preprocessor.cpp
+++ b/source/slang/slang-preprocessor.cpp
@@ -3,7 +3,7 @@
#include "slang-compiler.h"
#include "slang-diagnostics.h"
-#include "slang-lexer.h"
+#include "../compiler-core/slang-lexer.h"
// Needed so that we can construct modifier syntax to represent GLSL directives
#include "slang-syntax.h"
diff --git a/source/slang/slang-preprocessor.h b/source/slang/slang-preprocessor.h
index efecb912b..9de82b9f2 100644
--- a/source/slang/slang-preprocessor.h
+++ b/source/slang/slang-preprocessor.h
@@ -4,7 +4,7 @@
#include "../core/slang-basic.h"
-#include "slang-lexer.h"
+#include "../compiler-core/slang-lexer.h"
#include "slang-include-system.h"
diff --git a/source/slang/slang-repro.cpp b/source/slang/slang-repro.cpp
index 61ab3b75d..3618568c1 100644
--- a/source/slang/slang-repro.cpp
+++ b/source/slang/slang-repro.cpp
@@ -10,7 +10,7 @@
#include "slang-options.h"
-#include "slang-source-loc.h"
+#include "../compiler-core/slang-source-loc.h"
namespace Slang {
diff --git a/source/slang/slang-repro.h b/source/slang/slang-repro.h
index dd9984395..38a76a50a 100644
--- a/source/slang/slang-repro.h
+++ b/source/slang/slang-repro.h
@@ -9,8 +9,7 @@
#include "slang-compiler.h"
#include "../core/slang-offset-container.h"
-
-#include "slang-file-system.h"
+#include "../core/slang-file-system.h"
namespace Slang {
diff --git a/source/slang/slang-serialize-ir-types.h b/source/slang/slang-serialize-ir-types.h
index 326e41f6e..41759d378 100644
--- a/source/slang/slang-serialize-ir-types.h
+++ b/source/slang/slang-serialize-ir-types.h
@@ -9,8 +9,8 @@
#include "slang-serialize-types.h"
#include "slang-serialize-source-loc.h"
-#include "slang-name.h"
-#include "slang-source-loc.h"
+#include "../compiler-core/slang-name.h"
+#include "../compiler-core/slang-source-loc.h"
#include "slang-ir.h"
diff --git a/source/slang/slang-serialize-misc-type-info.h b/source/slang/slang-serialize-misc-type-info.h
index 08fd1269d..191514785 100644
--- a/source/slang/slang-serialize-misc-type-info.h
+++ b/source/slang/slang-serialize-misc-type-info.h
@@ -4,7 +4,7 @@
#include "slang-serialize-type-info.h"
-#include "slang-source-loc.h"
+#include "../compiler-core/slang-source-loc.h"
#include "slang-compiler.h"
namespace Slang {
diff --git a/source/slang/slang-serialize-reflection.h b/source/slang/slang-serialize-reflection.h
index 7eaf8543c..5ae87877e 100644
--- a/source/slang/slang-serialize-reflection.h
+++ b/source/slang/slang-serialize-reflection.h
@@ -2,7 +2,7 @@
#ifndef SLANG_SERIALIZE_REFLECTION_H
#define SLANG_SERIALIZE_REFLECTION_H
-#include "slang-name.h"
+#include "../compiler-core/slang-name.h"
namespace Slang
{
diff --git a/source/slang/slang-serialize-source-loc.h b/source/slang/slang-serialize-source-loc.h
index 5ebd264cc..595a55ea6 100644
--- a/source/slang/slang-serialize-source-loc.h
+++ b/source/slang/slang-serialize-source-loc.h
@@ -8,8 +8,8 @@
#include "slang-serialize-types.h"
-#include "slang-name.h"
-#include "slang-source-loc.h"
+#include "../compiler-core/slang-name.h"
+#include "../compiler-core/slang-source-loc.h"
namespace Slang {
diff --git a/source/slang/slang-serialize.h b/source/slang/slang-serialize.h
index ff402b35c..990a36adc 100644
--- a/source/slang/slang-serialize.h
+++ b/source/slang/slang-serialize.h
@@ -11,7 +11,7 @@
#include "slang-serialize-types.h"
-#include "slang-name.h"
+#include "../compiler-core/slang-name.h"
namespace Slang
{
diff --git a/source/slang/slang-source-loc.cpp b/source/slang/slang-source-loc.cpp
deleted file mode 100644
index 4b589fbf3..000000000
--- a/source/slang/slang-source-loc.cpp
+++ /dev/null
@@ -1,689 +0,0 @@
-// slang-source-loc.cpp
-#include "slang-source-loc.h"
-
-#include "../core/slang-string-util.h"
-
-namespace Slang {
-
-/* !!!!!!!!!!!!!!!!!!!!!!!!! SourceView !!!!!!!!!!!!!!!!!!!!!!!!!!!! */
-
-const String PathInfo::getMostUniqueIdentity() const
-{
- switch (type)
- {
- case Type::Normal: return uniqueIdentity;
- case Type::FoundPath:
- case Type::FromString:
- {
- return foundPath;
- }
- default: return "";
- }
-}
-
-bool PathInfo::operator==(const ThisType& rhs) const
-{
- // They must be the same type
- if (type != rhs.type)
- {
- return false;
- }
-
- switch (type)
- {
- case Type::TokenPaste:
- case Type::TypeParse:
- case Type::Unknown:
- case Type::CommandLine:
- {
- return true;
- }
- case Type::Normal:
- {
- return foundPath == rhs.foundPath && uniqueIdentity == rhs.uniqueIdentity;
- }
- case Type::FromString:
- case Type::FoundPath:
- {
- // Only have a found path
- return foundPath == rhs.foundPath;
- }
- default: break;
- }
-
- return false;
-}
-
-void PathInfo::appendDisplayName(StringBuilder& out) const
-{
- switch (type)
- {
- case Type::TokenPaste: out << "[Token Paste]"; break;
- case Type::TypeParse: out << "[Type Parse]"; break;
- case Type::Unknown: out << "[Unknown]"; break;
- case Type::CommandLine: out << "[Command Line]"; break;
- case Type::Normal:
- case Type::FromString:
- case Type::FoundPath:
- {
-
- out.appendChar('"');
- StringUtil::appendEscaped(foundPath.getUnownedSlice(), out);
- out.appendChar('"');
- break;
- }
- default: break;
- }
-}
-
-/* !!!!!!!!!!!!!!!!!!!!!!!!! SourceView !!!!!!!!!!!!!!!!!!!!!!!!!!!! */
-
-int SourceView::findEntryIndex(SourceLoc sourceLoc) const
-{
- if (!m_range.contains(sourceLoc))
- {
- return -1;
- }
-
- const auto rawValue = sourceLoc.getRaw();
-
- Index hi = m_entries.getCount();
- // If there are no entries, or it is in front of the first entry, then there is no associated entry
- if (hi == 0 ||
- m_entries[0].m_startLoc.getRaw() > sourceLoc.getRaw())
- {
- return -1;
- }
-
- Index lo = 0;
- while (lo + 1 < hi)
- {
- const Index mid = (hi + lo) >> 1;
- const Entry& midEntry = m_entries[mid];
- SourceLoc::RawValue midValue = midEntry.m_startLoc.getRaw();
- if (midValue <= rawValue)
- {
- // The location we seek is at or after this entry
- lo = mid;
- }
- else
- {
- // The location we seek is before this entry
- hi = mid;
- }
- }
-
- return int(lo);
-}
-
-void SourceView::addLineDirective(SourceLoc directiveLoc, StringSlicePool::Handle pathHandle, int line)
-{
- SLANG_ASSERT(pathHandle != StringSlicePool::Handle(0));
- SLANG_ASSERT(m_range.contains(directiveLoc));
-
- // Check that the directiveLoc values are always increasing
- SLANG_ASSERT(m_entries.getCount() == 0 || (m_entries.getLast().m_startLoc.getRaw() < directiveLoc.getRaw()));
-
- // Calculate the offset
- const int offset = m_range.getOffset(directiveLoc);
-
- // Get the line index in the original file
- const int lineIndex = m_sourceFile->calcLineIndexFromOffset(offset);
-
- Entry entry;
- entry.m_startLoc = directiveLoc;
- entry.m_pathHandle = pathHandle;
-
- // We also need to make sure that any lookups for line numbers will
- // get corrected based on this files location.
- // We assume the line number coming from the directive is a line number, NOT an index, so the correction needs + 1
- // There is an additional + 1 because we want the NEXT line - ie the line after the #line directive, to the specified value
- // Taking both into account means +2 is correct 'fix'
- entry.m_lineAdjust = line - (lineIndex + 2);
-
- m_entries.add(entry);
-}
-
-void SourceView::addLineDirective(SourceLoc directiveLoc, const String& path, int line)
-{
- StringSlicePool::Handle pathHandle = getSourceManager()->getStringSlicePool().add(path.getUnownedSlice());
- return addLineDirective(directiveLoc, pathHandle, line);
-}
-
-void SourceView::addDefaultLineDirective(SourceLoc directiveLoc)
-{
- SLANG_ASSERT(m_range.contains(directiveLoc));
- // Check that the directiveLoc values are always increasing
- SLANG_ASSERT(m_entries.getCount() == 0 || (m_entries.getLast().m_startLoc.getRaw() < directiveLoc.getRaw()));
-
- // Well if there are no entries, or the last one puts it in default case, then we don't need to add anything
- if (m_entries.getCount() == 0 || (m_entries.getCount() && m_entries.getLast().isDefault()))
- {
- return;
- }
-
- Entry entry;
- entry.m_startLoc = directiveLoc;
- entry.m_lineAdjust = 0; // No line adjustment... we are going back to default
- entry.m_pathHandle = StringSlicePool::Handle(0); // Mark that there is no path, and that this is a 'default'
-
- SLANG_ASSERT(entry.isDefault());
-
- m_entries.add(entry);
-}
-
-HumaneSourceLoc SourceView::getHumaneLoc(SourceLoc loc, SourceLocType type)
-{
- const int offset = m_range.getOffset(loc);
-
- // We need the line index from the original source file
- const int lineIndex = m_sourceFile->calcLineIndexFromOffset(offset);
-
- // TODO: we should really translate the byte index in the line
- // to deal with:
- //
- // - Non-ASCII characters, while might consume multiple bytes
- //
- // - Tab characters, which should really adjust how we report
- // columns (although how are we supposed to know the setting
- // that an IDE expects us to use when reporting locations?)
- const int columnIndex = m_sourceFile->calcColumnIndex(lineIndex, offset);
-
- HumaneSourceLoc humaneLoc;
- humaneLoc.column = columnIndex + 1;
- humaneLoc.line = lineIndex + 1;
-
- // Make up a default entry
- StringSlicePool::Handle pathHandle = StringSlicePool::Handle(0);
-
- // Only bother looking up the entry information if we want a 'Normal' lookup
- const int entryIndex = (type == SourceLocType::Nominal) ? findEntryIndex(loc) : -1;
- if (entryIndex >= 0)
- {
- const Entry& entry = m_entries[entryIndex];
- // Adjust the line
- humaneLoc.line += entry.m_lineAdjust;
- // Get the pathHandle..
- pathHandle = entry.m_pathHandle;
- }
-
- humaneLoc.pathInfo = _getPathInfoFromHandle(pathHandle);
- return humaneLoc;
-}
-
-PathInfo SourceView::_getPathInfo() const
-{
- if (m_viewPath.getLength())
- {
- PathInfo pathInfo(m_sourceFile->getPathInfo());
- pathInfo.foundPath = m_viewPath;
- return pathInfo;
- }
- else
- {
- return m_sourceFile->getPathInfo();
- }
-}
-
-PathInfo SourceView::_getPathInfoFromHandle(StringSlicePool::Handle pathHandle) const
-{
- // If there is no override path, then just the source files path
- if (pathHandle == StringSlicePool::Handle(0))
- {
- return _getPathInfo();
- }
- else
- {
- return PathInfo::makePath(getSourceManager()->getStringSlicePool().getSlice(pathHandle));
- }
-}
-
-PathInfo SourceView::getPathInfo(SourceLoc loc, SourceLocType type)
-{
- if (type == SourceLocType::Actual)
- {
- return _getPathInfo();
- }
-
- const int entryIndex = findEntryIndex(loc);
- return _getPathInfoFromHandle((entryIndex >= 0) ? m_entries[entryIndex].m_pathHandle : StringSlicePool::Handle(0));
-}
-
-/* !!!!!!!!!!!!!!!!!!!!!!! SourceFile !!!!!!!!!!!!!!!!!!!!!!!!!!!! */
-
-void SourceFile::setLineBreakOffsets(const uint32_t* offsets, UInt numOffsets)
-{
- m_lineBreakOffsets.clear();
- m_lineBreakOffsets.addRange(offsets, numOffsets);
-}
-
-const List<uint32_t>& SourceFile::getLineBreakOffsets()
-{
- // We now have a raw input file that we can search for line breaks.
- // We obviously don't want to do a linear scan over and over, so we will
- // cache an array of line break locations in the file.
- if (m_lineBreakOffsets.getCount() == 0)
- {
- UnownedStringSlice content(getContent()), line;
- char const* contentBegin = content.begin();
- while (StringUtil::extractLine(content, line))
- {
- m_lineBreakOffsets.add(uint32_t(line.begin() - contentBegin));
- }
- // Note that we do *not* treat the end of the file as a line
- // break, because otherwise we would report errors like
- // "end of file inside string literal" with a line number
- // that points at a line that doesn't exist.
- }
-
- return m_lineBreakOffsets;
-}
-
-SourceFile::OffsetRange SourceFile::getOffsetRangeAtLineIndex(Index lineIndex)
-{
- const List<uint32_t>& offsets = getLineBreakOffsets();
- const Index count = offsets.getCount();
-
- if (lineIndex >= count - 1)
- {
- // Work out the line start
- const uint32_t offsetEnd = uint32_t(getContentSize());
- const uint32_t offsetStart = (lineIndex >= count) ? offsetEnd : offsets[lineIndex];
- // The line is the span from start, to the end of the content
- return OffsetRange{ offsetStart, offsetEnd };
- }
- else
- {
- const uint32_t offsetStart = offsets[lineIndex];
- const uint32_t offsetEnd = offsets[lineIndex + 1];
- return OffsetRange { offsetStart, offsetEnd };
- }
-}
-
-UnownedStringSlice SourceFile::getLineAtIndex(Index lineIndex)
-{
- const OffsetRange range = getOffsetRangeAtLineIndex(lineIndex);
-
- if (range.isValid() && hasContent())
- {
- const UnownedStringSlice content = getContent();
- SLANG_ASSERT(range.end <= uint32_t(content.getLength()));
-
- const char*const text = content.begin();
- return UnownedStringSlice(text + range.start, text + range.end);
- }
-
- return UnownedStringSlice();
-}
-
-UnownedStringSlice SourceFile::getLineContainingOffset(uint32_t offset)
-{
- const Index lineIndex = calcLineIndexFromOffset(offset);
- return getLineAtIndex(lineIndex);
-}
-
-bool SourceFile::isOffsetOnLine(uint32_t offset, Index lineIndex)
-{
- const OffsetRange range = getOffsetRangeAtLineIndex(lineIndex);
- return range.isValid() && range.containsInclusive(offset);
-}
-
-int SourceFile::calcLineIndexFromOffset(int offset)
-{
- SLANG_ASSERT(UInt(offset) <= getContentSize());
-
- // Make sure we have the line break offsets
- const auto& lineBreakOffsets = getLineBreakOffsets();
-
- // At this point we can assume the `lineBreakOffsets` array has been filled in.
- // We will use a binary search to find the line index that contains our
- // chosen offset.
- Index lo = 0;
- Index hi = lineBreakOffsets.getCount();
-
- while (lo + 1 < hi)
- {
- const Index mid = (hi + lo) >> 1;
- const uint32_t midOffset = lineBreakOffsets[mid];
- if (midOffset <= uint32_t(offset))
- {
- lo = mid;
- }
- else
- {
- hi = mid;
- }
- }
-
- return int(lo);
-}
-
-int SourceFile::calcColumnIndex(int lineIndex, int offset)
-{
- const auto& lineBreakOffsets = getLineBreakOffsets();
- return offset - lineBreakOffsets[lineIndex];
-}
-
-/* !!!!!!!!!!!!!!!!!!!!!!!!! SourceFile !!!!!!!!!!!!!!!!!!!!!!!!!!!! */
-
-void SourceFile::setContents(ISlangBlob* blob)
-{
- const UInt contentSize = blob->getBufferSize();
-
- SLANG_ASSERT(contentSize == m_contentSize);
-
- char const* contentBegin = (char const*)blob->getBufferPointer();
- char const* contentEnd = contentBegin + contentSize;
-
- m_contentBlob = blob;
- m_content = UnownedStringSlice(contentBegin, contentEnd);
-}
-
-void SourceFile::setContents(const String& content)
-{
- ComPtr<ISlangBlob> contentBlob = StringUtil::createStringBlob(content);
- setContents(contentBlob);
-}
-
-SourceFile::SourceFile(SourceManager* sourceManager, const PathInfo& pathInfo, size_t contentSize) :
- m_sourceManager(sourceManager),
- m_pathInfo(pathInfo),
- m_contentSize(contentSize)
-{
-}
-
-SourceFile::~SourceFile()
-{
-}
-
-String SourceFile::calcVerbosePath() const
-{
- ISlangFileSystemExt* fileSystemExt = getSourceManager()->getFileSystemExt();
-
- if (fileSystemExt)
- {
- String canonicalPath;
- ComPtr<ISlangBlob> canonicalPathBlob;
- if (SLANG_SUCCEEDED(fileSystemExt->getCanonicalPath(m_pathInfo.foundPath.getBuffer(), canonicalPathBlob.writeRef())))
- {
- canonicalPath = StringUtil::getString(canonicalPathBlob);
- }
- if (canonicalPath.getLength() > 0)
- {
- return canonicalPath;
- }
- }
-
- return m_pathInfo.foundPath;
-}
-
-/* !!!!!!!!!!!!!!!!!!!!!!!!! SourceManager !!!!!!!!!!!!!!!!!!!!!!!!!!!! */
-
-void SourceManager::initialize(
- SourceManager* p,
- ISlangFileSystemExt* fileSystemExt)
-{
- m_fileSystemExt = fileSystemExt;
-
- m_parent = p;
-
- if( p )
- {
- // If we have a parent source manager, then we assume that all code at that level
- // has already been loaded, and it is safe to start our own source locations
- // right after those from the parent.
- //
- // TODO: more clever allocation in cases where that might not be reasonable
- m_startLoc = p->m_nextLoc;
- }
- else
- {
- // Location zero is reserved for an invalid location,
- // so we need to start reserving locations starting at 1.
- m_startLoc = SourceLoc::fromRaw(1);
- }
-
- m_nextLoc = m_startLoc;
-}
-
-SourceManager::~SourceManager()
-{
- for (auto item : m_sourceViews)
- {
- delete item;
- }
-
- for (auto item : m_sourceFiles)
- {
- delete item;
- }
-}
-
-UnownedStringSlice SourceManager::allocateStringSlice(const UnownedStringSlice& slice)
-{
- const UInt numChars = slice.getLength();
-
- char* dst = (char*)m_memoryArena.allocate(numChars);
- ::memcpy(dst, slice.begin(), numChars);
-
- return UnownedStringSlice(dst, numChars);
-}
-
-SourceRange SourceManager::allocateSourceRange(UInt size)
-{
- // TODO: consider using atomics here
-
-
- SourceLoc beginLoc = m_nextLoc;
- SourceLoc endLoc = beginLoc + size;
-
- // We need to be able to represent the location that is *at* the end of
- // the input source, so the next available location for a new file
- // must be placed one after the end of this one.
-
- m_nextLoc = endLoc + 1;
-
- return SourceRange(beginLoc, endLoc);
-}
-
-SourceFile* SourceManager::createSourceFileWithSize(const PathInfo& pathInfo, size_t contentSize)
-{
- SourceFile* sourceFile = new SourceFile(this, pathInfo, contentSize);
- m_sourceFiles.add(sourceFile);
- return sourceFile;
-}
-
-SourceFile* SourceManager::createSourceFileWithString(const PathInfo& pathInfo, const String& contents)
-{
- SourceFile* sourceFile = new SourceFile(this, pathInfo, contents.getLength());
- m_sourceFiles.add(sourceFile);
- sourceFile->setContents(contents);
- return sourceFile;
-}
-
-SourceFile* SourceManager::createSourceFileWithBlob(const PathInfo& pathInfo, ISlangBlob* blob)
-{
- SourceFile* sourceFile = new SourceFile(this, pathInfo, blob->getBufferSize());
- m_sourceFiles.add(sourceFile);
- sourceFile->setContents(blob);
- return sourceFile;
-}
-
-SourceView* SourceManager::createSourceView(SourceFile* sourceFile, const PathInfo* pathInfo, SourceLoc initiatingSourceLoc)
-{
- SourceRange range = allocateSourceRange(sourceFile->getContentSize());
-
- SourceView* sourceView = nullptr;
- if (pathInfo &&
- (pathInfo->foundPath.getLength() && sourceFile->getPathInfo().foundPath != pathInfo->foundPath))
- {
- sourceView = new SourceView(sourceFile, range, &pathInfo->foundPath, initiatingSourceLoc);
- }
- else
- {
- sourceView = new SourceView(sourceFile, range, nullptr, initiatingSourceLoc);
- }
-
- m_sourceViews.add(sourceView);
-
- return sourceView;
-}
-
-SourceView* SourceManager::findSourceView(SourceLoc loc) const
-{
- Index hi = m_sourceViews.getCount();
- // It must be in the range of this manager and have associated views for it to possibly be a hit
- if (!getSourceRange().contains(loc) || hi == 0)
- {
- return nullptr;
- }
-
- // If we don't have very many, we may as well just linearly search
- if (hi <= 8)
- {
- for (int i = 0; i < hi; ++i)
- {
- SourceView* view = m_sourceViews[i];
- if (view->getRange().contains(loc))
- {
- return view;
- }
- }
- return nullptr;
- }
-
- const SourceLoc::RawValue rawLoc = loc.getRaw();
-
- // Binary chop to see if we can find the associated SourceUnit
- Index lo = 0;
- while (lo + 1 < hi)
- {
- Index mid = (hi + lo) >> 1;
-
- SourceView* midView = m_sourceViews[mid];
- if (midView->getRange().contains(loc))
- {
- return midView;
- }
-
- const SourceLoc::RawValue midValue = midView->getRange().begin.getRaw();
- if (midValue <= rawLoc)
- {
- // The location we seek is at or after this entry
- lo = mid;
- }
- else
- {
- // The location we seek is before this entry
- hi = mid;
- }
- }
-
- // Check if low is actually a hit
- SourceView* view = m_sourceViews[lo];
- return (view->getRange().contains(loc)) ? view : nullptr;
-}
-
-SourceView* SourceManager::findSourceViewRecursively(SourceLoc loc) const
-{
- // Start with this manager
- const SourceManager* manager = this;
- do
- {
- SourceView* sourceView = manager->findSourceView(loc);
- // If we found a hit we are done
- if (sourceView)
- {
- return sourceView;
- }
- // Try the parent
- manager = manager->m_parent;
- }
- while (manager);
- // Didn't find it
- return nullptr;
-}
-
-SourceFile* SourceManager::findSourceFile(const String& uniqueIdentity) const
-{
- SourceFile*const* filePtr = m_sourceFileMap.TryGetValue(uniqueIdentity);
- return (filePtr) ? *filePtr : nullptr;
-}
-
-SourceFile* SourceManager::findSourceFileRecursively(const String& uniqueIdentity) const
-{
- const SourceManager* manager = this;
- do
- {
- SourceFile* sourceFile = manager->findSourceFile(uniqueIdentity);
- if (sourceFile)
- {
- return sourceFile;
- }
- manager = manager->m_parent;
- } while (manager);
- return nullptr;
-}
-
-SourceFile* SourceManager::findSourceFileByContentRecursively(const char* text)
-{
- const SourceManager* manager = this;
- do
- {
- SourceFile* sourceFile = manager->findSourceFileByContent(text);
- if (sourceFile)
- {
- return sourceFile;
- }
- manager = manager->m_parent;
- } while (manager);
- return nullptr;
-}
-
-SourceFile* SourceManager::findSourceFileByContent(const char* text) const
-{
- for (SourceFile* sourceFile : getSourceFiles())
- {
- auto content = sourceFile->getContent();
-
- if (text >= content.begin() && text <= content.end())
- {
- return sourceFile;
- }
- }
- return nullptr;
-}
-
-void SourceManager::addSourceFile(const String& uniqueIdentity, SourceFile* sourceFile)
-{
- SLANG_ASSERT(!findSourceFileRecursively(uniqueIdentity));
- m_sourceFileMap.Add(uniqueIdentity, sourceFile);
-}
-
-HumaneSourceLoc SourceManager::getHumaneLoc(SourceLoc loc, SourceLocType type)
-{
- SourceView* sourceView = findSourceViewRecursively(loc);
- if (sourceView)
- {
- return sourceView->getHumaneLoc(loc, type);
- }
- else
- {
- return HumaneSourceLoc();
- }
-}
-
-PathInfo SourceManager::getPathInfo(SourceLoc loc, SourceLocType type)
-{
- SourceView* sourceView = findSourceViewRecursively(loc);
- if (sourceView)
- {
- return sourceView->getPathInfo(loc, type);
- }
- else
- {
- return PathInfo::makeUnknown();
- }
-}
-
-} // namespace Slang
diff --git a/source/slang/slang-source-loc.h b/source/slang/slang-source-loc.h
deleted file mode 100644
index 54811918f..000000000
--- a/source/slang/slang-source-loc.h
+++ /dev/null
@@ -1,487 +0,0 @@
-// slang-source-loc.h
-#ifndef SLANG_SOURCE_LOC_H_INCLUDED
-#define SLANG_SOURCE_LOC_H_INCLUDED
-
-#include "../core/slang-basic.h"
-#include "../core/slang-memory-arena.h"
-#include "../core/slang-string-slice-pool.h"
-
-#include "../../slang-com-ptr.h"
-#include "../../slang.h"
-
-namespace Slang {
-
-/** Overview:
-
-There needs to be a mechanism where we can easily and quickly track a specific locations in any source file used during a compilation.
-This is important because that original location is meaningful to the user as it relates to their original source. Thus SourceLoc are
-used so we can display meaningful and accurate errors/warnings as well as being able to always map generated code locations back to their origins.
-
-A 'SourceLoc' along with associated structures (SourceView, SourceFile, SourceMangager) this can pinpoint the location down to the byte across the
-compilation. This could be achieved by storing for every token and instruction the file, line and column number came from. The SourceLoc is used in
-lots of places - every AST node, every Token from the lexer, every IRInst - so we really want to make it small. So for this reason we actually
-encode SourceLoc as a single integer and then use the associated structures when needed to determine what the location actually refers to -
-the source file, line and column number, or in effect the byte in the original file.
-
-Unfortunately there is extra complications. When a source is parsed it's interpretation (in terms of how a piece of source maps to an 'original' file etc)
-can be overridden - for example by using #line directives. Moreover a single source file can be parsed multiple times. When it's parsed multiple times the
-interpretation of the mapping (#line directives for example) can change. This is the purpose of the SourceView - it holds the interpretation of a source file
-for a specific Lex/Parse.
-
-Another complication is that not all 'source' comes from SourceFiles, a macro expansion, may generate new 'source' we need to handle this, but also be able
-to have a SourceLoc map to the expansion unambiguously. This is handled by creating a SourceFile and SourceView that holds only the macro generated
-specific information.
-
-SourceFile - Is the immutable text contents of a file (or perhaps some generated source - say from doing a macro substitution)
-SourceView - Tracks a single parse of a SourceFile. Each SourceView defines a range of source locations used. If a SourceFile is parsed twice, two
-SourceViews are created, with unique SourceRanges. This is so that it is possible to tell which specific parse a SourceLoc is from - and so know the right
-interpretation for that lex/parse.
-*/
-
-struct PathInfo
-{
- typedef PathInfo ThisType;
-
- /// To be more rigorous about where a path comes from, the type identifies what a paths origin is
- enum class Type : uint8_t
- {
- Unknown, ///< The path is not known
- Normal, ///< Normal has both path and uniqueIdentity
- FoundPath, ///< Just has a found path (uniqueIdentity is unknown, or even 'unknowable')
- FromString, ///< Created from a string (so found path might not be defined and should not be taken as to map to a loaded file)
- TokenPaste, ///< No paths, just created to do a macro expansion
- TypeParse, ///< No path, just created to do a type parse
- CommandLine, ///< A macro constructed from the command line
- };
-
- /// True if has a canonical path
- SLANG_FORCE_INLINE bool hasUniqueIdentity() const { return type == Type::Normal && uniqueIdentity.getLength() > 0; }
- /// True if has a regular found path
- SLANG_FORCE_INLINE bool hasFoundPath() const { return type == Type::Normal || type == Type::FoundPath || (type == Type::FromString && foundPath.getLength() > 0); }
- /// True if has a found path that has originated from a file (as opposed to string or some other origin)
- SLANG_FORCE_INLINE bool hasFileFoundPath() const { return (type == Type::Normal || type == Type::FoundPath) && foundPath.getLength() > 0; }
-
- bool operator==(const ThisType& rhs) const;
- bool operator!=(const ThisType& rhs) const { return !(*this == rhs); }
-
- /// Returns the 'most unique' identity for the path. If has a 'uniqueIdentity' returns that, else the foundPath, else "".
- const String getMostUniqueIdentity() const;
-
- /// Append to out, how to display the path
- void appendDisplayName(StringBuilder& out) const;
-
- // So simplify construction. In normal usage it's safer to use make methods over constructing directly.
- static PathInfo makeUnknown() { return PathInfo { Type::Unknown, String(), String() }; }
- static PathInfo makeTokenPaste() { return PathInfo{ Type::TokenPaste, "token paste", String()}; }
- static PathInfo makeNormal(const String& foundPathIn, const String& uniqueIdentity) { SLANG_ASSERT(uniqueIdentity.getLength() > 0 && foundPathIn.getLength() > 0); return PathInfo { Type::Normal, foundPathIn, uniqueIdentity }; }
- static PathInfo makePath(const String& pathIn) { SLANG_ASSERT(pathIn.getLength() > 0); return PathInfo { Type::FoundPath, pathIn, String()}; }
- static PathInfo makeTypeParse() { return PathInfo { Type::TypeParse, "type string", String() }; }
- static PathInfo makeCommandLine() { return PathInfo { Type::CommandLine, "command line", String() }; }
- static PathInfo makeFromString(const String& userPath) { return PathInfo{ Type::FromString, userPath, String() }; }
-
- Type type; ///< The type of path
- String foundPath; ///< The path where the file was found (might contain relative elements)
- String uniqueIdentity; ///< The unique identity of the file on the path found
-};
-
-class SourceLoc
-{
-public:
- typedef SourceLoc ThisType;
- typedef uint32_t RawValue;
-
-private:
- RawValue raw;
-
-public:
- SourceLoc()
- : raw(0)
- {}
-
- SourceLoc(
- SourceLoc const& loc)
- : raw(loc.raw)
- {}
-
- SLANG_FORCE_INLINE bool operator==(const ThisType& rhs) const { return raw == rhs.raw; }
- SLANG_FORCE_INLINE bool operator!=(const ThisType& rhs) const { return !(raw == rhs.raw); }
-
- RawValue getRaw() const { return raw; }
- void setRaw(RawValue value) { raw = value; }
-
- static SourceLoc fromRaw(RawValue value)
- {
- SourceLoc result;
- result.setRaw(value);
- return result;
- }
-
- bool isValid() const
- {
- return raw != 0;
- }
- SourceLoc& operator=(const ThisType& rhs) = default;
-};
-
-inline SourceLoc operator+(SourceLoc loc, Int offset)
-{
- return SourceLoc::fromRaw(SourceLoc::RawValue(Int(loc.getRaw()) + offset));
-}
-
-// A range of locations in the input source
-struct SourceRange
-{
- /// True if the loc is in the range. Range is inclusive on begin to end.
- bool contains(SourceLoc loc) const { const auto rawLoc = loc.getRaw(); return rawLoc >= begin.getRaw() && rawLoc <= end.getRaw(); }
- /// Get the total size
- UInt getSize() const { return UInt(end.getRaw() - begin.getRaw()); }
-
- /// Get the offset of a loc in this range
- int getOffset(SourceLoc loc) const { SLANG_ASSERT(contains(loc)); return int(loc.getRaw() - begin.getRaw()); }
-
- /// Convert an offset to a loc
- SourceLoc getSourceLocFromOffset(uint32_t offset) const { SLANG_ASSERT(offset <= getSize()); return begin + Int(offset); }
-
- SourceRange()
- {}
-
- SourceRange(SourceLoc loc)
- : begin(loc)
- , end(loc)
- {}
-
- SourceRange(SourceLoc begin, SourceLoc end)
- : begin(begin)
- , end(end)
- {}
-
- SourceLoc begin;
- SourceLoc end;
-};
-
-
-// Pre-declare
-struct SourceManager;
-
-// A logical or physical storage object for a range of input code
-// that has logically contiguous source locations.
-class SourceFile
-{
-public:
-
- struct OffsetRange
- {
- /// We need a value to indicate an invalid range. We can't use 0 as that is valid for an offset range
- /// We can't use a negative number, and don't want to make signed so we get the full 32-bits.
- /// So we just use the max value as invalid
- static const uint32_t kInvalid = 0xffffffff;
-
- /// True if the range is valid
- SLANG_FORCE_INLINE bool isValid() const { return end >= start && start != kInvalid; }
- /// True if offset is within range (inclusively)
- SLANG_FORCE_INLINE bool containsInclusive(uint32_t offset) const { return offset >= start && offset <= end; }
-
- /// Get the count
- SLANG_FORCE_INLINE uint32_t getCount() const { return end - start; }
-
- /// Return an invalid range.
- static OffsetRange makeInvalid() { return OffsetRange{ kInvalid, kInvalid }; }
-
- uint32_t start;
- uint32_t end;
- };
-
- /// Returns the line break offsets (in bytes from start of content)
- /// Note that this is lazily evaluated - the line breaks are only calculated on the first request
- const List<uint32_t>& getLineBreakOffsets();
-
- /// Returns true if the offset is on the specified line
- /// NOTE! If offsets are not fully setup (because we don't have source), will only be correct for lines that have offsets
- bool isOffsetOnLine(uint32_t offset, Index lineIndex);
-
- /// Get the line containing the offset. Requires that content is available, else will return an empty slice.
- UnownedStringSlice getLineContainingOffset(uint32_t offset);
-
- /// Get the line at the specified line index. Requires that content is available, else will return an empty slice.
- UnownedStringSlice getLineAtIndex(Index lineIndex);
-
- /// Get the offset range at the specified line index. Works without content.
- OffsetRange getOffsetRangeAtLineIndex(Index lineIndex);
-
- /// Set the line break offsets
- void setLineBreakOffsets(const uint32_t* offsets, UInt numOffsets);
-
- /// Calculate the line based on the offset
- int calcLineIndexFromOffset(int offset);
-
- /// Calculate the offset for a line
- int calcColumnIndex(int line, int offset);
-
- /// Get the content holding blob
- ISlangBlob* getContentBlob() const { return m_contentBlob; }
-
- /// True if has full set content
- bool hasContent() const { return m_contentBlob != nullptr; }
-
- /// Get the content size
- size_t getContentSize() const { return m_contentSize; }
-
- /// Get the content
- const UnownedStringSlice& getContent() const { return m_content; }
-
- /// Get path info
- const PathInfo& getPathInfo() const { return m_pathInfo; }
-
- /// Set the content as a blob
- void setContents(ISlangBlob* blob);
- /// Set the content as a string
- void setContents(const String& content);
-
- /// Calculate a display path -> can canonicalize if necessary
- String calcVerbosePath() const;
-
- /// Get the source manager this was created on
- SourceManager* getSourceManager() const { return m_sourceManager; }
-
- /// Ctor
- SourceFile(SourceManager* sourceManager, const PathInfo& pathInfo, size_t contentSize);
- /// Dtor
- ~SourceFile();
-
- protected:
-
- SourceManager* m_sourceManager; ///< The source manager this belongs to
- PathInfo m_pathInfo; ///< The path The logical file path to report for locations inside this span.
- ComPtr<ISlangBlob> m_contentBlob; ///< A blob that owns the storage for the file contents. If nullptr, there is no contents
- UnownedStringSlice m_content; ///< The actual contents of the file.
- size_t m_contentSize; ///< The size of the actual contents
-
- // In order to speed up lookup of line number information,
- // we will cache the starting offset of each line break in
- // the input file:
- List<uint32_t> m_lineBreakOffsets;
-};
-
-enum class SourceLocType
-{
- Nominal, ///< The normal interpretation which takes into account #line directives
- Actual, ///< Ignores #line directives - and is the location as seen in the actual file
-};
-
-// A source location in a format a human might like to see
-struct HumaneSourceLoc
-{
- PathInfo pathInfo = PathInfo::makeUnknown();
- Int line = 0;
- Int column = 0;
-};
-
-
-/* A SourceView maps to a single span of SourceLoc range and is equivalent to a single include or more precisely use of a source file.
-It is distinct from a SourceFile - because a SourceFile may be included multiple times, with different interpretations (depending
-on #defines for example).
-*/
-class SourceView
-{
- public:
-
- // Each entry represents some contiguous span of locations that
- // all map to the same logical file.
- struct Entry
- {
- /// True if this resets the line numbering. It is distinct from a m_lineAdjust being 0, because it also means the path returns to the default.
- bool isDefault() const { return m_pathHandle == StringSlicePool::Handle(0); }
-
- SourceLoc m_startLoc; ///< Where does this entry begin?
- StringSlicePool::Handle m_pathHandle; ///< What is the presumed path for this entry. If 0 it means there is no path.
- int32_t m_lineAdjust; ///< Adjustment to apply to source line numbers when printing presumed locations. Relative to the line number in the underlying file.
- };
-
- /// Given a sourceLoc finds the entry associated with it. If returns -1 then no entry is
- /// associated with this location, and therefore the location should be interpreted as an offset
- /// into the underlying sourceFile.
- int findEntryIndex(SourceLoc sourceLoc) const;
-
- /// Add a line directive for this view. The directiveLoc must of course be in this SourceView
- /// The path handle, must have been constructed on the SourceManager associated with the view
- /// NOTE! Directives are assumed to be added IN ORDER during parsing such that every directiveLoc > previous
- void addLineDirective(SourceLoc directiveLoc, StringSlicePool::Handle pathHandle, int line);
- void addLineDirective(SourceLoc directiveLoc, const String& path, int line);
-
- /// Removes any corrections on line numbers and reverts to the source files path
- void addDefaultLineDirective(SourceLoc directiveLoc);
-
- /// Get the range that this view applies to
- const SourceRange& getRange() const { return m_range; }
- /// Get the entries
- const List<Entry>& getEntries() const { return m_entries; }
- /// Set the entries list
- void setEntries(const Entry* entries, UInt numEntries) { m_entries.clear(); m_entries.addRange(entries, numEntries); }
-
- /// Get the source file holds the contents this view
- SourceFile* getSourceFile() const { return m_sourceFile; }
- /// Get the source manager
- SourceManager* getSourceManager() const { return m_sourceFile->getSourceManager(); }
-
- /// Get the associated 'content' (the source text)
- const UnownedStringSlice& getContent() const { return m_sourceFile->getContent(); }
-
- /// Get the size of the content
- size_t getContentSize() const { return m_sourceFile->getContentSize(); }
-
- /// Get the humane location
- /// Type determines if the location wanted is the original, or the 'normal' (which modifys behavior based on #line directives)
- HumaneSourceLoc getHumaneLoc(SourceLoc loc, SourceLocType type = SourceLocType::Nominal);
-
- /// Get the path associated with a location
- PathInfo getPathInfo(SourceLoc loc, SourceLocType type = SourceLocType::Nominal);
-
- /// Get the initiating source location - that is the source location that caused the this SourceView to be created
- /// Can be SourceLoc(0) if there is no initiating location.
- /// For example for a #include - the view's initiating source loc for the view that is the contents of the view
- /// will be the location of the #include in the source.
- /// For the original source file (ie not an include) - the view will have an initiating source loc of SourceLoc(0)
- SourceLoc getInitiatingSourceLoc() const { return m_initiatingSourceLoc; }
-
- /// Ctor
- SourceView(SourceFile* sourceFile, SourceRange range, const String* viewPath, SourceLoc initiatingSourceLoc):
- m_range(range),
- m_sourceFile(sourceFile),
- m_initiatingSourceLoc(initiatingSourceLoc)
- {
- if (viewPath)
- {
- m_viewPath = *viewPath;
- }
- }
-
- protected:
- /// Get the pathInfo from a string handle. If it's 0, it will return the _getPathInfo
- PathInfo _getPathInfoFromHandle(StringSlicePool::Handle pathHandle) const;
- /// Gets the pathInfo for this view. It may be different from the m_sourceFile's if the path has been
- /// overridden by m_viewPath
- PathInfo _getPathInfo() const;
-
- String m_viewPath; ///< Path to this view. If empty the path is the path to the SourceView
-
- SourceLoc m_initiatingSourceLoc; ///< An optional source loc that defines where this view was initiated from. SourceLoc(0) if not defined.
-
- SourceRange m_range; ///< The range that this SourceView applies to
- SourceFile* m_sourceFile; ///< The source file. Can hold the line breaks
- List<Entry> m_entries; ///< An array entries describing how we should interpret a range, starting from the start location.
-};
-
-struct SourceManager
-{
- // Initialize a source manager, with an optional parent
- void initialize(SourceManager* parent, ISlangFileSystemExt* fileSystemExt);
-
- /// Allocate a range of SourceLoc locations, these can be used to identify a specific location in the source
- SourceRange allocateSourceRange(UInt size);
-
- /// Create a SourceFile defined with the specified path, and content held within a blob
- SourceFile* createSourceFileWithSize(const PathInfo& pathInfo, size_t contentSize);
- SourceFile* createSourceFileWithString(const PathInfo& pathInfo, const String& contents);
- SourceFile* createSourceFileWithBlob(const PathInfo& pathInfo, ISlangBlob* blob);
-
- /// Get the humane source location
- HumaneSourceLoc getHumaneLoc(SourceLoc loc, SourceLocType type = SourceLocType::Nominal);
-
- /// Get the path associated with a location
- PathInfo getPathInfo(SourceLoc loc, SourceLocType type = SourceLocType::Nominal);
-
- /// Create a new source view from a file
- /// @param sourceFile is the source file that contains the source
- /// @param pathInfo is path used to read the file from
- /// @param initiatingSourceLoc the (optional) location in the source that led the the creation of this view. If there isn't an initiating source location pass SourceLoc(0)s
- SourceView* createSourceView(SourceFile* sourceFile, const PathInfo* pathInfo, SourceLoc initiatingSourceLoc);
-
- /// Find a view by a source file location.
- /// If not found in this manager will look in the parent SourceManager
- /// Returns nullptr if not found.
- SourceView* findSourceViewRecursively(SourceLoc loc) const;
-
- /// Find the SourceView associated with this manager for a specified location
- /// Returns nullptr if not found.
- SourceView* findSourceView(SourceLoc loc) const;
-
- /// Searches this manager, and then the parent to see if can find a match for path.
- /// If not found returns nullptr.
- SourceFile* findSourceFileRecursively(const String& uniqueIdentity) const;
- /// Find if the source file is defined on this manager.
- SourceFile* findSourceFile(const String& uniqueIdentity) const;
-
- /// Searches this manager, and then the parent to see if can find a match
- SourceFile* findSourceFileByContentRecursively(const char* text);
- /// Find the source file that contains *the memory* text points to.
- SourceFile* findSourceFileByContent(const char* text) const;
-
- /// Get the file system associated with this source manager
- ISlangFileSystemExt* getFileSystemExt() const { return m_fileSystemExt; }
- /// Get the file system associated with this source manager
- void setFileSystemExt(ISlangFileSystemExt* fileSystemExt) { m_fileSystemExt = fileSystemExt; }
-
- /// Add a source file, uniqueIdentity must be unique for this manager AND any parents
- void addSourceFile(const String& uniqueIdentity, SourceFile* sourceFile);
-
- /// Get the slice pool
- StringSlicePool& getStringSlicePool() { return m_slicePool; }
-
- /// Get the source range for just this manager
- /// Caution - the range will change if allocations are made to this manager.
- SourceRange getSourceRange() const { return SourceRange(m_startLoc, m_nextLoc); }
-
- /// Get the parent manager to this manager. Returns nullptr if there isn't any.
- SourceManager* getParent() const { return m_parent; }
-
- /// A memory arena to hold allocations that are in scope for the same time as SourceManager
- MemoryArena* getMemoryArena() { return &m_memoryArena; }
-
- /// Allocate a string slice
- UnownedStringSlice allocateStringSlice(const UnownedStringSlice& slice);
-
- /// Get all of the source files
- const List<SourceFile*>& getSourceFiles() const { return m_sourceFiles; }
-
- /// Get the source views
- const List<SourceView*>& getSourceViews() const { return m_sourceViews; }
-
- SourceManager() :
- m_memoryArena(2048),
- m_slicePool(StringSlicePool::Style::Default)
- {}
- ~SourceManager();
-
- protected:
-
- // The first location available to this source manager
- // (may not be the first location of all, because we might
- // have a parent source manager)
- SourceLoc m_startLoc;
-
- // The "parent" source manager that owns locations ahead of `startLoc`
- SourceManager* m_parent = nullptr;
-
- // The location to be used by the next source file to be loaded
- SourceLoc m_nextLoc;
-
- // All of the SourceViews constructed on this SourceManager. These are held in increasing order of range, so can find by doing a binary chop.
- List<SourceView*> m_sourceViews;
- // All of the SourceFiles constructed on this SourceManager. This owns the SourceFile.
- List<SourceFile*> m_sourceFiles;
-
- StringSlicePool m_slicePool;
-
- // Memory arena that can be used for holding data to held in scope as long as the Source is
- // Can be used for storing the decoded contents of Token. Content for example.
- MemoryArena m_memoryArena;
-
- // Maps uniqueIdentities to source files
- Dictionary<String, SourceFile*> m_sourceFileMap;
-
- ComPtr<ISlangFileSystemExt> m_fileSystemExt;
-};
-
-} // namespace Slang
-
-#endif
diff --git a/source/slang/slang-token-defs.h b/source/slang/slang-token-defs.h
deleted file mode 100644
index 6cece330e..000000000
--- a/source/slang/slang-token-defs.h
+++ /dev/null
@@ -1,96 +0,0 @@
-// slang-token-defs.h
-
-// This file is meant to be included multiple times, to produce different
-// pieces of code related to tokens
-//
-// Each token is declared here with:
-//
-// TOKEN(id, desc)
-//
-// where `id` is the identifier that will be used for the token in
-// ordinary code, while `desc` is name we should print when
-// referring to this token in diagnostic messages.
-
-
-#ifndef TOKEN
-#error Need to define TOKEN(ID, DESC) before including "token-defs.h"
-#endif
-
-TOKEN(Unknown, "<unknown>")
-TOKEN(EndOfFile, "end of file")
-TOKEN(EndOfDirective, "end of line")
-TOKEN(Invalid, "invalid character")
-TOKEN(Identifier, "identifier")
-TOKEN(IntegerLiteral, "integer literal")
-TOKEN(FloatingPointLiteral, "floating-point literal")
-TOKEN(StringLiteral, "string literal")
-TOKEN(CharLiteral, "character literal")
-TOKEN(WhiteSpace, "whitespace")
-TOKEN(NewLine, "newline")
-TOKEN(LineComment, "line comment")
-TOKEN(BlockComment, "block comment")
-TOKEN(DirectiveMessage, "user-defined message")
-
-#define PUNCTUATION(id, text) \
- TOKEN(id, "'" text "'")
-
-PUNCTUATION(Semicolon, ";")
-PUNCTUATION(Comma, ",")
-PUNCTUATION(Dot, ".")
-
-PUNCTUATION(LBrace, "{")
-PUNCTUATION(RBrace, "}")
-PUNCTUATION(LBracket, "[")
-PUNCTUATION(RBracket, "]")
-PUNCTUATION(LParent, "(")
-PUNCTUATION(RParent, ")")
-
-PUNCTUATION(OpAssign, "=")
-PUNCTUATION(OpAdd, "+")
-PUNCTUATION(OpSub, "-")
-PUNCTUATION(OpMul, "*")
-PUNCTUATION(OpDiv, "/")
-PUNCTUATION(OpMod, "%")
-PUNCTUATION(OpNot, "!")
-PUNCTUATION(OpBitNot, "~")
-PUNCTUATION(OpLsh, "<<")
-PUNCTUATION(OpRsh, ">>")
-PUNCTUATION(OpEql, "==")
-PUNCTUATION(OpNeq, "!=")
-PUNCTUATION(OpGreater, ">")
-PUNCTUATION(OpLess, "<")
-PUNCTUATION(OpGeq, ">=")
-PUNCTUATION(OpLeq, "<=")
-PUNCTUATION(OpAnd, "&&")
-PUNCTUATION(OpOr, "||")
-PUNCTUATION(OpBitAnd, "&")
-PUNCTUATION(OpBitOr, "|")
-PUNCTUATION(OpBitXor, "^")
-PUNCTUATION(OpInc, "++")
-PUNCTUATION(OpDec, "--")
-
-PUNCTUATION(OpAddAssign, "+=")
-PUNCTUATION(OpSubAssign, "-=")
-PUNCTUATION(OpMulAssign, "*=")
-PUNCTUATION(OpDivAssign, "/=")
-PUNCTUATION(OpModAssign, "%=")
-PUNCTUATION(OpShlAssign, "<<=")
-PUNCTUATION(OpShrAssign, ">>=")
-PUNCTUATION(OpAndAssign, "&=")
-PUNCTUATION(OpOrAssign, "|=")
-PUNCTUATION(OpXorAssign, "^=")
-
-PUNCTUATION(QuestionMark, "?")
-PUNCTUATION(Colon, ":")
-PUNCTUATION(RightArrow, "->")
-PUNCTUATION(At, "@")
-PUNCTUATION(Dollar, "$")
-PUNCTUATION(Pound, "#")
-PUNCTUATION(PoundPound, "##")
-
-PUNCTUATION(Scope, "::")
-
-#undef PUNCTUATION
-
-// Un-define the `TOKEN` macro so that client doesn't have to
-#undef TOKEN
diff --git a/source/slang/slang-token.cpp b/source/slang/slang-token.cpp
deleted file mode 100644
index a7f6d7d62..000000000
--- a/source/slang/slang-token.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-// slang-token.cpp
-#include "slang-token.h"
-
-#include <assert.h>
-
-namespace Slang {
-
-
-
-
-char const* TokenTypeToString(TokenType type)
-{
- switch( type )
- {
- default:
- SLANG_ASSERT(!"unexpected");
- return "<uknown>";
-
-#define TOKEN(NAME, DESC) case TokenType::NAME: return DESC;
-#include "slang-token-defs.h"
- }
-}
-
-} // namespace Slang
diff --git a/source/slang/slang-token.h b/source/slang/slang-token.h
deleted file mode 100644
index 9697a5c2d..000000000
--- a/source/slang/slang-token.h
+++ /dev/null
@@ -1,140 +0,0 @@
-// slang-token.h
-#ifndef SLANG_TOKEN_H_INCLUDED
-#define SLANG_TOKEN_H_INCLUDED
-
-#include "../core/slang-basic.h"
-
-#include "slang-source-loc.h"
-#include "slang-name.h"
-
-namespace Slang {
-
-class Name;
-
-enum class TokenType : uint8_t
-{
-#define TOKEN(NAME, DESC) NAME,
-#include "slang-token-defs.h"
-};
-
-char const* TokenTypeToString(TokenType type);
-
-typedef uint8_t TokenFlags;
-struct TokenFlag
-{
- enum Enum : TokenFlags
- {
- AtStartOfLine = 1 << 0,
- AfterWhitespace = 1 << 1,
- SuppressMacroExpansion = 1 << 2,
- ScrubbingNeeded = 1 << 3,
- Name = 1 << 4, ///< Determines if 'name' is set or 'chars' in the charsNameUnion
- };
-};
-
-class Token
-{
-public:
-
- TokenType type = TokenType::Unknown;
- TokenFlags flags = 0;
-
- SourceLoc loc;
- uint32_t charsCount = 0; ///< Amount of characters. Is set if name or not.
-
- union CharsNameUnion
- {
- const char* chars;
- Name* name;
- };
-
- CharsNameUnion charsNameUnion;
-
- bool hasContent() const { return charsCount > 0; }
- Index getContentLength() const { return charsCount; }
-
- UnownedStringSlice getContent() const;
- /// Set content
- void setContent(const UnownedStringSlice& content);
-
- Name* getName() const;
-
- Name* getNameOrNull() const;
-
- SourceLoc getLoc() const { return loc; }
-
- /// Set the name
- SLANG_FORCE_INLINE void setName(Name* inName);
-
- Token()
- {
- charsNameUnion.chars = nullptr;
- }
-
- Token(
- TokenType inType,
- const UnownedStringSlice& inContent,
- SourceLoc inLoc,
- TokenFlags inFlags = 0)
- : flags(inFlags)
- {
- SLANG_ASSERT((inFlags & TokenFlag::Name) == 0);
- type = inType;
- charsNameUnion.chars = inContent.begin();
- charsCount = uint32_t(inContent.getLength());
- loc = inLoc;
- }
- Token(
- TokenType inType,
- Name* name,
- SourceLoc inLoc,
- TokenFlags inFlags = 0)
- {
- SLANG_ASSERT(name);
- type = inType;
- flags = inFlags | TokenFlag::Name;
- charsNameUnion.name = name;
- charsCount = uint32_t(name->text.getLength());
- loc = inLoc;
- }
-};
-
-// ---------------------------------------------------------------------------
-SLANG_FORCE_INLINE UnownedStringSlice Token::getContent() const
-{
- return (flags & TokenFlag::Name) ? charsNameUnion.name->text.getUnownedSlice() : UnownedStringSlice(charsNameUnion.chars, charsCount);
-}
-
-// ---------------------------------------------------------------------------
-SLANG_FORCE_INLINE Name* Token::getName() const
-{
- return getNameOrNull();
-}
-
-// ---------------------------------------------------------------------------
-SLANG_FORCE_INLINE Name* Token::getNameOrNull() const
-{
- return (flags & TokenFlag::Name) ? charsNameUnion.name : nullptr;
-}
-
-// ---------------------------------------------------------------------------
-SLANG_FORCE_INLINE void Token::setContent(const UnownedStringSlice& content)
-{
- flags &= ~TokenFlag::Name;
- charsNameUnion.chars = content.begin();
- charsCount = uint32_t(content.getLength());
-}
-
-// ---------------------------------------------------------------------------
-SLANG_FORCE_INLINE void Token::setName(Name* inName)
-{
- SLANG_ASSERT(inName);
- flags |= TokenFlag::Name;
- charsNameUnion.name = inName;
- charsCount = uint32_t(inName->text.getLength());
-}
-
-
-} // namespace Slang
-
-#endif
diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp
index bcc3d1c67..5c04777de 100644
--- a/source/slang/slang.cpp
+++ b/source/slang/slang.cpp
@@ -18,11 +18,10 @@
#include "slang-repro.h"
-#include "slang-file-system.h"
-
+#include "../core/slang-file-system.h"
#include "../core/slang-writer.h"
-#include "slang-source-loc.h"
+#include "../compiler-core/slang-source-loc.h"
#include "slang-ast-dump.h"