summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
authorTim Foley <tfoley@nvidia.com>2017-06-21 10:43:25 -0700
committerTim Foley <tfoley@nvidia.com>2017-06-21 11:59:51 -0700
commit7f7864e80e8b5631ba5ec1aa9657fdaf1b4adb06 (patch)
treea9d0bc921e9ead73e5ec9491c4f3925c041cdbf5 /source
parent5148c594c19da9466b151ab3b6b11441f265823e (diff)
Support texture `Gather*()` operations
The catch with these operations is that they return a vector based on the scalar of the element type of the texture. That is, given `Texture2D<float> t` the operation `t.GatherRed(...)` should return a `float4`. The ideal way to solve this would use associated types, but we aren't there yet, so I am using extension declarations. An extension can "capture" the identity of the element type, like so: __generic<T, let N : int> __extension Texture2D<vector<T,N> > { ... } That extension will match `Texture2D<float3>` and correctly capture `T == float`, so that we can use it in other operations. Getting this working required a bunch of changes: - Actually emit the relevant extension declarations in the stdlib - Fix the parser to be able to parse `Texture2D<vector<T,N> >` (that is, a nested generic app). - I actually went ahead and significantly overhauled the expression parser while I was there, because I just couldn't deal with the existing code any longer. - Added support for general-case lookup to look through `__extension` declarations. I had logic in place to special-case this for looking up "constructors" but hadn't done anything for general member lookup yet. - This required some annoying holes to be punched through the layers, because lookup might need to invoke semantic analysis to ensure that an extension has been checked. - There is some first-pass code trying to support looking up a `typedef` nested inside the `vector` type. This is a nice idea in principle, but the problem is that the `Texture2D<T>` definition would be looking up `T.Element` and not `float4.Element`, and that means we'd need machinery for doing lookup *through* interface conformances for a type parameter like `T` The big gotcha here is that none of this logic applies to `Texture2D<float>` (the original case I mentioned) because I am matching vector types and not scalars. Matching scalars *should* be as easy as: __generic<T : __BuitlinScalarType> __extension Texture2D<T> { ... } But I'd need to confirm that interface constraints like that actually work, or else that extension would *also* apply to `Texture2D<float4>` and break everything.
Diffstat (limited to 'source')
-rw-r--r--source/slang/check.cpp132
-rw-r--r--source/slang/lookup.cpp70
-rw-r--r--source/slang/lookup.h12
-rw-r--r--source/slang/parser.cpp415
-rw-r--r--source/slang/slang-stdlib.cpp101
-rw-r--r--source/slang/syntax.h12
6 files changed, 616 insertions, 126 deletions
diff --git a/source/slang/check.cpp b/source/slang/check.cpp
index 5a82380d3..463052bc8 100644
--- a/source/slang/check.cpp
+++ b/source/slang/check.cpp
@@ -2269,7 +2269,7 @@ namespace Slang
// Note(tfoley): The name used for lookup here is a bit magical, since
// it must match what the parser installed in subscript declarations.
- LookupResult lookupResult = LookUpLocal("operator[]", aggTypeDeclRef);
+ LookupResult lookupResult = LookUpLocal(this, "operator[]", aggTypeDeclRef);
if (!lookupResult.isValid())
{
goto fail;
@@ -4552,7 +4552,7 @@ namespace Slang
expr->Type = ExpressionType::Error;
- auto lookupResult = LookUp(expr->name, expr->scope);
+ auto lookupResult = LookUp(this, expr->name, expr->scope);
if (lookupResult.isValid())
{
return createLookupResultExpr(
@@ -4795,6 +4795,38 @@ namespace Slang
baseScalarType,
1);
}
+ else if(auto typeType = baseType->As<TypeType>())
+ {
+ // We are looking up a member inside a type.
+ // We want to be careful here because we should only find members
+ // that are implicitly or explicitly `static`.
+ //
+ // TODO: this duplicates a *lot* of logic with the case below.
+ // We need to fix that.
+ auto type = typeType->type;
+ if(auto declRefType = type->AsDeclRefType())
+ {
+ if (auto aggTypeDeclRef = declRefType->declRef.As<AggTypeDecl>())
+ {
+ // Checking of the type must be complete before we can reference its members safely
+ EnsureDecl(aggTypeDeclRef.getDecl(), DeclCheckState::Checked);
+
+ LookupResult lookupResult = LookUpLocal(this, expr->name, aggTypeDeclRef);
+ if (!lookupResult.isValid())
+ {
+ goto fail;
+ }
+
+ // TODO: need to filter for declarations that are valid to refer
+ // to in this context...
+
+ return createLookupResultExpr(
+ lookupResult,
+ expr->BaseExpression,
+ expr);
+ }
+ }
+ }
else if (auto declRefType = baseType->AsDeclRefType())
{
if (auto aggTypeDeclRef = declRefType->declRef.As<AggTypeDecl>())
@@ -4802,8 +4834,7 @@ namespace Slang
// Checking of the type must be complete before we can reference its members safely
EnsureDecl(aggTypeDeclRef.getDecl(), DeclCheckState::Checked);
-
- LookupResult lookupResult = LookUpLocal(expr->name, aggTypeDeclRef);
+ LookupResult lookupResult = LookUpLocal(this, expr->name, aggTypeDeclRef);
if (!lookupResult.isValid())
{
goto fail;
@@ -4813,88 +4844,6 @@ namespace Slang
lookupResult,
expr->BaseExpression,
expr);
-#if 0
- DeclRef<Decl> memberDeclRef(lookupResult.decl, aggTypeDeclRef.substitutions);
- return ConstructDeclRefExpr(memberDeclRef, expr->BaseExpression, expr);
-#endif
-
-#if 0
-
-
- // TODO(tfoley): It is unfortunate that the lookup strategy
- // here isn't unified with the ordinary `Scope` case.
- // In particular, if we add support for "transparent" declarations,
- // etc. here then we would need to add them in ordinary lookup
- // as well.
-
- Decl* memberDecl = nullptr; // The first declaration we found, if any
- Decl* secondDecl = nullptr; // Another declaration with the same name, if any
- for (auto m : aggTypeDeclRef.GetMembers())
- {
- if (m.GetName() != expr->MemberName)
- continue;
-
- if (!memberDecl)
- {
- memberDecl = m.getDecl();
- }
- else
- {
- secondDecl = m.getDecl();
- break;
- }
- }
-
- // If we didn't find any member, then we signal an error
- if (!memberDecl)
- {
- expr->Type = ExpressionType::Error;
- getSink()->diagnose(expr, Diagnostics::noMemberOfNameInType, expr->MemberName, baseType);
- return expr;
- }
-
- // If we found only a single member, then we are fine
- if (!secondDecl)
- {
- // TODO: need to
- DeclRef<Decl> memberDeclRef(memberDecl, aggTypeDeclRef.substitutions);
-
- expr->declRef = memberDeclRef;
- expr->Type = GetTypeForDeclRef(memberDeclRef);
-
- // When referencing a member variable, the result is an l-value
- // if and only if the base expression was.
- if (auto memberVarDecl = dynamic_cast<VarDeclBase*>(memberDecl))
- {
- expr->Type.IsLeftValue = expr->BaseExpression->Type.IsLeftValue;
- }
- return expr;
- }
-
- // We found multiple members with the same name, and need
- // to resolve the embiguity at some point...
- expr->Type = ExpressionType::Error;
- getSink()->diagnose(expr, Diagnostics::unimplemented, "ambiguous member reference");
- return expr;
-
-#endif
-
-#if 0
-
- StructField* field = structDecl->FindField(expr->MemberName);
- if (!field)
- {
- expr->Type = ExpressionType::Error;
- getSink()->diagnose(expr, Diagnostics::noMemberOfNameInType, expr->MemberName, baseType);
- }
- else
- expr->Type = field->Type;
-
- // A reference to a struct member is an l-value if the reference to the struct
- // value was also an l-value.
- expr->Type.IsLeftValue = expr->BaseExpression->Type.IsLeftValue;
- return expr;
-#endif
}
// catch-all
@@ -5048,4 +4997,15 @@ namespace Slang
return getTypeForDeclRef(nullptr, nullptr, declRef, &typeResult);
}
+ DeclRef<ExtensionDecl> ApplyExtensionToType(
+ SemanticsVisitor* semantics,
+ ExtensionDecl* extDecl,
+ RefPtr<ExpressionType> type)
+ {
+ if(!semantics)
+ return DeclRef<ExtensionDecl>();
+
+ return semantics->ApplyExtensionToType(extDecl, type);
+ }
+
}
diff --git a/source/slang/lookup.cpp b/source/slang/lookup.cpp
index e9c2177de..f5e472ec5 100644
--- a/source/slang/lookup.cpp
+++ b/source/slang/lookup.cpp
@@ -5,6 +5,14 @@ namespace Slang {
//
+DeclRef<ExtensionDecl> ApplyExtensionToType(
+ SemanticsVisitor* semantics,
+ ExtensionDecl* extDecl,
+ RefPtr<ExpressionType> type);
+
+//
+
+
// Helper for constructing breadcrumb trails during lookup, without unnecessary heap allocaiton
struct BreadcrumbInfo
{
@@ -190,7 +198,7 @@ void DoMemberLookupImpl(
// Look for members of the given name in the given container for declarations
void DoLocalLookupImpl(
String const& name,
- DeclRef<ContainerDecl> containerDeclRef,
+ DeclRef<ContainerDecl> containerDeclRef,
LookupRequest const& request,
LookupResult& result,
BreadcrumbInfo* inBreadcrumbs)
@@ -241,7 +249,24 @@ void DoLocalLookupImpl(
DoMemberLookupImpl(name, transparentMemberDeclRef, request, result, &memberRefBreadcrumb);
}
- // TODO(tfoley): need to consider lookup via extension here?
+ // Consider lookup via extension
+ if( auto aggTypeDeclRef = containerDeclRef.As<AggTypeDecl>() )
+ {
+ RefPtr<ExpressionType> type = DeclRefType::Create(aggTypeDeclRef);
+
+ for (auto ext = GetCandidateExtensions(aggTypeDeclRef); ext; ext = ext->nextCandidateExtension)
+ {
+ auto extDeclRef = ApplyExtensionToType(request.semantics, ext, type);
+ if (!extDeclRef)
+ continue;
+
+ // TODO: eventually we need to insert a breadcrumb here so that
+ // the constructed result can somehow indicate that a member
+ // was found through an extension.
+
+ DoLocalLookupImpl(name, extDeclRef, request, result, inBreadcrumbs);
+ }
+ }
}
void DoLookupImpl(
@@ -258,10 +283,34 @@ void DoLookupImpl(
// also finding a hit in another
for(auto link = scope; link; link = link->nextSibling)
{
- if(!link->containerDecl)
+ auto containerDecl = link->containerDecl;
+
+ if(!containerDecl)
continue;
- DeclRef<ContainerDecl> containerRef = DeclRef<Decl>(link->containerDecl, nullptr).As<ContainerDecl>();
+ // If the container is a generic, then we need to instantiate it
+ // at the parameters themselves, so provide a fully-resolved
+ // declaration reference for lookup.
+ RefPtr<Substitutions> subst = nullptr;
+ if(auto parentGenericDecl = dynamic_cast<GenericDecl*>(containerDecl->ParentDecl))
+ {
+ subst = new Substitutions();
+ subst->genericDecl = parentGenericDecl;
+
+ for( auto pp : parentGenericDecl->Members )
+ {
+ if( auto genericTypeParam = pp.As<GenericTypeParamDecl>() )
+ {
+ subst->args.Add(DeclRefType::Create(DeclRef<GenericTypeParamDecl>(genericTypeParam.Ptr(), nullptr)));
+ }
+ else if( auto genericValParam = pp.As<GenericValueParamDecl>() )
+ {
+ subst->args.Add(new GenericParamIntVal(DeclRef<GenericValueParamDecl>(genericValParam.Ptr(), nullptr)));
+ }
+ }
+ }
+
+ DeclRef<ContainerDecl> containerRef = DeclRef<Decl>(containerDecl, subst).As<ContainerDecl>();
DoLocalLookupImpl(name, containerRef, request, result, nullptr);
}
@@ -283,18 +332,27 @@ LookupResult DoLookup(String const& name, LookupRequest const& request)
return result;
}
-LookupResult LookUp(String const& name, RefPtr<Scope> scope)
+LookupResult LookUp(
+ SemanticsVisitor* semantics,
+ String const& name,
+ RefPtr<Scope> scope)
{
LookupRequest request;
+ request.semantics = semantics;
request.scope = scope;
return DoLookup(name, request);
}
// perform lookup within the context of a particular container declaration,
// and do *not* look further up the chain
-LookupResult LookUpLocal(String const& name, DeclRef<ContainerDecl> containerDeclRef)
+LookupResult LookUpLocal(
+ SemanticsVisitor* semantics,
+ String const& name,
+ DeclRef<ContainerDecl> containerDeclRef)
{
LookupRequest request;
+ request.semantics = semantics;
+
LookupResult result;
DoLocalLookupImpl(name, containerDeclRef, request, result, nullptr);
return result;
diff --git a/source/slang/lookup.h b/source/slang/lookup.h
index eb1888878..52eaa9804 100644
--- a/source/slang/lookup.h
+++ b/source/slang/lookup.h
@@ -5,6 +5,8 @@
namespace Slang {
+class SemanticsVisitor;
+
// Take an existing lookup result and refine it to only include
// results that pass the given `LookupMask`.
LookupResult refineLookup(LookupResult const& inResult, LookupMask mask);
@@ -15,11 +17,17 @@ void buildMemberDictionary(ContainerDecl* decl);
// Look up a name in the given scope, proceeding up through
// parent scopes as needed.
-LookupResult LookUp(String const& name, RefPtr<Scope> scope);
+LookupResult LookUp(
+ SemanticsVisitor* semantics,
+ String const& name,
+ RefPtr<Scope> scope);
// perform lookup within the context of a particular container declaration,
// and do *not* look further up the chain
-LookupResult LookUpLocal(String const& name, DeclRef<ContainerDecl> containerDeclRef);
+LookupResult LookUpLocal(
+ SemanticsVisitor* semantics,
+ String const& name,
+ DeclRef<ContainerDecl> containerDeclRef);
// TODO: this belongs somewhere else
diff --git a/source/slang/parser.cpp b/source/slang/parser.cpp
index 48954dc04..0598e67a7 100644
--- a/source/slang/parser.cpp
+++ b/source/slang/parser.cpp
@@ -750,6 +750,7 @@ namespace Slang
if( parser->LookAheadToken(TokenType::Identifier) )
{
LookupResult lookupResult = LookUp(
+ nullptr, // No semantics visitor available yet!
parser->tokenReader.PeekToken().Content,
parser->currentScope);
@@ -1331,6 +1332,32 @@ namespace Slang
RefPtr<ExpressionSyntaxNode> expr;
};
+ static RefPtr<ExpressionSyntaxNode> parseGenericApp(
+ Parser* parser,
+ RefPtr<ExpressionSyntaxNode> base)
+ {
+ RefPtr<GenericAppExpr> genericApp = new GenericAppExpr();
+
+ parser->FillPosition(genericApp.Ptr()); // set up scope for lookup
+ genericApp->FunctionExpr = base;
+ parser->ReadToken(TokenType::OpLess);
+ parser->genericDepth++;
+ // For now assume all generics have at least one argument
+ genericApp->Arguments.Add(ParseGenericArg(parser));
+ while (AdvanceIf(parser, TokenType::Comma))
+ {
+ genericApp->Arguments.Add(ParseGenericArg(parser));
+ }
+ parser->genericDepth--;
+
+ // TODO: probably want to suppot `>>` and `>=` here as well,
+ // and split up those tokens as needed.
+ //
+ parser->ReadToken(TokenType::OpGreater);
+
+ return genericApp;
+ }
+
static TypeSpec
parseTypeSpec(Parser* parser)
{
@@ -1367,21 +1394,7 @@ namespace Slang
if (parser->LookAheadToken(TokenType::OpLess))
{
- RefPtr<GenericAppExpr> gtype = new GenericAppExpr();
- parser->FillPosition(gtype.Ptr()); // set up scope for lookup
- gtype->Position = typeName.Position;
- gtype->FunctionExpr = typeExpr;
- parser->ReadToken(TokenType::OpLess);
- parser->genericDepth++;
- // For now assume all generics have at least one argument
- gtype->Arguments.Add(ParseGenericArg(parser));
- while (AdvanceIf(parser, TokenType::Comma))
- {
- gtype->Arguments.Add(ParseGenericArg(parser));
- }
- parser->genericDepth--;
- parser->ReadToken(TokenType::OpGreater);
- typeExpr = gtype;
+ typeExpr = parseGenericApp(parser, typeExpr);
}
typeSpec.expr = typeExpr;
@@ -1959,10 +1972,10 @@ namespace Slang
{
AddMember(decl, ParseGenericParamDecl(parser, decl));
-if( parser->LookAheadToken(TokenType::OpGreater) )
-break;
+ if( parser->LookAheadToken(TokenType::OpGreater) )
+ break;
-parser->ReadToken(TokenType::Comma);
+ parser->ReadToken(TokenType::Comma);
}
parser->genericDepth--;
parser->ReadToken(TokenType::OpGreater);
@@ -2370,14 +2383,33 @@ parser->ReadToken(TokenType::Comma);
return stmt;
}
- static bool peekTypeName(Parser* parser)
+ static bool isGenericName(Parser* parser, String const& name)
{
- if(!parser->LookAheadToken(TokenType::Identifier))
+ auto lookupResult = LookUp(
+ nullptr, // no semantics visitor available yet
+ name,
+ parser->currentScope);
+ if(!lookupResult.isValid() || lookupResult.isOverloaded())
return false;
- auto name = parser->tokenReader.PeekToken().Content;
+ auto decl = lookupResult.item.declRef.getDecl();
+ if( auto genericDecl = dynamic_cast<GenericDecl*>(decl) )
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
- auto lookupResult = LookUp(name, parser->currentScope);
+ static bool isTypeName(Parser* parser, String const& name)
+ {
+ auto lookupResult = LookUp(
+ nullptr, // no semantics visitor available yet
+ name,
+ parser->currentScope);
if(!lookupResult.isValid() || lookupResult.isOverloaded())
return false;
@@ -2396,6 +2428,15 @@ parser->ReadToken(TokenType::Comma);
}
}
+ static bool peekTypeName(Parser* parser)
+ {
+ if(!parser->LookAheadToken(TokenType::Identifier))
+ return false;
+
+ auto name = parser->tokenReader.PeekToken().Content;
+ return isTypeName(parser, name);
+ }
+
RefPtr<StatementSyntaxNode> Parser::ParseStatement()
{
auto modifiers = ParseModifiers(this);
@@ -2766,6 +2807,8 @@ parser->ReadToken(TokenType::Comma);
{
switch(type)
{
+ case TokenType::QuestionMark:
+ return Precedence::TernaryConditional;
case TokenType::Comma:
return Precedence::Comma;
case TokenType::OpAssign:
@@ -2918,8 +2961,79 @@ parser->ReadToken(TokenType::Comma);
}
+ static RefPtr<ExpressionSyntaxNode> createInfixExpr(
+ Parser* /*parser*/,
+ RefPtr<ExpressionSyntaxNode> left,
+ RefPtr<ExpressionSyntaxNode> op,
+ RefPtr<ExpressionSyntaxNode> right)
+ {
+ RefPtr<InfixExpr> expr = new InfixExpr();
+ expr->Position = op->Position;
+ expr->FunctionExpr = op;
+ expr->Arguments.Add(left);
+ expr->Arguments.Add(right);
+ return expr;
+ }
+
+ static RefPtr<ExpressionSyntaxNode> parseInfixExprWithPrecedence(
+ Parser* parser,
+ RefPtr<ExpressionSyntaxNode> inExpr,
+ Precedence prec)
+ {
+ auto expr = inExpr;
+ for(;;)
+ {
+ auto opTokenType = parser->tokenReader.PeekTokenType();
+ auto opPrec = GetOpLevel(parser, opTokenType);
+ if(opPrec < prec)
+ break;
+
+ auto op = parseOperator(parser);
+
+ // Special case the `?:` operator since it is the
+ // one non-binary case we need to deal with.
+ if(opTokenType == TokenType::QuestionMark)
+ {
+ RefPtr<SelectExpressionSyntaxNode> select = new SelectExpressionSyntaxNode();
+ select->Position = op->Position;
+ select->FunctionExpr = op;
+
+ select->Arguments.Add(expr);
+
+ select->Arguments.Add(parser->ParseExpression(opPrec));
+ parser->ReadToken(TokenType::Colon);
+ select->Arguments.Add(parser->ParseExpression(opPrec));
+
+ expr = select;
+ continue;
+ }
+
+ auto right = parser->ParseLeafExpression();
+
+ for(;;)
+ {
+ auto nextOpPrec = GetOpLevel(parser, parser->tokenReader.PeekTokenType());
+
+ if((GetAssociativityFromLevel(nextOpPrec) == Associativity::Right) && (nextOpPrec != opPrec))
+ break;
+ else if( nextOpPrec <= opPrec)
+ break;
+
+ right = parseInfixExprWithPrecedence(parser, right, nextOpPrec);
+ }
+
+ expr = createInfixExpr(parser, expr, op, right);
+ }
+ return expr;
+ }
+
RefPtr<ExpressionSyntaxNode> Parser::ParseExpression(Precedence level)
{
+ auto expr = ParseLeafExpression();
+ return parseInfixExprWithPrecedence(this, expr, level);
+
+#if 0
+
if (level == Precedence::Prefix)
return ParseLeafExpression();
if (level == Precedence::TernaryConditional)
@@ -2975,10 +3089,266 @@ parser->ReadToken(TokenType::Comma);
return left;
}
}
+#endif
+ }
+
+ static TokenType peekTokenType(Parser* parser)
+ {
+ return parser->tokenReader.PeekTokenType();
+ }
+
+ // We *might* be looking at an application of a generic to arguments,
+ // but we need to disambiguate to make sure.
+ static RefPtr<ExpressionSyntaxNode> maybeParseGenericApp(
+ Parser* parser,
+
+ // TODO: need to support more general expressions here
+ RefPtr<VarExpressionSyntaxNode> 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);
+ }
+
+ static RefPtr<ExpressionSyntaxNode> parseAtomicExpr(Parser* parser)
+ {
+ switch( peekTokenType(parser) )
+ {
+ default:
+ // TODO: should this return an error expression instead of NULL?
+ parser->sink->diagnose(parser->tokenReader.PeekLoc(), Diagnostics::syntaxError);
+ return nullptr;
+
+ // Either:
+ // - parenthized expression `(exp)`
+ // - cast `(type) exp`
+ //
+ // Proper disambiguation requires mixing up parsing
+ // and semantic checking (which we should do eventually)
+ // but for now we will follow some hueristics.
+ case TokenType::LParent:
+ {
+ parser->ReadToken(TokenType::LParent);
+
+ RefPtr<ExpressionSyntaxNode> expr;
+ if (peekTypeName(parser) && parser->LookAheadToken(TokenType::RParent, 1))
+ {
+ RefPtr<TypeCastExpressionSyntaxNode> tcexpr = new TypeCastExpressionSyntaxNode();
+ parser->FillPosition(tcexpr.Ptr());
+ tcexpr->TargetType = parser->ParseTypeExp();
+ parser->ReadToken(TokenType::RParent);
+ tcexpr->Expression = parser->ParseExpression(Precedence::Multiplicative); // Note(tfoley): need to double-check this
+ expr = tcexpr;
+ }
+ else
+ {
+ expr = parser->ParseExpression();
+ parser->ReadToken(TokenType::RParent);
+ }
+
+ return expr;
+ }
+
+ // An initializer list `{ expr, ... }`
+ case TokenType::LBrace:
+ {
+ RefPtr<InitializerListExpr> initExpr = new InitializerListExpr();
+ parser->FillPosition(initExpr.Ptr());
+
+ // Initializer list
+ parser->ReadToken(TokenType::LBrace);
+
+ List<RefPtr<ExpressionSyntaxNode>> exprs;
+
+ for(;;)
+ {
+ if(AdvanceIfMatch(parser, TokenType::RBrace))
+ break;
+
+ auto expr = parser->ParseArgExpr();
+ if( expr )
+ {
+ initExpr->args.Add(expr);
+ }
+
+ if(AdvanceIfMatch(parser, TokenType::RBrace))
+ break;
+
+ parser->ReadToken(TokenType::Comma);
+ }
+
+ return initExpr;
+ }
+
+ case TokenType::IntLiterial:
+ case TokenType::DoubleLiterial:
+ {
+ RefPtr<ConstantExpressionSyntaxNode> constExpr = new ConstantExpressionSyntaxNode();
+ auto token = parser->tokenReader.AdvanceToken();
+ parser->FillPosition(constExpr.Ptr());
+ if (token.Type == TokenType::IntLiterial)
+ {
+ constExpr->ConstType = ConstantExpressionSyntaxNode::ConstantType::Int;
+ constExpr->IntValue = StringToInt(token.Content);
+ }
+ else if (token.Type == TokenType::DoubleLiterial)
+ {
+ constExpr->ConstType = ConstantExpressionSyntaxNode::ConstantType::Float;
+ constExpr->FloatValue = (FloatingPointLiteralValue) StringToDouble(token.Content);
+ }
+
+ return constExpr;
+ }
+
+ case TokenType::Identifier:
+ {
+ // TODO(tfoley): Need a name-lookup step here to resolve
+ // syntactic keywords in expression context.
+
+ if (parser->LookAheadToken("true") || parser->LookAheadToken("false"))
+ {
+ RefPtr<ConstantExpressionSyntaxNode> constExpr = new ConstantExpressionSyntaxNode();
+ auto token = parser->tokenReader.AdvanceToken();
+ parser->FillPosition(constExpr.Ptr());
+ constExpr->ConstType = ConstantExpressionSyntaxNode::ConstantType::Bool;
+ constExpr->IntValue = token.Content == "true" ? 1 : 0;
+
+ return constExpr;
+ }
+
+ // Default behavior is just to create a name expression
+ RefPtr<VarExpressionSyntaxNode> varExpr = new VarExpressionSyntaxNode();
+ varExpr->scope = parser->currentScope.Ptr();
+ parser->FillPosition(varExpr.Ptr());
+ auto token = parser->ReadToken(TokenType::Identifier);
+ varExpr->name = token.Content;
+
+ if(peekTokenType(parser) == TokenType::OpLess)
+ {
+ return maybeParseGenericApp(parser, varExpr);
+ }
+
+ return varExpr;
+ }
+ }
+ }
+
+ static RefPtr<ExpressionSyntaxNode> parsePostfixExpr(Parser* parser)
+ {
+ auto expr = parseAtomicExpr(parser);
+ for(;;)
+ {
+ switch( peekTokenType(parser) )
+ {
+ default:
+ return expr;
+
+ // Postfix increment/decrement
+ case TokenType::OpInc:
+ case TokenType::OpDec:
+ {
+ RefPtr<OperatorExpressionSyntaxNode> postfixExpr = new PostfixExpr();
+ parser->FillPosition(postfixExpr.Ptr());
+ postfixExpr->FunctionExpr = parseOperator(parser);
+ postfixExpr->Arguments.Add(expr);
+
+ expr = postfixExpr;
+ }
+ break;
+
+ // Subscript operation `a[i]`
+ case TokenType::LBracket:
+ {
+ RefPtr<IndexExpressionSyntaxNode> indexExpr = new IndexExpressionSyntaxNode();
+ indexExpr->BaseExpression = expr;
+ parser->FillPosition(indexExpr.Ptr());
+ parser->ReadToken(TokenType::LBracket);
+ indexExpr->IndexExpression = parser->ParseExpression();
+ parser->ReadToken(TokenType::RBracket);
+
+ expr = indexExpr;
+ }
+ break;
+
+ // Call oepration `f(x)`
+ case TokenType::LParent:
+ {
+ RefPtr<InvokeExpressionSyntaxNode> invokeExpr = new InvokeExpressionSyntaxNode();
+ invokeExpr->FunctionExpr = expr;
+ parser->FillPosition(invokeExpr.Ptr());
+ parser->ReadToken(TokenType::LParent);
+ while (!parser->tokenReader.IsAtEnd())
+ {
+ if (!parser->LookAheadToken(TokenType::RParent))
+ invokeExpr->Arguments.Add(parser->ParseArgExpr());
+ else
+ {
+ break;
+ }
+ if (!parser->LookAheadToken(TokenType::Comma))
+ break;
+ parser->ReadToken(TokenType::Comma);
+ }
+ parser->ReadToken(TokenType::RParent);
+
+ expr = invokeExpr;
+ }
+ break;
+
+ // Member access `x.m`
+ case TokenType::Dot:
+ {
+ RefPtr<MemberExpressionSyntaxNode> memberExpr = new MemberExpressionSyntaxNode();
+
+ // TODO(tfoley): why would a member expression need this?
+ memberExpr->scope = parser->currentScope.Ptr();
+
+ parser->FillPosition(memberExpr.Ptr());
+ memberExpr->BaseExpression = expr;
+ parser->ReadToken(TokenType::Dot);
+ memberExpr->name = parser->ReadToken(TokenType::Identifier).Content;
+
+ expr = memberExpr;
+ }
+ break;
+ }
+ }
+ }
+
+ static RefPtr<ExpressionSyntaxNode> parsePrefixExpr(Parser* parser)
+ {
+ switch( peekTokenType(parser) )
+ {
+ default:
+ return parsePostfixExpr(parser);
+
+ case TokenType::OpInc:
+ case TokenType::OpDec:
+ case TokenType::OpNot:
+ case TokenType::OpBitNot:
+ case TokenType::OpSub:
+ {
+ RefPtr<PrefixExpr> prefixExpr = new PrefixExpr();
+ parser->FillPosition(prefixExpr.Ptr());
+ prefixExpr->FunctionExpr = parseOperator(parser);
+ prefixExpr->Arguments.Add(parsePrefixExpr(parser));
+ return prefixExpr;
+ }
+ break;
+ }
}
RefPtr<ExpressionSyntaxNode> Parser::ParseLeafExpression()
{
+ return parsePrefixExpr(this);
+
+#if 0
RefPtr<ExpressionSyntaxNode> rs;
if (LookAheadToken(TokenType::OpInc) ||
LookAheadToken(TokenType::OpDec) ||
@@ -3150,6 +3520,7 @@ parser->ReadToken(TokenType::Comma);
sink->diagnose(tokenReader.PeekLoc(), Diagnostics::syntaxError);
}
return rs;
+#endif
}
// Parse a source file into an existing translation unit
diff --git a/source/slang/slang-stdlib.cpp b/source/slang/slang-stdlib.cpp
index 387b6fbb2..3a3f6d13f 100644
--- a/source/slang/slang-stdlib.cpp
+++ b/source/slang/slang-stdlib.cpp
@@ -1150,6 +1150,7 @@ namespace Slang
// Declare vector and matrix types
sb << "__generic<T = float, let N : int = 4> __magic_type(Vector) struct vector\n{\n";
+ sb << " typedef T Element;\n";
sb << " __init(T value);\n"; // initialize from single scalar
sb << "};\n";
sb << "__generic<T = float, let R : int = 4, let C : int = 4> __magic_type(Matrix) struct matrix {};\n";
@@ -1343,13 +1344,9 @@ namespace Slang
sb << "float CalculateLevelOfDetailUnclamped(SamplerState s, ";
sb << "float" << kBaseTextureTypes[tt].coordCount << " location);\n";
-
- // TODO: `Gather` operation
- // (tricky because it returns a 4-vector of the element type
- // of the texture components...)
}
- // TODO: `GetDimensions` operations
+ // `GetDimensions`
for(int isFloat = 0; isFloat < 2; ++isFloat)
for(int includeMipInfo = 0; includeMipInfo < 2; ++includeMipInfo)
@@ -1532,12 +1529,104 @@ namespace Slang
}
sb << "\n};\n";
+
+ // `Gather*()` operations are handled via an `extension` declaration,
+ // because this lets us capture the element type of the texture.
+ //
+ // TODO: longer-term there should be something like a `TextureElementType`
+ // interface, that both scalars and vectors implement, that then exposes
+ // a `Scalar` associated type, and `Gather` can return `vector<T.Scalar, 4>`.
+ //
+ static const struct {
+ char const* genericPrefix;
+ char const* elementType;
+ } kGatherExtensionCases[] = {
+ { "__generic<T, let N : int>", "vector<T,N>" },
+
+ // TODO: need a case here for scalars `T`, but also
+ // need to ensure that case doesn't accidentally match
+ // for `T = vector<...>`, which requires actual checking
+ // of constraints on generic parameters.
+ };
+ for(auto cc : kGatherExtensionCases)
+ {
+ // TODO: this should really be an `if` around the entire `Gather` logic
+ if (isMultisample) break;
+
+ EMIT_LINE_DIRECTIVE();
+ sb << cc.genericPrefix << " __extension ";
+ sb << kBaseTextureAccessLevels[accessLevel].name;
+ sb << name;
+ if (isArray) sb << "Array";
+ sb << "<" << cc.elementType << " >";
+ sb << "\n{\n";
+
+
+ // `Gather`
+ // (tricky because it returns a 4-vector of the element type
+ // of the texture components...)
+ //
+ // TODO: is it actually correct to restrict these so that, e.g.,
+ // `GatherAlpha()` isn't allowed on `Texture2D<float3>` because
+ // it nominally doesn't have an alpha component?
+ static const struct {
+ int componentIndex;
+ char const* componentName;
+ } kGatherComponets[] = {
+ { 0, "" },
+ { 0, "Red" },
+ { 1, "Green" },
+ { 2, "Blue" },
+ { 3, "Alpha" },
+ };
+
+ for(auto cc : kGatherComponets)
+ {
+ auto componentIndex = cc.componentIndex;
+ auto componentName = cc.componentName;
+
+ EMIT_LINE_DIRECTIVE();
+ sb << "vector<T, 4> Gather" << componentName << "(SamplerState s, ";
+ sb << "float" << kBaseTextureTypes[tt].coordCount << " location);\n";
+
+ EMIT_LINE_DIRECTIVE();
+ sb << "vector<T, 4> Gather" << componentName << "(SamplerState s, ";
+ sb << "float" << kBaseTextureTypes[tt].coordCount << " location, ";
+ sb << "int" << kBaseTextureTypes[tt].coordCount << " offset);\n";
+
+ EMIT_LINE_DIRECTIVE();
+ sb << "vector<T, 4> Gather" << componentName << "(SamplerState s, ";
+ sb << "float" << kBaseTextureTypes[tt].coordCount << " location, ";
+ sb << "int" << kBaseTextureTypes[tt].coordCount << " offset, ";
+ sb << "out uint status);\n";
+
+ EMIT_LINE_DIRECTIVE();
+ sb << "vector<T, 4> Gather" << componentName << "(SamplerState s, ";
+ sb << "float" << kBaseTextureTypes[tt].coordCount << " location, ";
+ sb << "int" << kBaseTextureTypes[tt].coordCount << " offset1, ";
+ sb << "int" << kBaseTextureTypes[tt].coordCount << " offset2, ";
+ sb << "int" << kBaseTextureTypes[tt].coordCount << " offset3, ";
+ sb << "int" << kBaseTextureTypes[tt].coordCount << " offset4);\n";
+
+ EMIT_LINE_DIRECTIVE();
+ sb << "vector<T, 4> Gather" << componentName << "(SamplerState s, ";
+ sb << "float" << kBaseTextureTypes[tt].coordCount << " location, ";
+ sb << "int" << kBaseTextureTypes[tt].coordCount << " offset1, ";
+ sb << "int" << kBaseTextureTypes[tt].coordCount << " offset2, ";
+ sb << "int" << kBaseTextureTypes[tt].coordCount << " offset3, ";
+ sb << "int" << kBaseTextureTypes[tt].coordCount << " offset4, ";
+ sb << "out uint status);\n";
+ }
+
+ EMIT_LINE_DIRECTIVE();
+ sb << "\n}\n";
+ }
}
}
}
// Declare additional built-in generic types
-
+ EMIT_LINE_DIRECTIVE();
sb << "__generic<T> __magic_type(ConstantBuffer) struct ConstantBuffer {};\n";
sb << "__generic<T> __magic_type(TextureBuffer) struct TextureBuffer {};\n";
diff --git a/source/slang/syntax.h b/source/slang/syntax.h
index 66eddc536..5eb62462e 100644
--- a/source/slang/syntax.h
+++ b/source/slang/syntax.h
@@ -632,7 +632,7 @@ namespace Slang
class Decl : public DeclBase
{
public:
- ContainerDecl* ParentDecl;
+ ContainerDecl* ParentDecl = nullptr;
Token Name;
String const& getName() { return Name.Content; }
@@ -1883,12 +1883,16 @@ namespace Slang
bool isOverloaded() const { return items.Count() > 1; }
};
+ class SemanticsVisitor;
+
struct LookupRequest
{
- RefPtr<Scope> scope = nullptr;
- RefPtr<Scope> endScope = nullptr;
+ SemanticsVisitor* semantics = nullptr;
+
+ RefPtr<Scope> scope = nullptr;
+ RefPtr<Scope> endScope = nullptr;
- LookupMask mask = LookupMask::All;
+ LookupMask mask = LookupMask::All;
};
// An expression that references an overloaded set of declarations