summaryrefslogtreecommitdiff
path: root/source/slang/slang-source-stream.cpp
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2019-06-04 15:10:26 -0400
committerGitHub <noreply@github.com>2019-06-04 15:10:26 -0400
commit0d9071bd1511ee2cb7d6ba6ce9e250d25613ddca (patch)
tree410558e5bae917d027209f5807f8633db8291069 /source/slang/slang-source-stream.cpp
parent0a8f7ae6b899718150f359a378e53bfedd090090 (diff)
Review improvements on #971: WIP: Support for other source target languages (#974)
* * Added SourceStyle to CLikeSourceEmitter, to limit cases to actual target types. * Made Impl methods _ prefixed * Small tidyup * * SourceStream -> SourceWriter * use slang-emit- prefix on SourceWriter file * * Remove EmitContext -> merge into CLikeSourceEmitter * slang-c-like-source-emitter -> slang-emit-source.cpp * ExtensionUsageTracker -> GLSLExtensionTracker slang-extension-usage-tracker.cpp/.h -> slang-emit-glsl-extension-tracker.cpp/.h * emit-source.cpp.h -> emit-c-like.cpp/.h * Small fix to move where some _ prefixed functions are declared in CLikeSourceEmitter.
Diffstat (limited to 'source/slang/slang-source-stream.cpp')
-rw-r--r--source/slang/slang-source-stream.cpp396
1 files changed, 0 insertions, 396 deletions
diff --git a/source/slang/slang-source-stream.cpp b/source/slang/slang-source-stream.cpp
deleted file mode 100644
index e561176ae..000000000
--- a/source/slang/slang-source-stream.cpp
+++ /dev/null
@@ -1,396 +0,0 @@
-// emit.cpp
-#include "slang-source-stream.h"
-
-// Disable warnings about sprintf
-#ifdef _WIN32
-# pragma warning(disable:4996)
-#endif
-
-// Note: using C++ stdio just to get a locale-independent
-// way to format floating-point values.
-//
-// TODO: Go ahead and implement the Dragon4 algorithm so
-// that we can print floating-point values to arbitrary
-// precision as needed.
-#include <sstream>
-
-namespace Slang {
-
-SourceStream::SourceStream(SourceManager* sourceManager, LineDirectiveMode lineDirectiveMode)
-{
- m_lineDirectiveMode = lineDirectiveMode;
- this->m_sourceManager = sourceManager;
-}
-
-String SourceStream::getContentAndClear()
-{
- String content(getContent());
- clearContent();
- return content;
-}
-
-void SourceStream::emitRawTextSpan(char const* textBegin, char const* textEnd)
-{
- // TODO(tfoley): Need to make "corelib" not use `int` for pointer-sized things...
- auto len = textEnd - textBegin;
- m_builder.Append(textBegin, len);
-}
-
-void SourceStream::emitRawText(char const* text)
-{
- emitRawTextSpan(text, text + strlen(text));
-}
-
-void SourceStream::_emitTextSpan(char const* textBegin, char const* textEnd)
-{
- // Don't change anything given an empty string
- if (textBegin == textEnd)
- return;
-
- // If the source location has changed in a way that required update,
- // do it now!
- _flushSourceLocationChange();
-
- // Note: we don't want to emit indentation on a line that is empty.
- // The logic in `Emit(textBegin, textEnd)` below will have broken
- // the text into lines, so we can simply check if a line consists
- // of just a newline.
- if (m_isAtStartOfLine && *textBegin != '\n')
- {
- // We are about to emit text (other than a newline)
- // at the start of a line, so we will emit the proper
- // amount of indentation to keep things looking nice.
- m_isAtStartOfLine = false;
- for (Int ii = 0; ii < m_indentLevel; ++ii)
- {
- char const* indentString = " ";
- size_t indentStringSize = strlen(indentString);
- emitRawTextSpan(indentString, indentString + indentStringSize);
-
- // We will also update our tracking location, just in
- // case other logic needs it.
- //
- // TODO: We may need to have a switch that controls whether
- // we are in "pretty-printing" mode or "follow the locations
- // in the original code" mode.
- m_loc.column += indentStringSize;
- }
- }
-
- // Emit the raw text
- emitRawTextSpan(textBegin, textEnd);
-
- // Update our logical position
- auto len = int(textEnd - textBegin);
- m_loc.column += len;
-}
-
-void SourceStream::indent()
-{
- m_indentLevel++;
-}
-
-void SourceStream::dedent()
-{
- m_indentLevel--;
-}
-
-void SourceStream::emit(char const* textBegin, char const* textEnd)
-{
- char const* spanBegin = textBegin;
- char const* spanEnd = spanBegin;
- for (;;)
- {
- if (spanEnd == textEnd)
- {
- // We have a whole range of text waiting to be flushed
- _emitTextSpan(spanBegin, spanEnd);
- return;
- }
-
- auto c = *spanEnd++;
-
- if (c == '\n')
- {
- // At the end of a line, we need to update our tracking
- // information on code positions
- _emitTextSpan(spanBegin, spanEnd);
- m_loc.line++;
- m_loc.column = 1;
- m_isAtStartOfLine = true;
-
- // Start a new span for emit purposes
- spanBegin = spanEnd;
- }
- }
-}
-
-void SourceStream::emit(char const* text)
-{
- emit(text, text + strlen(text));
-}
-
-void SourceStream::emit(const String& text)
-{
- emit(text.begin(), text.end());
-}
-
-void SourceStream::emit(const UnownedStringSlice& text)
-{
- emit(text.begin(), text.end());
-}
-
-void SourceStream::emit(Name* name)
-{
- emit(getText(name));
-}
-
-void SourceStream::emit(const NameLoc& nameAndLoc)
-{
- advanceToSourceLocation(nameAndLoc.loc);
- emit(getText(nameAndLoc.name));
-}
-
-void SourceStream::emitName(Name* name, const SourceLoc& locIn)
-{
- advanceToSourceLocation(locIn);
- emit(name);
-}
-
-void SourceStream::emitName(const NameLoc& nameAndLoc)
-{
- emitName(nameAndLoc.name, nameAndLoc.loc);
-}
-
-void SourceStream::emitName(Name* name)
-{
- emitName(name, SourceLoc());
-}
-
-void SourceStream::emit(IntegerLiteralValue value)
-{
- char buffer[32];
- sprintf(buffer, "%lld", (long long int)value);
- emit(buffer);
-}
-
-void SourceStream::emit(UInt value)
-{
- char buffer[32];
- sprintf(buffer, "%llu", (unsigned long long)(value));
- emit(buffer);
-}
-
-void SourceStream::emit(int value)
-{
- char buffer[16];
- sprintf(buffer, "%d", value);
- emit(buffer);
-}
-
-void SourceStream::emit(double value)
-{
- // There are a few different requirements here that we need to deal with:
- //
- // 1) We need to print something that is valid syntax in the target language
- // (this means that hex floats are off the table for now)
- //
- // 2) We need our printing to be independent of the current global locale in C,
- // so that we don't depend on the application leaving it as the default,
- // and we also don't revert any changes they make.
- // (this means that `sprintf` and friends are off the table)
- //
- // 3) We need to be sure that floating-point literals specified by the user will
- // "round-trip" and turn into the same value when parsed back in. This means
- // that we need to print a reasonable number of digits of precision.
- //
- // For right now, the easiest option that can balance these is to use
- // the C++ standard library `iostream`s, because they support an explicit locale,
- // and can (hopefully) print floating-point numbers accurately.
- //
- // Eventually, the right move here would be to implement proper floating-point
- // number formatting ourselves, but that would require extensive testing to
- // make sure we get it right.
-
- std::ostringstream stream;
- stream.imbue(std::locale::classic());
- stream.setf(std::ios::fixed, std::ios::floatfield);
- stream.precision(20);
- stream << value;
-
- emit(stream.str().c_str());
-}
-
-void SourceStream::advanceToSourceLocation(const SourceLoc& sourceLocation)
-{
- advanceToSourceLocation(getSourceManager()->getHumaneLoc(sourceLocation));
-}
-
-void SourceStream::advanceToSourceLocation(const HumaneSourceLoc& sourceLocation)
-{
- // Skip invalid locations
- if (sourceLocation.line <= 0)
- return;
-
- m_needToUpdateSourceLocation = true;
- m_nextSourceLocation = sourceLocation;
-}
-
-void SourceStream::_flushSourceLocationChange()
-{
- if (!m_needToUpdateSourceLocation)
- return;
-
- // Note: the order matters here, because trying to update
- // the source location may involve outputting text that
- // advances the location, and outputting text is what
- // triggers this flush operation.
- m_needToUpdateSourceLocation = false;
- _emitLineDirectiveIfNeeded(m_nextSourceLocation);
-}
-
-void SourceStream::_emitLineDirectiveAndUpdateSourceLocation(const HumaneSourceLoc& sourceLocation)
-{
- _emitLineDirective(sourceLocation);
-
- HumaneSourceLoc newLoc = sourceLocation;
- newLoc.column = 1;
-
- m_loc = newLoc;
-}
-
-void SourceStream::_emitLineDirectiveIfNeeded(const HumaneSourceLoc& sourceLocation)
-{
- // Don't do any of this work if the user has requested that we
- // not emit line directives.
- auto mode = getLineDirectiveMode();
- switch (mode)
- {
- case LineDirectiveMode::None:
- return;
-
- case LineDirectiveMode::Default:
- default:
- break;
- }
-
- // Ignore invalid source locations
- if (sourceLocation.line <= 0)
- return;
-
- // If we are currently emitting code at a source location with
- // a differnet file or line, *or* if the source location is
- // somehow later on the line than what we want to emit,
- // then we need to emit a new `#line` directive.
- if (sourceLocation.pathInfo.foundPath != m_loc.pathInfo.foundPath
- || sourceLocation.line != m_loc.line
- || sourceLocation.column < m_loc.column)
- {
- // Special case: if we are in the same file, and within a small number
- // of lines of the target location, then go ahead and output newlines
- // to get us caught up.
- enum { kSmallLineCount = 3 };
- auto lineDiff = sourceLocation.line - m_loc.line;
- if (sourceLocation.pathInfo.foundPath == m_loc.pathInfo.foundPath
- && sourceLocation.line > m_loc.line
- && lineDiff <= kSmallLineCount)
- {
- for (int ii = 0; ii < lineDiff; ++ii)
- {
- emit("\n");
- }
- SLANG_RELEASE_ASSERT(sourceLocation.line == m_loc.line);
- }
- else
- {
- // Go ahead and output a `#line` directive to get us caught up
- _emitLineDirectiveAndUpdateSourceLocation(sourceLocation);
- }
- }
-}
-
-void SourceStream::_emitLineDirective(const HumaneSourceLoc& sourceLocation)
-{
- emitRawText("\n#line ");
-
- char buffer[16];
- sprintf(buffer, "%llu", (unsigned long long)sourceLocation.line);
- emitRawText(buffer);
-
- // Only emit the path part of a `#line` directive if needed
- if (sourceLocation.pathInfo.foundPath != m_loc.pathInfo.foundPath)
- {
- emitRawText(" ");
-
- auto mode = getLineDirectiveMode();
- switch (mode)
- {
- default:
- case LineDirectiveMode::None:
- SLANG_UNEXPECTED("should not be trying to emit '#line' directive");
- return;
- case LineDirectiveMode::GLSL:
- {
- auto path = sourceLocation.pathInfo.foundPath;
-
- // GLSL doesn't support the traditional form of a `#line` directive without
- // an extension. Rather than depend on that extension we will output
- // a directive in the traditional GLSL fashion.
- //
- // TODO: Add some kind of configuration where we require the appropriate
- // extension and then emit a traditional line directive.
-
- int id = 0;
- if (!m_mapGLSLSourcePathToID.TryGetValue(path, id))
- {
- id = m_glslSourceIDCount++;
- m_mapGLSLSourcePathToID.Add(path, id);
- }
-
- sprintf(buffer, "%d", id);
- emitRawText(buffer);
- break;
- }
- case LineDirectiveMode::Default:
- case LineDirectiveMode::Standard:
- {
- // The simple case is to emit the path for the current source
- // location. We need to be a little bit careful with this,
- // because the path might include backslash characters if we
- // are on Windows, and we want to canonicalize those over
- // to forward slashes.
- //
- // TODO: Canonicalization like this should be done centrally
- // in a module that tracks source files.
-
- emitRawText("\"");
- const auto& path = sourceLocation.pathInfo.foundPath;
- for (auto c : path)
- {
- char charBuffer[] = { c, 0 };
- switch (c)
- {
- default:
- emitRawText(charBuffer);
- break;
-
- // The incoming file path might use `/` and/or `\\` as
- // a directory separator. We want to canonicalize this.
- //
- // TODO: should probably canonicalize paths to not use backslash somewhere else
- // in the compilation pipeline...
- case '\\':
- emitRawText("/");
- break;
- }
- }
- emitRawText("\"");
- break;
- }
- }
- }
-
- emitRawText("\n");
-}
-
-} // namespace Slang