summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/core/slang-string.cpp5
-rw-r--r--source/core/slang-string.h7
-rw-r--r--source/slang/diagnostic-defs.h32
-rw-r--r--source/slang/diagnostics.cpp6
-rw-r--r--source/slang/diagnostics.h1
-rw-r--r--source/slang/modifier-defs.h4
-rw-r--r--source/slang/parameter-binding.cpp105
-rw-r--r--source/slang/parser.cpp81
8 files changed, 200 insertions, 41 deletions
diff --git a/source/core/slang-string.cpp b/source/core/slang-string.cpp
index 2420cb7d7..b195e12d5 100644
--- a/source/core/slang-string.cpp
+++ b/source/core/slang-string.cpp
@@ -298,6 +298,11 @@ namespace Slang
append(slice.begin(), slice.end());
}
+ void String::append(UnownedStringSlice const& slice)
+ {
+ append(slice.begin(), slice.end());
+ }
+
void String::append(int32_t value, int radix)
{
enum { kCount = 33 };
diff --git a/source/core/slang-string.h b/source/core/slang-string.h
index 9f18554f6..894776ca6 100644
--- a/source/core/slang-string.h
+++ b/source/core/slang-string.h
@@ -193,6 +193,12 @@ namespace Slang
return (*this) == UnownedStringSlice(str, str + strlen(str));
}
+ bool operator!=(UnownedStringSlice const& other) const
+ {
+ return !(*this == other);
+ }
+
+
bool endsWith(UnownedStringSlice const& other) const;
bool endsWith(char const* str) const;
@@ -328,6 +334,7 @@ namespace Slang
void append(char chr);
void append(String const& str);
void append(StringSlice const& slice);
+ void append(UnownedStringSlice const& slice);
String(int32_t val, int radix = 10)
{
diff --git a/source/slang/diagnostic-defs.h b/source/slang/diagnostic-defs.h
index 8f564cc59..f8e048bdb 100644
--- a/source/slang/diagnostic-defs.h
+++ b/source/slang/diagnostic-defs.h
@@ -253,18 +253,6 @@ DIAGNOSTIC(39999, Error, tooManyArguments, "too many arguments to call (got $0,
DIAGNOSTIC(39999, Error, invalidIntegerLiteralSuffix, "invalid suffix '$0' on integer literal")
DIAGNOSTIC(39999, Error, invalidFloatingPOintLiteralSuffix, "invalid suffix '$0' on floating-point literal")
-DIAGNOSTIC(39999, Error, conflictingExplicitBindingsForParameter, "conflicting explicit bindings for parameter '$0'")
-DIAGNOSTIC(39999, Warning, parameterBindingsOverlap, "explicit binding for parameter '$0' overlaps with parameter '$1'")
-
-
-DIAGNOSTIC(39999, Error, shaderParameterDeclarationsDontMatch, "declarations of shader parameter '$0' in different translation units don't match")
-
-DIAGNOSTIC(39999, Note, shaderParameterTypeMismatch, "type is declared as '$0' in one translation unit, and '$0' in another")
-DIAGNOSTIC(39999, Note, fieldTypeMisMatch, "type of field '$0' is declared as '$1' in one translation unit, and '$2' in another")
-DIAGNOSTIC(39999, Note, fieldDeclarationsDontMatch, "type '$0' is declared with different fields in each translation unit")
-DIAGNOSTIC(39999, Note, usedInDeclarationOf, "used in declaration of '$0'")
-
-
@@ -287,6 +275,26 @@ DIAGNOSTIC(38021, Error, typeArgumentDoesNotConformToInterface, "type argument `
DIAGNOSTIC(38200, Error, recursiveModuleImport, "module `$0` recursively imports itself")
DIAGNOSTIC(39999, Fatal, errorInImportedModule, "error in imported module, compilation ceased.")
+// 39xxx - Type layout and parameter binding.
+
+DIAGNOSTIC(39000, Error, conflictingExplicitBindingsForParameter, "conflicting explicit bindings for parameter '$0'")
+DIAGNOSTIC(39001, Warning, parameterBindingsOverlap, "explicit binding for parameter '$0' overlaps with parameter '$1'")
+
+
+DIAGNOSTIC(39002, Error, shaderParameterDeclarationsDontMatch, "declarations of shader parameter '$0' in different translation units don't match")
+
+DIAGNOSTIC(39003, Note, shaderParameterTypeMismatch, "type is declared as '$0' in one translation unit, and '$0' in another")
+DIAGNOSTIC(39004, Note, fieldTypeMisMatch, "type of field '$0' is declared as '$1' in one translation unit, and '$2' in another")
+DIAGNOSTIC(39005, Note, fieldDeclarationsDontMatch, "type '$0' is declared with different fields in each translation unit")
+DIAGNOSTIC(39006, Note, usedInDeclarationOf, "used in declaration of '$0'")
+
+DIAGNOSTIC(39007, Error, unknownRegisterClass, "unknown register class: '$0'")
+DIAGNOSTIC(39008, Error, expectedARegisterIndex, "expected a register index after '$0'")
+DIAGNOSTIC(39009, Error, expectedSpace, "expected 'space', got '$0'")
+DIAGNOSTIC(39010, Error, expectedSpaceIndex, "expected a register space index after 'space'")
+DIAGNOSTIC(39011, Error, componentMaskNotSupported, "explicit register component masks are not yet supported in Slang")
+DIAGNOSTIC(39012, Error, packOffsetNotSupported, "explicit 'packoffset' bindings are not yet supported in Slang")
+
//
// 4xxxx - IL code generation.
//
diff --git a/source/slang/diagnostics.cpp b/source/slang/diagnostics.cpp
index 03acf50dc..77473b95f 100644
--- a/source/slang/diagnostics.cpp
+++ b/source/slang/diagnostics.cpp
@@ -39,6 +39,12 @@ 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);
diff --git a/source/slang/diagnostics.h b/source/slang/diagnostics.h
index 9bc3b3d8c..a12de03e4 100644
--- a/source/slang/diagnostics.h
+++ b/source/slang/diagnostics.h
@@ -77,6 +77,7 @@ namespace Slang
void printDiagnosticArg(StringBuilder& sb, int val);
void printDiagnosticArg(StringBuilder& sb, UInt 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, Decl* decl);
void printDiagnosticArg(StringBuilder& sb, Type* type);
diff --git a/source/slang/modifier-defs.h b/source/slang/modifier-defs.h
index 6212a244e..f9b3b6675 100644
--- a/source/slang/modifier-defs.h
+++ b/source/slang/modifier-defs.h
@@ -164,7 +164,9 @@ SYNTAX_CLASS(HLSLLayoutSemantic, HLSLSemantic)
END_SYNTAX_CLASS()
// An HLSL `register` semantic
-SIMPLE_SYNTAX_CLASS(HLSLRegisterSemantic, HLSLLayoutSemantic)
+SYNTAX_CLASS(HLSLRegisterSemantic, HLSLLayoutSemantic)
+ FIELD(Token, spaceName)
+END_SYNTAX_CLASS()
// TODO(tfoley): `packoffset`
SIMPLE_SYNTAX_CLASS(HLSLPackOffsetSemantic, HLSLLayoutSemantic)
diff --git a/source/slang/parameter-binding.cpp b/source/slang/parameter-binding.cpp
index 4378cb06b..e0cc26f2b 100644
--- a/source/slang/parameter-binding.cpp
+++ b/source/slang/parameter-binding.cpp
@@ -288,8 +288,34 @@ struct LayoutSemanticInfo
// TODO: need to deal with component-granularity binding...
};
+static bool isDigit(char c)
+{
+ return (c >= '0') && (c <= '9');
+}
+
+/// Given a string that specifies a name and index (e.g., `COLOR0`),
+/// split it into slices for the name part and the index part.
+static void splitNameAndIndex(
+ String const& text,
+ UnownedStringSlice& outName,
+ UnownedStringSlice& outDigits)
+{
+ char const* nameBegin = text.begin();
+ char const* digitsEnd = text.end();
+
+ char const* nameEnd = digitsEnd;
+ while( nameEnd != nameBegin && isDigit(*(nameEnd - 1)) )
+ {
+ nameEnd--;
+ }
+ char const* digitsBegin = nameEnd;
+
+ outName = UnownedStringSlice(nameBegin, nameEnd);
+ outDigits = UnownedStringSlice(digitsBegin, digitsEnd);
+}
+
LayoutSemanticInfo ExtractLayoutSemanticInfo(
- ParameterBindingContext* /*context*/,
+ ParameterBindingContext* context,
HLSLLayoutSemantic* semantic)
{
LayoutSemanticInfo info;
@@ -297,12 +323,31 @@ LayoutSemanticInfo ExtractLayoutSemanticInfo(
info.index = 0;
info.kind = LayoutResourceKind::None;
- auto registerName = semantic->registerName.Content;
+ String registerName = semantic->registerName.Content;
if (registerName.Length() == 0)
return info;
+ // The register name is expected to be in the form:
+ //
+ // identifier-char+ digit+
+ //
+ // where the identifier characters name a "register class"
+ // and the digits identify a register index within that class.
+ //
+ // We are going to split the string the user gave us
+ // into these constituent parts:
+ //
+ UnownedStringSlice registerClassName;
+ UnownedStringSlice registerIndexDigits;
+ splitNameAndIndex(registerName, registerClassName, registerIndexDigits);
+
+ // All of the register classes we support are single ASCII characters,
+ // so we really just care about the first byte, but we want to be
+ // careful and only look at it if the register class name is one
+ // byte long.
+ char registerClassChar = registerClassName.size() == 1 ? *registerClassName.begin() : 0;
LayoutResourceKind kind = LayoutResourceKind::None;
- switch (registerName[0])
+ switch (registerClassChar)
{
case 'b':
kind = LayoutResourceKind::ConstantBuffer;
@@ -321,29 +366,59 @@ LayoutSemanticInfo ExtractLayoutSemanticInfo(
break;
default:
- // TODO: issue an error here!
+ getSink(context)->diagnose(semantic->registerName, Diagnostics::unknownRegisterClass, registerClassName);
return info;
}
- // TODO: need to parse and handle `space` binding
- int space = 0;
+ // For a `register` semantic, the register index is not optional (unlike
+ // how it works for varying input/output semantics).
+ if( registerIndexDigits.size() == 0 )
+ {
+ getSink(context)->diagnose(semantic->registerName, Diagnostics::expectedARegisterIndex, registerClassName);
+ }
UInt index = 0;
- for (UInt ii = 1; ii < registerName.Length(); ++ii)
+ for(auto c : registerIndexDigits)
{
- int c = registerName[ii];
- if (c >= '0' && c <= '9')
- {
- index = index * 10 + (c - '0');
- }
- else
+ SLANG_ASSERT(isDigit(c));
+ index = index * 10 + (c - '0');
+ }
+
+
+ UInt space = 0;
+ if( auto registerSemantic = dynamic_cast<HLSLRegisterSemantic*>(semantic) )
+ {
+ auto const& spaceName = registerSemantic->spaceName.Content;
+ if(spaceName.Length() != 0)
{
- // TODO: issue an error here!
- return info;
+ UnownedStringSlice spaceSpelling;
+ UnownedStringSlice spaceDigits;
+ splitNameAndIndex(spaceName, spaceSpelling, spaceDigits);
+
+ if( spaceSpelling != UnownedTerminatedStringSlice("space") )
+ {
+ getSink(context)->diagnose(semantic->registerName, Diagnostics::expectedSpace, spaceSpelling);
+ }
+ else if( spaceDigits.size() == 0 )
+ {
+ getSink(context)->diagnose(semantic->registerName, Diagnostics::expectedSpaceIndex);
+ }
+ else
+ {
+ for(auto c : spaceDigits)
+ {
+ SLANG_ASSERT(isDigit(c));
+ space = space * 10 + (c - '0');
+ }
+ }
}
}
// TODO: handle component mask part of things...
+ if( semantic->componentMask.Content.Length() != 0 )
+ {
+ getSink(context)->diagnose(semantic->componentMask, Diagnostics::componentMaskNotSupported);
+ }
info.kind = kind;
info.index = (int) index;
diff --git a/source/slang/parser.cpp b/source/slang/parser.cpp
index 5d1b254d7..ab95be5ac 100644
--- a/source/slang/parser.cpp
+++ b/source/slang/parser.cpp
@@ -1835,24 +1835,76 @@ namespace Slang
}
}
- //
- // layout-semantic ::= (register | packoffset) '(' register-name component-mask? ')'
- // register-name ::= identifier
- // component-mask ::= '.' identifier
- //
- static void ParseHLSLLayoutSemantic(
- Parser* parser,
- HLSLLayoutSemantic* semantic)
+ /// Parse the "register name" part of a `register` or `packoffset` semantic.
+ ///
+ /// The syntax matched is:
+ ///
+ /// register-name-and-component-mask ::= register-name component-mask?
+ /// register-name ::= identifier
+ /// component-mask ::= '.' identifier
+ ///
+ static void parseHLSLRegisterNameAndOptionalComponentMask(
+ Parser* parser,
+ HLSLLayoutSemantic* semantic)
{
- semantic->name = parser->ReadToken(TokenType::Identifier);
-
- parser->ReadToken(TokenType::LParent);
semantic->registerName = parser->ReadToken(TokenType::Identifier);
if (AdvanceIf(parser, TokenType::Dot))
{
semantic->componentMask = parser->ReadToken(TokenType::Identifier);
}
+ }
+
+ /// Parse an HLSL `register` semantic.
+ ///
+ /// The syntax matched is:
+ ///
+ /// register-semantic ::= 'register' '(' register-name-and-component-mask register-space? ')'
+ /// register-space ::= ',' identifier
+ ///
+ static void parseHLSLRegisterSemantic(
+ Parser* parser,
+ HLSLRegisterSemantic* semantic)
+ {
+ // Read the `register` keyword
+ semantic->name = parser->ReadToken(TokenType::Identifier);
+
+ // Expect a parenthized list of additional arguments
+ parser->ReadToken(TokenType::LParent);
+
+ // First argument is a required register name and optional component mask
+ parseHLSLRegisterNameAndOptionalComponentMask(parser, semantic);
+
+ // Second argument is an optional register space
+ if(AdvanceIf(parser, TokenType::Comma))
+ {
+ semantic->spaceName = parser->ReadToken(TokenType::Identifier);
+ }
+
+ parser->ReadToken(TokenType::RParent);
+ }
+
+ /// Parse an HLSL `packoffset` semantic.
+ ///
+ /// The syntax matched is:
+ ///
+ /// packoffset-semantic ::= 'packoffset' '(' register-name-and-component-mask ')'
+ ///
+ static void parseHLSLPackOffsetSemantic(
+ Parser* parser,
+ HLSLPackOffsetSemantic* semantic)
+ {
+ // Read the `packoffset` keyword
+ semantic->name = parser->ReadToken(TokenType::Identifier);
+
+ // Expect a parenthized list of additional arguments
+ parser->ReadToken(TokenType::LParent);
+
+ // First and only argument is a required register name and optional component mask
+ parseHLSLRegisterNameAndOptionalComponentMask(parser, semantic);
+
parser->ReadToken(TokenType::RParent);
+
+ parser->sink->diagnose(semantic, Diagnostics::packOffsetNotSupported);
}
//
@@ -1864,18 +1916,21 @@ namespace Slang
if (parser->LookAheadToken("register"))
{
RefPtr<HLSLRegisterSemantic> semantic = new HLSLRegisterSemantic();
- ParseHLSLLayoutSemantic(parser, semantic.Ptr());
+ parser->FillPosition(semantic);
+ parseHLSLRegisterSemantic(parser, semantic.Ptr());
return semantic;
}
else if (parser->LookAheadToken("packoffset"))
{
RefPtr<HLSLPackOffsetSemantic> semantic = new HLSLPackOffsetSemantic();
- ParseHLSLLayoutSemantic(parser, semantic.Ptr());
+ parser->FillPosition(semantic);
+ parseHLSLPackOffsetSemantic(parser, semantic.Ptr());
return semantic;
}
else if (parser->LookAheadToken(TokenType::Identifier))
{
RefPtr<HLSLSimpleSemantic> semantic = new HLSLSimpleSemantic();
+ parser->FillPosition(semantic);
semantic->name = parser->ReadToken(TokenType::Identifier);
return semantic;
}