diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2018-07-31 11:03:53 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-07-31 11:03:53 -0400 |
| commit | 9914ca800c92e9b3fe768dec4e913a302f3d678d (patch) | |
| tree | 49544fb2c0387f39876fd99e112cfc32ed05302d /source/slang/parser.cpp | |
| parent | 171f524d7ca2922084a33f50c77a1e8797e80949 (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.cpp | 194 |
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*/) |
