summaryrefslogtreecommitdiffstats
path: root/source/slang/parser.cpp
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2018-07-31 11:03:53 -0400
committerGitHub <noreply@github.com>2018-07-31 11:03:53 -0400
commit9914ca800c92e9b3fe768dec4e913a302f3d678d (patch)
tree49544fb2c0387f39876fd99e112cfc32ed05302d /source/slang/parser.cpp
parent171f524d7ca2922084a33f50c77a1e8797e80949 (diff)
Feature/attributed binding (#621)
* Typo fix, and added dxc to command line documentation. * Fix small typos. Added support for Scope to lexer. Fix bug in Token ctor. * Add support for attribute names that are scoped. * Added GLSLBindingAttribute. Make binding work through core.met.slang. * Allow [[gl::binding(binding, set)]] [[vk::binding(binding,set)]]
Diffstat (limited to 'source/slang/parser.cpp')
-rw-r--r--source/slang/parser.cpp194
1 files changed, 161 insertions, 33 deletions
diff --git a/source/slang/parser.cpp b/source/slang/parser.cpp
index fee5d04b6..62fed75cc 100644
--- a/source/slang/parser.cpp
+++ b/source/slang/parser.cpp
@@ -8,6 +8,52 @@
namespace Slang
{
+ // Pre-declare
+ static Name* getName(Parser* parser, String const& text);
+
+ // Helper class useful to build a list of modifiers.
+ struct ModifierListBuilder
+ {
+ ModifierListBuilder()
+ {
+ m_next = &m_result;
+ }
+ void add(Modifier* modifier)
+ {
+ // Doesn't handle SharedModifiers
+ SLANG_ASSERT(modifier->As<SharedModifiers>() == nullptr);
+
+ // Splice at end
+ *m_next = modifier;
+ m_next = &modifier->next;
+ }
+ template <typename T>
+ T* find() const
+ {
+ Modifier* cur = m_result;
+ while (cur)
+ {
+ T* castCur = cur->As<T>();
+ if (castCur)
+ {
+ return castCur;
+ }
+ cur = cur->next;
+ }
+ return nullptr;
+ }
+ template <typename T>
+ bool hasType() const
+ {
+ return find<T>() != nullptr;
+ }
+ RefPtr<Modifier> getFirst() { return m_result; };
+ protected:
+
+ RefPtr<Modifier> m_result;
+ RefPtr<Modifier>* m_next;
+ };
+
enum Precedence : int
{
Invalid = -1,
@@ -567,7 +613,9 @@ namespace Slang
// About to look at shared modifiers? Done.
RefPtr<Modifier> linkMod = *modifierLink;
if(linkMod.As<SharedModifiers>())
+ {
break;
+ }
// Otherwise: keep traversing the modifier list.
modifierLink = &(*modifierLink)->next;
@@ -575,7 +623,7 @@ namespace Slang
// Splice the modifier into the linked list
- // We need to deal with the case where the modifeir to
+ // We need to deal with the case where the modifier to
// be spliced in might actually be a modifier *list*,
// so that we actually want to splice in at the
// end of the new list...
@@ -598,10 +646,57 @@ namespace Slang
AddModifier(&modifierLink, modifier);
}
+ //
+ // '::'? identifier ('::' identifier)*
+ static Token parseAttributeName(Parser* parser)
+ {
+ const SourceLoc scopedIdSourceLoc = parser->tokenReader.PeekLoc();
+
+ // Strip initial :: if there is one
+ const TokenType initialTokenType = parser->tokenReader.PeekTokenType();
+ if (initialTokenType == TokenType::Scope)
+ {
+ parser->ReadToken(TokenType::Scope);
+ }
+
+ const Token firstIdentifier = parser->ReadToken(TokenType::Identifier);
+ if (initialTokenType != TokenType::Scope && parser->tokenReader.PeekTokenType() != TokenType::Scope)
+ {
+ return firstIdentifier;
+ }
+
+ // Build up scoped string
+ StringBuilder scopedIdentifierBuilder;
+ if (initialTokenType == TokenType::Scope)
+ {
+ scopedIdentifierBuilder.Append('_');
+ }
+ scopedIdentifierBuilder.Append(firstIdentifier.Content);
+
+ while (parser->tokenReader.PeekTokenType() == TokenType::Scope)
+ {
+ parser->ReadToken(TokenType::Scope);
+ scopedIdentifierBuilder.Append('_');
+
+ const Token nextIdentifier(parser->ReadToken(TokenType::Identifier));
+ scopedIdentifierBuilder.Append(nextIdentifier.Content);
+ }
+
+ // Make a 'token'
+ const String scopedIdentifier(scopedIdentifierBuilder.ToString());
+ Token token(TokenType::Identifier, scopedIdentifier, scopedIdSourceLoc);
+ token.ptrValue = getName(parser, token.Content);
+
+ return token;
+ }
+
// Parse HLSL-style `[name(arg, ...)]` style "attribute" modifiers
static void ParseSquareBracketAttributes(Parser* parser, RefPtr<Modifier>** ioModifierLink)
{
parser->ReadToken(TokenType::LBracket);
+
+ const bool hasDoubleBracket = AdvanceIf(parser, TokenType::LBracket);
+
for(;;)
{
// Note: When parsing we just construct an AST node for an
@@ -613,7 +708,8 @@ namespace Slang
// seems better to not complicate the parsing process any more.
//
- auto nameToken = parser->ReadToken(TokenType::Identifier);
+ Token nameToken = parseAttributeName(parser);
+
RefPtr<UncheckedAttribute> modifier = new UncheckedAttribute();
modifier->name = nameToken.getName();
modifier->loc = nameToken.getLoc();
@@ -645,6 +741,12 @@ namespace Slang
parser->ReadToken(TokenType::Comma);
}
+
+ if (hasDoubleBracket)
+ {
+ // Read the second ]
+ parser->ReadToken(TokenType::RBracket);
+ }
}
static TokenType peekTokenType(Parser* parser)
@@ -4368,60 +4470,86 @@ namespace Slang
return modifier;
}
+
+
static RefPtr<RefObject> parseLayoutModifier(Parser* parser, void* /*userData*/)
{
- Modifiers modifiers;
- RefPtr<Modifier>* modifierLink = &modifiers.first;
-
- auto beginMarker = new GLSLLayoutModifierGroupBegin();
- AddModifier(&modifierLink, beginMarker);
+ ModifierListBuilder listBuilder;
+ listBuilder.add(new GLSLLayoutModifierGroupBegin());
+
parser->ReadToken(TokenType::LParent);
while (!AdvanceIfMatch(parser, TokenType::RParent))
{
auto nameAndLoc = expectIdentifier(parser);
+ const String& nameText = nameAndLoc.name->text;
- RefPtr<GLSLLayoutModifier> modifier;
+ if (nameText == "binding" ||
+ nameText == "set")
+ {
+ GLSLBindingAttribute* attr = listBuilder.find<GLSLBindingAttribute>();
+ if (!attr)
+ {
+ attr = new GLSLBindingAttribute();
+ listBuilder.add(attr);
+ }
- // TODO: better handling of this choise (e.g., lookup in scope)
- if(0) {}
- #define CASE(KEYWORD, CLASS) \
- else if(getText(nameAndLoc.name) == #KEYWORD) modifier = new CLASS()
+ parser->ReadToken(TokenType::OpAssign);
- CASE(constant_id, GLSLConstantIDLayoutModifier);
- CASE(binding, GLSLBindingLayoutModifier);
- CASE(set, GLSLSetLayoutModifier);
- CASE(location, GLSLLocationLayoutModifier);
- CASE(push_constant, GLSLPushConstantLayoutModifier);
- CASE(local_size_x, GLSLLocalSizeXLayoutModifier);
- CASE(local_size_y, GLSLLocalSizeYLayoutModifier);
- CASE(local_size_z, GLSLLocalSizeZLayoutModifier);
+ Token valToken = parser->ReadToken(TokenType::IntegerLiteral);
+ // Work out the value
+ auto value = getIntegerLiteralValue(valToken);
- #undef CASE
+ if (nameText == "binding")
+ {
+ attr->binding = int32_t(value);
+ }
+ else
+ {
+ attr->set = int32_t(value);
+ }
+ }
else
{
- modifier = new GLSLUnparsedLayoutModifier();
- }
+ RefPtr<GLSLLayoutModifier> modifier;
- modifier->name = nameAndLoc.name;
- modifier->loc = nameAndLoc.loc;
+ // TODO: better handling of this choice (e.g., lookup in scope)
+ if(0) {}
+ #define CASE(KEYWORD, CLASS) \
+ else if(getText(nameAndLoc.name) == #KEYWORD) modifier = new CLASS()
- if(AdvanceIf(parser, TokenType::OpAssign))
- {
- modifier->valToken = parser->ReadToken(TokenType::IntegerLiteral);
- }
+ CASE(constant_id, GLSLConstantIDLayoutModifier);
+ CASE(location, GLSLLocationLayoutModifier);
+ CASE(push_constant, GLSLPushConstantLayoutModifier);
+ CASE(local_size_x, GLSLLocalSizeXLayoutModifier);
+ CASE(local_size_y, GLSLLocalSizeYLayoutModifier);
+ CASE(local_size_z, GLSLLocalSizeZLayoutModifier);
- AddModifier(&modifierLink, modifier);
+ #undef CASE
+ else
+ {
+ modifier = new GLSLUnparsedLayoutModifier();
+ }
+
+ modifier->name = nameAndLoc.name;
+ modifier->loc = nameAndLoc.loc;
+
+ if(AdvanceIf(parser, TokenType::OpAssign))
+ {
+ modifier->valToken = parser->ReadToken(TokenType::IntegerLiteral);
+ }
+
+ listBuilder.add(modifier);
+ }
if (AdvanceIf(parser, TokenType::RParent))
break;
parser->ReadToken(TokenType::Comma);
}
- auto endMarker = new GLSLLayoutModifierGroupEnd();
- AddModifier(&modifierLink, endMarker);
+ listBuilder.add(new GLSLLayoutModifierGroupEnd());
- return modifiers.first;
+ return listBuilder.getFirst();
}
static RefPtr<RefObject> parseBuiltinTypeModifier(Parser* parser, void* /*userData*/)