summaryrefslogtreecommitdiffstats
path: root/source/slang/parser.cpp
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2017-11-07 19:09:40 -0500
committerTim Foley <tfoleyNV@users.noreply.github.com>2017-11-07 16:09:40 -0800
commit6e591ada0eb652c320bba4bd8a46cd579946df01 (patch)
tree768229fb26204b6b0a89201d9b14c32e9203c098 /source/slang/parser.cpp
parent939688e963fde7a0485f210ef2674c27692021a4 (diff)
Support generic interface methods (#251)
* improve diagnostic messages and prevent fatal errors from crashing the compiler. * fix top level exception catching. * spelling fix * change wording of invalidSwizzleExpr diagnostic * add speculative GenericsApp expr parsing * add new test case of cascading generics call. * Fixing bugs in compiling cascaded generic function calls. Add implementation of DeclaredSubTypeWitness::SubstituteImpl() This is not needed by the type checker, but needed by IR specialization. When input source contains cascading generic function call, the arguments to `specialize` instruction is currently represented as a substitution. The arg values of this subsittution can be a `DeclaredSubTypeWitness` when a generic function uses one of its generic parameter to specialize another generic function. When the top level generics function is being specialized, this substitution argument, which is a `DeclaredSubTypeWitness`, needs to be substituted with the witness that used to specialize the top level function in the specialized specialize instruction as well. * add a test case for cascading generic function call. * parser bug fix * fixes #255 * add test case for issue #255 * Generate missing `specialize` instruction when calling a generic method from an interface constraint. When calling a generic method via an interface, we should be generating the following ir: ... f = lookup_interface_method(...) f_s = specailize(f, declRef) ... This commit fixes this `emitFuncRef` function to emit the needed `specialize` instruction. * fixes #260 This fix follows the second apporach in the disucssion. It generated mangled name for specialized functions by appending new substitution type names to the original mangled name. * Disabling removing and re-inserting specailized functions in getSpecalizeFunc() I am not sure why it is needed, it seems HLSL and GLSL backends are generating forward declarations anyways, so the order of functions in IRModule shouldn't matter. * cleanup and complete test cases. * fix warnings
Diffstat (limited to 'source/slang/parser.cpp')
-rw-r--r--source/slang/parser.cpp104
1 files changed, 71 insertions, 33 deletions
diff --git a/source/slang/parser.cpp b/source/slang/parser.cpp
index 595d58d7e..eb02d98c5 100644
--- a/source/slang/parser.cpp
+++ b/source/slang/parser.cpp
@@ -77,7 +77,7 @@ namespace Slang
, sink(sink)
, outerScope(outerScope)
{}
-
+ Parser(const Parser & other) = default;
Session* getSession()
{
return translationUnit->compileRequest->mSession;
@@ -1396,6 +1396,69 @@ namespace Slang
return genericApp;
}
+ static bool isGenericName(Parser* parser, Name* name)
+ {
+ auto lookupResult = lookUp(
+ parser->getSession(),
+ nullptr, // no semantics visitor available yet
+ name,
+ parser->currentScope);
+ if (!lookupResult.isValid() || lookupResult.isOverloaded())
+ return false;
+
+ auto decl = lookupResult.item.declRef.getDecl();
+ if (auto genericDecl = dynamic_cast<GenericDecl*>(decl))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ static RefPtr<Expr> tryParseGenericApp(
+ Parser* parser,
+ RefPtr<Expr> base)
+ {
+ Name * baseName = nullptr;
+ if (auto varExpr = base->As<VarExpr>())
+ baseName = varExpr->name;
+ // if base is a known generics, parse as generics
+ if (baseName && isGenericName(parser, baseName))
+ return parseGenericApp(parser, base);
+
+ // otherwise, we speculate as generics, and fallback to comparison when parsing failed
+ TokenSpan tokenSpan;
+ tokenSpan.mBegin = parser->tokenReader.mCursor;
+ tokenSpan.mEnd = parser->tokenReader.mEnd;
+ DiagnosticSink newSink;
+ newSink.sourceManager = parser->sink->sourceManager;
+ Parser newParser(*parser);
+ newParser.sink = &newSink;
+ auto speculateParseRs = parseGenericApp(&newParser, base);
+ if (newSink.errorCount == 0)
+ {
+ // disambiguate based on FOLLOW set
+ switch (peekTokenType(&newParser))
+ {
+ case TokenType::Dot:
+ case TokenType::LParent:
+ case TokenType::RParent:
+ case TokenType::RBracket:
+ case TokenType::Colon:
+ case TokenType::Comma:
+ case TokenType::QuestionMark:
+ case TokenType::Semicolon:
+ case TokenType::OpEql:
+ case TokenType::OpNeq:
+ {
+ return parseGenericApp(parser, base);
+ }
+ }
+ }
+ return base;
+ }
static RefPtr<Expr> parseMemberType(Parser * parser, RefPtr<Expr> base)
{
RefPtr<MemberExpr> memberExpr = new MemberExpr();
@@ -2624,28 +2687,6 @@ namespace Slang
return stmt;
}
- static bool isGenericName(Parser* parser, Name* name)
- {
- auto lookupResult = lookUp(
- parser->getSession(),
- nullptr, // no semantics visitor available yet
- name,
- parser->currentScope);
- if(!lookupResult.isValid() || lookupResult.isOverloaded())
- return false;
-
- auto decl = lookupResult.item.declRef.getDecl();
- if( auto genericDecl = dynamic_cast<GenericDecl*>(decl) )
- {
- return true;
- }
- else
- {
- return false;
- }
- }
-
-
static bool isTypeName(Parser* parser, Name* name)
{
auto lookupResult = lookUp(
@@ -3367,24 +3408,18 @@ namespace Slang
}
#endif
}
-
+
// We *might* be looking at an application of a generic to arguments,
// but we need to disambiguate to make sure.
static RefPtr<Expr> maybeParseGenericApp(
Parser* parser,
// TODO: need to support more general expressions here
- RefPtr<VarExpr> base)
+ RefPtr<Expr> base)
{
if(peekTokenType(parser) != TokenType::OpLess)
return base;
-
- if(!isGenericName(parser, base->name))
- return base;
-
- // Okay, seems likely that we are looking at a generic app
-
- return parseGenericApp(parser, base);
+ return tryParseGenericApp(parser, base);
}
static RefPtr<Expr> parsePrefixExpr(Parser* parser);
@@ -3769,7 +3804,10 @@ namespace Slang
parser->ReadToken(TokenType::Dot);
memberExpr->name = expectIdentifier(parser).name;
- expr = memberExpr;
+ if (peekTokenType(parser) == TokenType::OpLess)
+ expr = maybeParseGenericApp(parser, memberExpr);
+ else
+ expr = memberExpr;
}
break;
}