summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
authorTim Foley <tim.foley.is@gmail.com>2017-07-08 18:58:42 -0700
committerGitHub <noreply@github.com>2017-07-08 18:58:42 -0700
commit68df74b58a56b0a1fb19b9ec4ff0282969cd6a12 (patch)
tree5eaa7eaab892504db53cca4b8044b0c8bcde58b3 /source
parentc07a6e6b5f5e0e4839b435ff6c15b821b6dead11 (diff)
parent767d47a842700653b8deffe82ccb3c85ad582c13 (diff)
Merge pull request #60 from tfoleyNV/revise-rewriter
Revise rewriter
Diffstat (limited to 'source')
-rw-r--r--source/slang/check.cpp432
-rw-r--r--source/slang/emit.cpp766
-rw-r--r--source/slang/expr-defs.h21
-rw-r--r--source/slang/intrinsic-defs.h1
-rw-r--r--source/slang/lexer.cpp6
-rw-r--r--source/slang/lower.cpp234
-rw-r--r--source/slang/parser.cpp192
-rw-r--r--source/slang/slang-stdlib.cpp356
-rw-r--r--source/slang/slang-stdlib.h13
-rw-r--r--source/slang/slang.cpp17
-rw-r--r--source/slang/stmt-defs.h7
-rw-r--r--source/slang/syntax.h17
12 files changed, 1258 insertions, 804 deletions
diff --git a/source/slang/check.cpp b/source/slang/check.cpp
index 7c67473be..b87f7c6bc 100644
--- a/source/slang/check.cpp
+++ b/source/slang/check.cpp
@@ -243,14 +243,16 @@ namespace Slang
if (lookupResult.isOverloaded())
{
// We had an ambiguity anyway, so report it.
- getSink()->diagnose(overloadedExpr, Diagnostics::ambiguousReference, lookupResult.items[0].declRef.GetName());
-
- for(auto item : lookupResult.items)
+ if (!isRewriteMode())
{
- String declString = getDeclSignatureString(item);
- getSink()->diagnose(item.declRef, Diagnostics::overloadCandidate, declString);
- }
+ getSink()->diagnose(overloadedExpr, Diagnostics::ambiguousReference, lookupResult.items[0].declRef.GetName());
+ for(auto item : lookupResult.items)
+ {
+ String declString = getDeclSignatureString(item);
+ getSink()->diagnose(item.declRef, Diagnostics::overloadCandidate, declString);
+ }
+ }
// TODO(tfoley): should we construct a new ErrorExpr here?
overloadedExpr->Type = QualType(ExpressionType::Error);
return overloadedExpr;
@@ -276,9 +278,11 @@ namespace Slang
return expr;
}
- getSink()->diagnose(expr, Diagnostics::unimplemented, "expected a type");
- // TODO: construct some kind of `ErrorExpr`?
- return expr;
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(expr, Diagnostics::unimplemented, "expected a type");
+ }
+ return CreateErrorExpr(expr);
}
RefPtr<ExpressionType> ExpectAType(RefPtr<ExpressionSyntaxNode> expr)
@@ -424,7 +428,10 @@ namespace Slang
{
if (outProperType)
{
- getSink()->diagnose(typeExp.exp.Ptr(), Diagnostics::unimplemented, "can't fill in default for generic type parameter");
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(typeExp.exp.Ptr(), Diagnostics::unimplemented, "can't fill in default for generic type parameter");
+ }
*outProperType = ExpressionType::Error;
}
return false;
@@ -440,7 +447,10 @@ namespace Slang
{
if (outProperType)
{
- getSink()->diagnose(typeExp.exp.Ptr(), Diagnostics::unimplemented, "can't fill in default for generic type parameter");
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(typeExp.exp.Ptr(), Diagnostics::unimplemented, "can't fill in default for generic type parameter");
+ }
*outProperType = ExpressionType::Error;
}
return false;
@@ -511,7 +521,10 @@ namespace Slang
if (basicType->BaseType == BaseType::Void)
{
// TODO(tfoley): pick the right diagnostic message
- getSink()->diagnose(result.exp.Ptr(), Diagnostics::invalidTypeVoid);
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(result.exp.Ptr(), Diagnostics::invalidTypeVoid);
+ }
result.type = ExpressionType::Error;
return result;
}
@@ -634,7 +647,9 @@ namespace Slang
CASE(Int, Signed, Int32);
CASE(UInt, Unsigned, Int32);
CASE(UInt64, Unsigned, Int64);
+ CASE(Half, Float, Int16);
CASE(Float, Float, Int32);
+ CASE(Double, Float, Int64);
CASE(Void, Error, Error);
#undef CASE
@@ -972,7 +987,19 @@ namespace Slang
RefPtr<ExpressionType> toType,
RefPtr<ExpressionSyntaxNode> fromExpr)
{
- auto castExpr = new TypeCastExpressionSyntaxNode();
+ // In "rewrite" mode, we will generate a different syntax node
+ // to indicate that this type-cast was implicitly generated
+ // by the compiler, and shouldn't appear in the output code.
+ RefPtr<TypeCastExpressionSyntaxNode> castExpr;
+ if (isRewriteMode())
+ {
+ castExpr = new HiddenImplicitCastExpr();
+ }
+ else
+ {
+ castExpr = new ImplicitCastExpr();
+ }
+
castExpr->Position = fromExpr->Position;
castExpr->TargetType.type = toType;
castExpr->Type = QualType(toType);
@@ -980,6 +1007,10 @@ namespace Slang
return castExpr;
}
+ bool isRewriteMode()
+ {
+ return (getTranslationUnit()->compileFlags & SLANG_COMPILE_FLAG_NO_CHECKING) != 0;
+ }
// Perform type coercion, and emit errors if it isn't possible
RefPtr<ExpressionSyntaxNode> Coerce(
@@ -990,7 +1021,7 @@ namespace Slang
// expressions without a type, and we need to ignore them.
if( !fromExpr->Type.type )
{
- if(getTranslationUnit()->compileFlags & SLANG_COMPILE_FLAG_NO_CHECKING )
+ if(isRewriteMode())
return fromExpr;
}
@@ -1002,7 +1033,7 @@ namespace Slang
fromExpr.Ptr(),
nullptr))
{
- if(!(getTranslationUnit()->compileFlags & SLANG_COMPILE_FLAG_NO_CHECKING))
+ if(!isRewriteMode())
{
getSink()->diagnose(fromExpr->Position, Diagnostics::typeMismatch, toType, fromExpr->Type);
}
@@ -1041,13 +1072,20 @@ namespace Slang
else
{
// TODO: infer a type from the initializers
+
if (!initExpr)
{
- getSink()->diagnose(varDecl, Diagnostics::unimplemented, "variable declaration with no type must have initializer");
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(varDecl, Diagnostics::unimplemented, "variable declaration with no type must have initializer");
+ }
}
else
{
- getSink()->diagnose(varDecl, Diagnostics::unimplemented, "type inference for variable declaration");
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(varDecl, Diagnostics::unimplemented, "type inference for variable declaration");
+ }
}
}
@@ -1122,7 +1160,10 @@ namespace Slang
// If type expression didn't name an interface, we'll emit an error here
// TODO: deal with the case of an error in the type expression (don't cascade)
- getSink()->diagnose( base.exp, Diagnostics::expectedAnInterfaceGot, base.type);
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose( base.exp, Diagnostics::expectedAnInterfaceGot, base.type);
+ }
}
RefPtr<ConstantIntVal> checkConstantIntVal(
@@ -1138,7 +1179,10 @@ namespace Slang
auto constIntVal = intVal.As<ConstantIntVal>();
if(!constIntVal)
{
- getSink()->diagnose(expr->Position, Diagnostics::expectedIntegerConstantNotLiteral);
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(expr->Position, Diagnostics::expectedIntegerConstantNotLiteral);
+ }
return nullptr;
}
return constIntVal;
@@ -1503,7 +1547,10 @@ namespace Slang
if (!funcDecl->ReturnType.Equals(prevFuncDecl->ReturnType))
{
// Bad dedeclaration
- getSink()->diagnose(funcDecl, Diagnostics::unimplemented, "redeclaration has a different return type");
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(funcDecl, Diagnostics::unimplemented, "redeclaration has a different return type");
+ }
// Don't bother emitting other errors at this point
break;
@@ -1517,7 +1564,10 @@ namespace Slang
if (funcDecl->Body && prevFuncDecl->Body)
{
// Redefinition
- getSink()->diagnose(funcDecl, Diagnostics::unimplemented, "function redefinition");
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(funcDecl, Diagnostics::unimplemented, "function redefinition");
+ }
// Don't bother emitting other errors
break;
@@ -1539,7 +1589,12 @@ namespace Slang
para->Type = CheckUsableType(para->Type);
if (para->Type.Equals(ExpressionType::GetVoid()))
- getSink()->diagnose(para, Diagnostics::parameterCannotBeVoid);
+ {
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(para, Diagnostics::parameterCannotBeVoid);
+ }
+ }
}
void VisitFunctionDeclaration(FunctionSyntaxNode *functionNode)
@@ -1556,7 +1611,12 @@ namespace Slang
checkDecl(para);
if (paraNames.Contains(para->Name.Content))
- getSink()->diagnose(para, Diagnostics::parameterAlreadyDefined, para->Name);
+ {
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(para, Diagnostics::parameterAlreadyDefined, para->Name);
+ }
+ }
else
paraNames.Add(para->Name.Content);
}
@@ -1613,7 +1673,10 @@ namespace Slang
auto outer = FindOuterStmt<BreakableStmt>();
if (!outer)
{
- getSink()->diagnose(stmt, Diagnostics::breakOutsideLoop);
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(stmt, Diagnostics::breakOutsideLoop);
+ }
}
stmt->parentStmt = outer;
}
@@ -1622,7 +1685,10 @@ namespace Slang
auto outer = FindOuterStmt<LoopStmt>();
if (!outer)
{
- getSink()->diagnose(stmt, Diagnostics::continueOutsideLoop);
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(stmt, Diagnostics::continueOutsideLoop);
+ }
}
stmt->parentStmt = outer;
}
@@ -1691,7 +1757,10 @@ namespace Slang
if (!switchStmt)
{
- getSink()->diagnose(stmt, Diagnostics::caseOutsideSwitch);
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(stmt, Diagnostics::caseOutsideSwitch);
+ }
}
else
{
@@ -1707,7 +1776,10 @@ namespace Slang
auto switchStmt = FindOuterStmt<SwitchStmt>();
if (!switchStmt)
{
- getSink()->diagnose(stmt, Diagnostics::defaultOutsideSwitch);
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(stmt, Diagnostics::defaultOutsideSwitch);
+ }
}
stmt->parentStmt = switchStmt;
}
@@ -1723,7 +1795,6 @@ namespace Slang
// Nothing to do
}
-
void visitEmptyStatementSyntaxNode(EmptyStatementSyntaxNode*)
{
// Nothing to do
@@ -1739,7 +1810,12 @@ namespace Slang
if (!stmt->Expression)
{
if (function && !function->ReturnType.Equals(ExpressionType::GetVoid()))
- getSink()->diagnose(stmt, Diagnostics::returnNeedsExpression);
+ {
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(stmt, Diagnostics::returnNeedsExpression);
+ }
+ }
}
else
{
@@ -1832,7 +1908,10 @@ namespace Slang
// TODO(tfoley): How to handle the case where bound isn't known?
if (GetMinBound(elementCount) <= 0)
{
- getSink()->diagnose(varDecl, Diagnostics::invalidArraySize);
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(varDecl, Diagnostics::invalidArraySize);
+ }
return;
}
}
@@ -1853,7 +1932,12 @@ namespace Slang
#endif
varDecl->Type = typeExp;
if (varDecl->Type.Equals(ExpressionType::GetVoid()))
- getSink()->diagnose(varDecl, Diagnostics::invalidTypeVoid);
+ {
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(varDecl, Diagnostics::invalidTypeVoid);
+ }
+ }
if(auto initExpr = varDecl->Expr)
{
@@ -2044,6 +2128,12 @@ namespace Slang
RefPtr<IntVal> TryConstantFoldExpr(
ExpressionSyntaxNode* expr)
{
+ // Unwrap any "identity" expressions
+ while (auto parenExpr = dynamic_cast<ParenExpr*>(expr))
+ {
+ expr = parenExpr->base;
+ }
+
// TODO(tfoley): more serious constant folding here
if (auto constExp = dynamic_cast<ConstantExpressionSyntaxNode*>(expr))
{
@@ -2160,7 +2250,10 @@ namespace Slang
auto result = TryCheckIntegerConstantExpression(expr.Ptr());
if (!result)
{
- getSink()->diagnose(expr, Diagnostics::expectedIntegerConstantNotConstant);
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(expr, Diagnostics::expectedIntegerConstantNotConstant);
+ }
}
return result;
}
@@ -2177,7 +2270,10 @@ namespace Slang
if (!indexExpr->Type->Equals(ExpressionType::GetInt()) &&
!indexExpr->Type->Equals(ExpressionType::GetUInt()))
{
- getSink()->diagnose(indexExpr, Diagnostics::subscriptIndexNonInteger);
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(indexExpr, Diagnostics::subscriptIndexNonInteger);
+ }
return CreateErrorExpr(subscriptExpr.Ptr());
}
@@ -2320,7 +2416,10 @@ namespace Slang
fail:
{
- getSink()->diagnose(subscriptExpr, Diagnostics::subscriptNonArray, baseType);
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(subscriptExpr, Diagnostics::subscriptNonArray, baseType);
+ }
return CreateErrorExpr(subscriptExpr);
}
}
@@ -2419,6 +2518,16 @@ namespace Slang
return appExpr;
}
+ RefPtr<ExpressionSyntaxNode> visitParenExpr(ParenExpr* expr)
+ {
+ auto base = expr->base;
+ base = CheckTerm(base);
+
+ expr->base = base;
+ expr->Type = base->Type;
+ return expr;
+ }
+
//
RefPtr<ExpressionSyntaxNode> visitAssignExpr(AssignExpr* expr)
@@ -2431,7 +2540,10 @@ namespace Slang
if (!type.IsLeftValue)
{
- getSink()->diagnose(expr, Diagnostics::assignNonLValue);
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(expr, Diagnostics::assignNonLValue);
+ }
}
expr->Type = type;
return expr;
@@ -2460,7 +2572,10 @@ namespace Slang
}
else
{
- getSink()->diagnose(decl->targetType.exp, Diagnostics::unimplemented, "expected a nominal type here");
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(decl->targetType.exp, Diagnostics::unimplemented, "expected a nominal type here");
+ }
}
}
else if (decl->targetType->Equals(ExpressionType::Error))
@@ -2469,7 +2584,10 @@ namespace Slang
}
else
{
- getSink()->diagnose(decl->targetType.exp, Diagnostics::unimplemented, "expected a nominal type here");
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(decl->targetType.exp, Diagnostics::unimplemented, "expected a nominal type here");
+ }
}
decl->SetCheckState(DeclCheckState::CheckedHeader);
@@ -3073,12 +3191,18 @@ namespace Slang
{
if (argCount < paramCounts.required)
{
- getSink()->diagnose(context.appExpr, Diagnostics::notEnoughArguments, argCount, paramCounts.required);
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(context.appExpr, Diagnostics::notEnoughArguments, argCount, paramCounts.required);
+ }
}
else
{
assert(argCount > paramCounts.allowed);
- getSink()->diagnose(context.appExpr, Diagnostics::tooManyArguments, argCount, paramCounts.allowed);
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(context.appExpr, Diagnostics::tooManyArguments, argCount, paramCounts.allowed);
+ }
}
}
@@ -3100,8 +3224,11 @@ namespace Slang
if (context.mode != OverloadResolveContext::Mode::JustTrying)
{
- getSink()->diagnose(context.appExpr, Diagnostics::expectedPrefixOperator);
- getSink()->diagnose(decl, Diagnostics::seeDefinitionOf, decl->getName());
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(context.appExpr, Diagnostics::expectedPrefixOperator);
+ getSink()->diagnose(decl, Diagnostics::seeDefinitionOf, decl->getName());
+ }
}
return false;
@@ -3113,8 +3240,11 @@ namespace Slang
if (context.mode != OverloadResolveContext::Mode::JustTrying)
{
- getSink()->diagnose(context.appExpr, Diagnostics::expectedPostfixOperator);
- getSink()->diagnose(decl, Diagnostics::seeDefinitionOf, decl->getName());
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(context.appExpr, Diagnostics::expectedPostfixOperator);
+ getSink()->diagnose(decl, Diagnostics::seeDefinitionOf, decl->getName());
+ }
}
return false;
@@ -3311,13 +3441,16 @@ namespace Slang
if (candidate.status == OverloadCandidate::Status::GenericArgumentInferenceFailed)
{
String callString = GetCallSignatureString(context.appExpr);
- getSink()->diagnose(
- context.appExpr,
- Diagnostics::genericArgumentInferenceFailed,
- callString);
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(
+ context.appExpr,
+ Diagnostics::genericArgumentInferenceFailed,
+ callString);
- String declString = getDeclSignatureString(candidate.item);
- getSink()->diagnose(candidate.item.declRef, Diagnostics::genericSignatureTried, declString);
+ String declString = getDeclSignatureString(candidate.item);
+ getSink()->diagnose(candidate.item.declRef, Diagnostics::genericSignatureTried, declString);
+ }
goto error;
}
@@ -4223,6 +4356,14 @@ namespace Slang
{
return CreateErrorExpr(expr);
}
+ // If any of the arguments is an error, then we should bail out, to avoid
+ // cascading errors where we successfully pick an overload, but not the one
+ // the user meant.
+ for (auto arg : expr->Arguments)
+ {
+ if (IsErrorExpr(arg))
+ return CreateErrorExpr(expr);
+ }
OverloadResolveContext context;
context.appExpr = expr;
@@ -4268,11 +4409,17 @@ namespace Slang
// We will construct a diagnostic message to help out.
if (funcName.Length() != 0)
{
- getSink()->diagnose(expr, Diagnostics::noApplicableOverloadForNameWithArgs, funcName, argsList);
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(expr, Diagnostics::noApplicableOverloadForNameWithArgs, funcName, argsList);
+ }
}
else
{
- getSink()->diagnose(expr, Diagnostics::noApplicableWithArgs, argsList);
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(expr, Diagnostics::noApplicableWithArgs, argsList);
+ }
}
}
else
@@ -4281,32 +4428,41 @@ namespace Slang
if (funcName.Length() != 0)
{
- getSink()->diagnose(expr, Diagnostics::ambiguousOverloadForNameWithArgs, funcName, argsList);
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(expr, Diagnostics::ambiguousOverloadForNameWithArgs, funcName, argsList);
+ }
}
else
{
- getSink()->diagnose(expr, Diagnostics::ambiguousOverloadWithArgs, argsList);
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(expr, Diagnostics::ambiguousOverloadWithArgs, argsList);
+ }
}
}
- UInt candidateCount = context.bestCandidates.Count();
- UInt maxCandidatesToPrint = 10; // don't show too many candidates at once...
- UInt candidateIndex = 0;
- for (auto candidate : context.bestCandidates)
+ if (!isRewriteMode())
{
- String declString = getDeclSignatureString(candidate.item);
+ UInt candidateCount = context.bestCandidates.Count();
+ UInt maxCandidatesToPrint = 10; // don't show too many candidates at once...
+ UInt candidateIndex = 0;
+ for (auto candidate : context.bestCandidates)
+ {
+ String declString = getDeclSignatureString(candidate.item);
- declString = declString + "[" + String(candidate.conversionCostSum) + "]";
+ declString = declString + "[" + String(candidate.conversionCostSum) + "]";
- getSink()->diagnose(candidate.item.declRef, Diagnostics::overloadCandidate, declString);
+ getSink()->diagnose(candidate.item.declRef, Diagnostics::overloadCandidate, declString);
- candidateIndex++;
- if (candidateIndex == maxCandidatesToPrint)
- break;
- }
- if (candidateIndex != candidateCount)
- {
- getSink()->diagnose(expr, Diagnostics::moreOverloadCandidates, candidateCount - candidateIndex);
+ candidateIndex++;
+ if (candidateIndex == maxCandidatesToPrint)
+ break;
+ }
+ if (candidateIndex != candidateCount)
+ {
+ getSink()->diagnose(expr, Diagnostics::moreOverloadCandidates, candidateCount - candidateIndex);
+ }
}
return CreateErrorExpr(expr);
@@ -4322,7 +4478,10 @@ namespace Slang
else
{
// Nothing at all was found that we could even consider invoking
- getSink()->diagnose(expr->FunctionExpr, Diagnostics::expectedFunction);
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(expr->FunctionExpr, Diagnostics::expectedFunction);
+ }
expr->Type = QualType(ExpressionType::Error);
return expr;
}
@@ -4417,7 +4576,10 @@ namespace Slang
// TODO(tfoley): print a reasonable message here...
- getSink()->diagnose(genericAppExpr, Diagnostics::unimplemented, "no applicable generic");
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(genericAppExpr, Diagnostics::unimplemented, "no applicable generic");
+ }
return CreateErrorExpr(genericAppExpr);
}
@@ -4448,76 +4610,12 @@ namespace Slang
else
{
// Nothing at all was found that we could even consider invoking
- getSink()->diagnose(genericAppExpr, Diagnostics::unimplemented, "expected a generic");
- return CreateErrorExpr(genericAppExpr);
- }
-
-
-#if TIMREMOVED
-
- if (IsErrorExpr(base))
- {
- return CreateErrorExpr(typeNode);
- }
- else if(auto baseDeclRefExpr = base.As<DeclRefExpr>())
- {
- auto declRef = baseDeclRefExpr->declRef;
-
- if (auto genericDeclRef = declRef.As<GenericDecl>())
+ if (!isRewriteMode())
{
- int argCount = typeNode->Args.Count();
- int argIndex = 0;
- for (RefPtr<Decl> member : genericDeclRef.getDecl()->Members)
- {
- if (auto typeParam = member.As<GenericTypeParamDecl>())
- {
- if (argIndex == argCount)
- {
- // Too few arguments!
-
- }
-
- // TODO: checking!
- }
- else if (auto valParam = member.As<GenericValueParamDecl>())
- {
- // TODO: checking
- }
- else
- {
-
- }
- }
- if (argIndex != argCount)
- {
- // Too many arguments!
- }
-
- // Now instantiate the declaration given those arguments
- auto type = InstantiateGenericType(genericDeclRef, args);
- typeResult = type;
- typeNode->Type = new TypeExpressionType(type);
- return typeNode;
- }
- }
- else if (auto overloadedExpr = base.As<OverloadedExpr>())
- {
- // We are referring to a bunch of declarations, each of which might be generic
- LookupResult result;
- for (auto item : overloadedExpr->lookupResult2.items)
- {
- auto applied = TryApplyGeneric(item, typeNode);
- if (!applied)
- continue;
-
- AddToLookupResult(result, appliedItem);
+ getSink()->diagnose(genericAppExpr, Diagnostics::unimplemented, "expected a generic");
}
+ return CreateErrorExpr(genericAppExpr);
}
-
- // TODO: correct diagnostic here!
- getSink()->diagnose(typeNode, Diagnostics::expectedAGeneric, base->Type);
- return CreateErrorExpr(typeNode);
-#endif
}
RefPtr<ExpressionSyntaxNode> visitSharedTypeExpr(SharedTypeExpr* expr)
@@ -4568,7 +4666,10 @@ namespace Slang
if (i < expr->Arguments.Count() && expr->Arguments[i]->Type->AsBasicType() &&
!expr->Arguments[i]->Type.IsLeftValue)
{
- getSink()->diagnose(expr->Arguments[i], Diagnostics::argumentExpectedLValue, (*params)[i]->Name);
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(expr->Arguments[i], Diagnostics::argumentExpectedLValue, (*params)[i]->Name);
+ }
}
}
}
@@ -4610,7 +4711,10 @@ namespace Slang
expr);
}
- getSink()->diagnose(expr, Diagnostics::undefinedIdentifier2, expr->name);
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(expr, Diagnostics::undefinedIdentifier2, expr->name);
+ }
return expr;
}
@@ -4651,32 +4755,13 @@ namespace Slang
fail:
// Default: in no other case succeds, then the cast failed and we emit a diagnostic.
- getSink()->diagnose(expr, Diagnostics::invalidTypeCast, expr->Expression->Type, targetType->ToString());
- expr->Type = QualType(ExpressionType::Error);
- return expr;
- }
-#if TIMREMOVED
- virtual RefPtr<ExpressionSyntaxNode> VisitSelectExpression(SelectExpressionSyntaxNode * expr) override
- {
- auto selectorExpr = expr->SelectorExpr;
- selectorExpr = CheckExpr(selectorExpr);
- selectorExpr = Coerce(ExpressionType::GetBool(), selectorExpr);
- expr->SelectorExpr = selectorExpr;
-
- // TODO(tfoley): We need a general purpose "join" on types for inferring
- // generic argument types for builtins/intrinsics, so this should really
- // be using the exact same logic...
- //
- expr->Expr0 = expr->Expr0->Accept(this).As<ExpressionSyntaxNode>();
- expr->Expr1 = expr->Expr1->Accept(this).As<ExpressionSyntaxNode>();
- if (!expr->Expr0->Type->Equals(expr->Expr1->Type.Ptr()))
+ if (!isRewriteMode())
{
- getSink()->diagnose(expr, Diagnostics::selectValuesTypeMismatch);
+ getSink()->diagnose(expr, Diagnostics::invalidTypeCast, expr->Expression->Type, targetType->ToString());
}
- expr->Type = expr->Expr0->Type;
+ expr->Type = QualType(ExpressionType::Error);
return expr;
}
-#endif
// Get the type to use when referencing a declaration
QualType GetTypeForDeclRef(DeclRef<Decl> declRef)
@@ -4771,7 +4856,10 @@ namespace Slang
case 'w': case 'a': elementIndex = 3; break;
default:
// An invalid character in the swizzle is an error
- getSink()->diagnose(swizExpr, Diagnostics::unimplemented, "invalid component name for swizzle");
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(swizExpr, Diagnostics::unimplemented, "invalid component name for swizzle");
+ }
anyError = true;
continue;
}
@@ -4782,7 +4870,10 @@ namespace Slang
// Make sure the index is in range for the source type
if (elementIndex >= limitElement)
{
- getSink()->diagnose(swizExpr, Diagnostics::unimplemented, "swizzle component out of range for type");
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(swizExpr, Diagnostics::unimplemented, "swizzle component out of range for type");
+ }
anyError = true;
continue;
}
@@ -4806,7 +4897,7 @@ namespace Slang
if (anyError)
{
- swizExpr->Type = QualType(ExpressionType::Error);
+ return CreateErrorExpr(memberRefExpr);
}
else if (elementCount == 1)
{
@@ -4844,7 +4935,10 @@ namespace Slang
}
else
{
- getSink()->diagnose(memberRefExpr, Diagnostics::unimplemented, "swizzle on vector of unknown size");
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(memberRefExpr, Diagnostics::unimplemented, "swizzle on vector of unknown size");
+ }
return CreateErrorExpr(memberRefExpr);
}
}
@@ -4928,7 +5022,10 @@ namespace Slang
// catch-all
fail:
- getSink()->diagnose(expr, Diagnostics::noMemberOfNameInType, expr->name, baseType);
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(expr, Diagnostics::noMemberOfNameInType, expr->name, baseType);
+ }
expr->Type = QualType(ExpressionType::Error);
return expr;
}
@@ -4940,7 +5037,10 @@ namespace Slang
if (!baseType->Equals(ExpressionType::Error.Ptr()) &&
expr->Type->Equals(ExpressionType::Error.Ptr()))
{
- getSink()->diagnose(expr, Diagnostics::typeHasNoPublicMemberOfName, baseType, expr->name);
+ if (!isRewriteMode())
+ {
+ getSink()->diagnose(expr, Diagnostics::typeHasNoPublicMemberOfName, baseType, expr->name);
+ }
}
return expr;
}
diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp
index df74d19e4..c135090c1 100644
--- a/source/slang/emit.cpp
+++ b/source/slang/emit.cpp
@@ -21,9 +21,6 @@ struct SharedEmitContext
// The target language we want to generate code for
CodeGenTarget target;
- // A set of words reserved by the target
- Dictionary<String, String> reservedWords;
-
// The string of code we've built so far
StringBuilder sb;
@@ -57,10 +54,6 @@ struct EmitContext
{
// The shared context that is in effect
SharedEmitContext* shared;
-
- // Are we in "rewrite" mode, where we are trying to reproduce the input
- // code as closely as posible?
- bool isRewrite;
};
//
@@ -84,6 +77,194 @@ static String getStringOrIdentifierTokenValue(
}
+enum EPrecedence
+{
+#define LEFT(NAME) \
+ kEPrecedence_##NAME##_Left, \
+ kEPrecedence_##NAME##_Right
+
+#define RIGHT(NAME) \
+ kEPrecedence_##NAME##_Right, \
+ kEPrecedence_##NAME##_Left
+
+#define NONASSOC(NAME) \
+ kEPrecedence_##NAME##_Left, \
+ kEPrecedence_##NAME##_Right = kEPrecedence_##NAME##_Left
+
+ NONASSOC(None),
+ LEFT(Comma),
+
+ NONASSOC(General),
+
+ RIGHT(Assign),
+
+ RIGHT(Conditional),
+
+ LEFT(Or),
+ LEFT(And),
+ LEFT(BitOr),
+ LEFT(BitXor),
+ LEFT(BitAnd),
+
+ LEFT(Equality),
+ LEFT(Relational),
+ LEFT(Shift),
+ LEFT(Additive),
+ LEFT(Multiplicative),
+ RIGHT(Prefix),
+ LEFT(Postfix),
+ NONASSOC(Atomic),
+
+#if 0
+
+ kEPrecedence_None,
+ kEPrecedence_Comma,
+
+ kEPrecedence_Assign,
+ kEPrecedence_AddAssign = kEPrecedence_Assign,
+ kEPrecedence_SubAssign = kEPrecedence_Assign,
+ kEPrecedence_MulAssign = kEPrecedence_Assign,
+ kEPrecedence_DivAssign = kEPrecedence_Assign,
+ kEPrecedence_ModAssign = kEPrecedence_Assign,
+ kEPrecedence_LshAssign = kEPrecedence_Assign,
+ kEPrecedence_RshAssign = kEPrecedence_Assign,
+ kEPrecedence_OrAssign = kEPrecedence_Assign,
+ kEPrecedence_AndAssign = kEPrecedence_Assign,
+ kEPrecedence_XorAssign = kEPrecedence_Assign,
+
+ kEPrecedence_General = kEPrecedence_Assign,
+
+ kEPrecedence_Conditional, // "ternary"
+ kEPrecedence_Or,
+ kEPrecedence_And,
+ kEPrecedence_BitOr,
+ kEPrecedence_BitXor,
+ kEPrecedence_BitAnd,
+
+ kEPrecedence_Eql,
+ kEPrecedence_Neq = kEPrecedence_Eql,
+
+ kEPrecedence_Less,
+ kEPrecedence_Greater = kEPrecedence_Less,
+ kEPrecedence_Leq = kEPrecedence_Less,
+ kEPrecedence_Geq = kEPrecedence_Less,
+
+ kEPrecedence_Lsh,
+ kEPrecedence_Rsh = kEPrecedence_Lsh,
+
+ kEPrecedence_Add,
+ kEPrecedence_Sub = kEPrecedence_Add,
+
+ kEPrecedence_Mul,
+ kEPrecedence_Div = kEPrecedence_Mul,
+ kEPrecedence_Mod = kEPrecedence_Mul,
+
+ kEPrecedence_Prefix,
+ kEPrecedence_Postfix,
+ kEPrecedence_Atomic = kEPrecedence_Postfix
+
+#endif
+
+};
+
+// Info on an op for emit purposes
+struct EOpInfo
+{
+ char const* op;
+ EPrecedence leftPrecedence;
+ EPrecedence rightPrecedence;
+};
+
+#define OP(NAME, TEXT, PREC) \
+static const EOpInfo kEOp_##NAME = { TEXT, kEPrecedence_##PREC##_Left, kEPrecedence_##PREC##_Right, }
+
+OP(None, "", None);
+
+OP(Comma, ",", Comma);
+
+OP(General, "", General);
+
+OP(Assign, "=", Assign);
+OP(AddAssign, "+=", Assign);
+OP(SubAssign, "-=", Assign);
+OP(MulAssign, "*=", Assign);
+OP(DivAssign, "/=", Assign);
+OP(ModAssign, "%=", Assign);
+OP(LshAssign, "<<=", Assign);
+OP(RshAssign, ">>=", Assign);
+OP(OrAssign, "|=", Assign);
+OP(AndAssign, "&=", Assign);
+OP(XorAssign, "^=", Assign);
+
+OP(Conditional, "?:", Conditional);
+
+OP(Or, "||", Or);
+OP(And, "&&", And);
+OP(BitOr, "|", BitOr);
+OP(BitXor, "^", BitXor);
+OP(BitAnd, "&", BitAnd);
+
+OP(Eql, "==", Equality);
+OP(Neq, "!=", Equality);
+
+OP(Less, "<", Relational);
+OP(Greater, ">", Relational);
+OP(Leq, "<=", Relational);
+OP(Geq, ">=", Relational);
+
+OP(Lsh, "<<", Shift);
+OP(Rsh, ">>", Shift);
+
+OP(Add, "+", Additive);
+OP(Sub, "-", Additive);
+
+OP(Mul, "*", Multiplicative);
+OP(Div, "/", Multiplicative);
+OP(Mod, "%", Multiplicative);
+
+OP(Prefix, "", Prefix);
+OP(Postfix, "", Postfix);
+OP(Atomic, "", Atomic);
+
+#undef OP
+
+// Table to allow data-driven lookup of an op based on its
+// name (to assist when outputting unchecked operator calls)
+static EOpInfo const* const kInfixOpInfos[] =
+{
+ &kEOp_Comma,
+ &kEOp_Assign,
+ &kEOp_AddAssign,
+ &kEOp_SubAssign,
+ &kEOp_MulAssign,
+ &kEOp_DivAssign,
+ &kEOp_ModAssign,
+ &kEOp_LshAssign,
+ &kEOp_RshAssign,
+ &kEOp_OrAssign,
+ &kEOp_AndAssign,
+ &kEOp_XorAssign,
+ &kEOp_Or,
+ &kEOp_And,
+ &kEOp_BitOr,
+ &kEOp_BitXor,
+ &kEOp_BitAnd,
+ &kEOp_Eql,
+ &kEOp_Neq,
+ &kEOp_Less,
+ &kEOp_Greater,
+ &kEOp_Leq,
+ &kEOp_Geq,
+ &kEOp_Lsh,
+ &kEOp_Rsh,
+ &kEOp_Add,
+ &kEOp_Sub,
+ &kEOp_Mul,
+ &kEOp_Div,
+ &kEOp_Mod,
+};
+
+
//
// represents a declarator for use in emitting types
@@ -113,7 +294,7 @@ struct TypeEmitArg
struct ExprEmitArg
{
- int outerPrec;
+ EOpInfo outerPrec;
};
struct DeclEmitArg
@@ -201,46 +382,12 @@ struct EmitVisitor
Emit(text.begin(), text.end());
}
- bool isReservedWord(String const& name)
- {
- return context->shared->reservedWords.TryGetValue(name) != nullptr;
- }
-
void emitName(
String const& inName,
CodePosition const& loc)
{
String name = inName;
- // By default, we would like to emit a name in the generated
- // code exactly as it appeared in the soriginal program.
- // When that isn't possible, we'd like to emit a name as
- // close to the original as possible (to ensure that existing
- // debugging tools still work reasonably well).
- //
- // One reason why a name might not be allowed as-is is that
- // it could collide with a reserved word in the target language.
- // Another reason is that it might not follow a naming convention
- // imposed by the target (e.g., in GLSL names starting with
- // `gl_` or containing `__` are reserved).
- //
- // Given a name that should not be allowed, we want to
- // change it to a name that *is* allowed. e.g., by adding
- // `_` to the end of a reserved word.
- //
- // The next problem this creates is that the modified name
- // could not collide with an existing use of the same
- // (valid) name.
- //
- // For now we are going to solve this problem in a simple
- // and ad hoc fashion, but longer term we'll want to do
- // something sytematic.
-
- if (isReservedWord(name))
- {
- name = name + "_";
- }
-
advanceToSourceLocation(loc);
emit(name);
}
@@ -970,6 +1117,14 @@ struct EmitVisitor
{
e = derefExpr->base;
}
+
+ if (auto declRefExpr = e.As<DeclRefExpr>())
+ {
+ auto decl = declRefExpr->declRef.getDecl();
+ if (decl && decl->HasModifier<TransparentModifier>())
+ return true;
+ }
+
// Is the expression referencing a constant buffer?
if (auto cbufferType = e->Type->As<ConstantBufferType>())
{
@@ -979,73 +1134,30 @@ struct EmitVisitor
return false;
}
- enum
- {
- kPrecedence_None,
- kPrecedence_Comma,
-
- kPrecedence_Assign,
- kPrecedence_AddAssign = kPrecedence_Assign,
- kPrecedence_SubAssign = kPrecedence_Assign,
- kPrecedence_MulAssign = kPrecedence_Assign,
- kPrecedence_DivAssign = kPrecedence_Assign,
- kPrecedence_ModAssign = kPrecedence_Assign,
- kPrecedence_LshAssign = kPrecedence_Assign,
- kPrecedence_RshAssign = kPrecedence_Assign,
- kPrecedence_OrAssign = kPrecedence_Assign,
- kPrecedence_AndAssign = kPrecedence_Assign,
- kPrecedence_XorAssign = kPrecedence_Assign,
-
- kPrecedence_General = kPrecedence_Assign,
-
- kPrecedence_Conditional, // "ternary"
- kPrecedence_Or,
- kPrecedence_And,
- kPrecedence_BitOr,
- kPrecedence_BitXor,
- kPrecedence_BitAnd,
-
- kPrecedence_Eql,
- kPrecedence_Neq = kPrecedence_Eql,
-
- kPrecedence_Less,
- kPrecedence_Greater = kPrecedence_Less,
- kPrecedence_Leq = kPrecedence_Less,
- kPrecedence_Geq = kPrecedence_Less,
-
- kPrecedence_Lsh,
- kPrecedence_Rsh = kPrecedence_Lsh,
-
- kPrecedence_Add,
- kPrecedence_Sub = kPrecedence_Add,
-
- kPrecedence_Mul,
- kPrecedence_Div = kPrecedence_Mul,
- kPrecedence_Mod = kPrecedence_Mul,
-
- kPrecedence_Prefix,
- kPrecedence_Postfix,
- kPrecedence_Atomic = kPrecedence_Postfix
- };
-
+#if 0
void EmitPostfixExpr(RefPtr<ExpressionSyntaxNode> expr)
{
- EmitExprWithPrecedence(expr, kPrecedence_Postfix);
+ EmitExprWithPrecedence(expr, kEOp_Postfix);
}
+#endif
void EmitExpr(RefPtr<ExpressionSyntaxNode> expr)
{
- EmitExprWithPrecedence(expr, kPrecedence_General);
+ EmitExprWithPrecedence(expr, kEOp_General);
}
- bool MaybeEmitParens(int outerPrec, int prec)
+ bool MaybeEmitParens(EOpInfo& outerPrec, EOpInfo prec)
{
- if (prec <= outerPrec)
+ bool needParens = (prec.leftPrecedence <= outerPrec.leftPrecedence)
+ || (prec.rightPrecedence <= outerPrec.rightPrecedence);
+
+ if (needParens)
{
Emit("(");
- return true;
+
+ outerPrec = kEOp_None;
}
- return false;
+ return needParens;
}
// When we are going to emit an expression in an l-value context,
@@ -1071,8 +1183,8 @@ struct EmitVisitor
}
void emitInfixExprImpl(
- int outerPrec,
- int prec,
+ EOpInfo outerPrec,
+ EOpInfo prec,
char const* op,
RefPtr<InvokeExpressionSyntaxNode> binExpr,
bool isAssign)
@@ -1085,30 +1197,30 @@ struct EmitVisitor
left = prepareLValueExpr(left);
}
- EmitExprWithPrecedence(left, prec);
+ EmitExprWithPrecedence(left, leftSide(outerPrec, prec));
Emit(" ");
Emit(op);
Emit(" ");
- EmitExprWithPrecedence(binExpr->Arguments[1], prec);
+ EmitExprWithPrecedence(binExpr->Arguments[1], rightSide(prec, outerPrec));
if (needsClose)
{
Emit(")");
}
}
- void EmitBinExpr(int outerPrec, int prec, char const* op, RefPtr<InvokeExpressionSyntaxNode> binExpr)
+ void EmitBinExpr(EOpInfo outerPrec, EOpInfo prec, char const* op, RefPtr<InvokeExpressionSyntaxNode> binExpr)
{
emitInfixExprImpl(outerPrec, prec, op, binExpr, false);
}
- void EmitBinAssignExpr(int outerPrec, int prec, char const* op, RefPtr<InvokeExpressionSyntaxNode> binExpr)
+ void EmitBinAssignExpr(EOpInfo outerPrec, EOpInfo prec, char const* op, RefPtr<InvokeExpressionSyntaxNode> binExpr)
{
emitInfixExprImpl(outerPrec, prec, op, binExpr, true);
}
void emitUnaryExprImpl(
- int outerPrec,
- int prec,
+ EOpInfo outerPrec,
+ EOpInfo prec,
char const* preOp,
char const* postOp,
RefPtr<InvokeExpressionSyntaxNode> expr,
@@ -1123,7 +1235,16 @@ struct EmitVisitor
arg = prepareLValueExpr(arg);
}
- EmitExprWithPrecedence(arg, prec);
+ if (preOp)
+ {
+ EmitExprWithPrecedence(arg, rightSide(prec, outerPrec));
+ }
+ else
+ {
+ assert(postOp);
+ EmitExprWithPrecedence(arg, leftSide(outerPrec, prec));
+ }
+
Emit(postOp);
if (needsClose)
{
@@ -1132,8 +1253,8 @@ struct EmitVisitor
}
void EmitUnaryExpr(
- int outerPrec,
- int prec,
+ EOpInfo outerPrec,
+ EOpInfo prec,
char const* preOp,
char const* postOp,
RefPtr<InvokeExpressionSyntaxNode> expr)
@@ -1142,8 +1263,8 @@ struct EmitVisitor
}
void EmitUnaryAssignExpr(
- int outerPrec,
- int prec,
+ EOpInfo outerPrec,
+ EOpInfo prec,
char const* preOp,
char const* postOp,
RefPtr<InvokeExpressionSyntaxNode> expr)
@@ -1206,9 +1327,10 @@ struct EmitVisitor
// just an expression of the form `f(a0, a1, ...)`
void emitSimpleCallExpr(
RefPtr<InvokeExpressionSyntaxNode> callExpr,
- int outerPrec)
+ EOpInfo outerPrec)
{
- bool needClose = MaybeEmitParens(outerPrec, kPrecedence_Postfix);
+ auto prec = kEOp_Postfix;
+ bool needClose = MaybeEmitParens(outerPrec, prec);
auto funcExpr = callExpr->FunctionExpr;
if (auto funcDeclRefExpr = funcExpr.As<DeclRefExpr>())
@@ -1222,13 +1344,13 @@ struct EmitVisitor
else
{
// default case: just emit the decl ref
- EmitExpr(funcExpr);
+ EmitExprWithPrecedence(funcExpr, leftSide(outerPrec, prec));
}
}
else
{
// default case: just emit the expression
- EmitPostfixExpr(funcExpr);
+ EmitExprWithPrecedence(funcExpr, leftSide(outerPrec, prec));
}
Emit("(");
@@ -1273,7 +1395,23 @@ struct EmitVisitor
emit("\"");
}
- void EmitExprWithPrecedence(RefPtr<ExpressionSyntaxNode> expr, int outerPrec)
+ EOpInfo leftSide(EOpInfo const& outerPrec, EOpInfo const& prec)
+ {
+ EOpInfo result;
+ result.leftPrecedence = outerPrec.leftPrecedence;
+ result.rightPrecedence = prec.leftPrecedence;
+ return result;
+ }
+
+ EOpInfo rightSide(EOpInfo const& prec, EOpInfo const& outerPrec)
+ {
+ EOpInfo result;
+ result.leftPrecedence = prec.rightPrecedence;
+ result.rightPrecedence = outerPrec.rightPrecedence;
+ return result;
+ }
+
+ void EmitExprWithPrecedence(RefPtr<ExpressionSyntaxNode> expr, EOpInfo outerPrec)
{
ExprEmitArg arg;
arg.outerPrec = outerPrec;
@@ -1281,6 +1419,14 @@ struct EmitVisitor
ExprVisitorWithArg::dispatch(expr, arg);
}
+ void EmitExprWithPrecedence(RefPtr<ExpressionSyntaxNode> expr, EPrecedence leftPrec, EPrecedence rightPrec)
+ {
+ EOpInfo outerPrec;
+ outerPrec.leftPrecedence = leftPrec;
+ outerPrec.rightPrecedence = rightPrec;
+ }
+
+
#define UNEXPECTED(NAME) \
void visit##NAME(NAME*, ExprEmitArg const&) \
{ Emit(#NAME); }
@@ -1289,35 +1435,113 @@ struct EmitVisitor
#undef UNEXPECTED
- void visitSharedTypeExpr(SharedTypeExpr* expr, ExprEmitArg const& arg)
+ void visitSharedTypeExpr(SharedTypeExpr* expr, ExprEmitArg const&)
{
emitTypeExp(expr->base);
}
void visitSelectExpressionSyntaxNode(SelectExpressionSyntaxNode* selectExpr, ExprEmitArg const& arg)
{
+ auto prec = kEOp_Conditional;
auto outerPrec = arg.outerPrec;
- bool needClose = MaybeEmitParens(outerPrec, kPrecedence_Conditional);
+ bool needClose = MaybeEmitParens(outerPrec, kEOp_Conditional);
- EmitExprWithPrecedence(selectExpr->Arguments[0], kPrecedence_Conditional);
+ // TODO(tfoley): Need to ver the precedence here...
+
+ EmitExprWithPrecedence(selectExpr->Arguments[0], leftSide(outerPrec, prec));
Emit(" ? ");
- EmitExprWithPrecedence(selectExpr->Arguments[1], kPrecedence_Conditional);
+ EmitExprWithPrecedence(selectExpr->Arguments[1], prec);
Emit(" : ");
- EmitExprWithPrecedence(selectExpr->Arguments[2], kPrecedence_Conditional);
+ EmitExprWithPrecedence(selectExpr->Arguments[2], rightSide(prec, outerPrec));
if(needClose) Emit(")");
}
+ void visitParenExpr(ParenExpr* expr, ExprEmitArg const&)
+ {
+ Emit("(");
+ EmitExprWithPrecedence(expr->base, kEOp_None);
+ Emit(")");
+ }
+
void visitAssignExpr(AssignExpr* assignExpr, ExprEmitArg const& arg)
{
+ auto prec = kEOp_Assign;
auto outerPrec = arg.outerPrec;
- bool needClose = MaybeEmitParens(outerPrec, kPrecedence_Assign);
- EmitExprWithPrecedence(assignExpr->left, kPrecedence_Assign);
+ bool needClose = MaybeEmitParens(outerPrec, prec);
+ EmitExprWithPrecedence(assignExpr->left, leftSide(outerPrec, prec));
Emit(" = ");
- EmitExprWithPrecedence(assignExpr->right, kPrecedence_Assign);
+ EmitExprWithPrecedence(assignExpr->right, rightSide(prec, outerPrec));
if(needClose) Emit(")");
}
+ void emitUncheckedCallExpr(
+ RefPtr<InvokeExpressionSyntaxNode> callExpr,
+ String const& funcName,
+ ExprEmitArg const& arg)
+ {
+ auto outerPrec = arg.outerPrec;
+ auto funcExpr = callExpr->FunctionExpr;
+
+ // This can occur when we are dealing with unchecked input syntax,
+ // because we are in "rewriter" mode. In this case we should go
+ // ahead and emit things in the form that they were written.
+ if( auto infixExpr = callExpr.As<InfixExpr>() )
+ {
+ auto prec = kEOp_Comma;
+ for (auto opInfo : kInfixOpInfos)
+ {
+ if (funcName == opInfo->op)
+ {
+ prec = *opInfo;
+ break;
+ }
+ }
+
+ EmitBinExpr(
+ outerPrec,
+ prec,
+ funcName.Buffer(),
+ callExpr);
+ }
+ else if( auto prefixExpr = callExpr.As<PrefixExpr>() )
+ {
+ EmitUnaryExpr(
+ outerPrec,
+ kEOp_Prefix,
+ funcName.Buffer(),
+ "",
+ callExpr);
+ }
+ else if(auto postfixExpr = callExpr.As<PostfixExpr>())
+ {
+ EmitUnaryExpr(
+ outerPrec,
+ kEOp_Postfix,
+ "",
+ funcName.Buffer(),
+ callExpr);
+ }
+ else
+ {
+ bool needClose = MaybeEmitParens(outerPrec, kEOp_Postfix);
+
+ EmitExpr(funcExpr);
+
+ Emit("(");
+ UInt argCount = callExpr->Arguments.Count();
+ for (UInt aa = 0; aa < argCount; ++aa)
+ {
+ if (aa != 0) Emit(", ");
+ EmitExpr(callExpr->Arguments[aa]);
+ }
+ Emit(")");
+
+ if (needClose) Emit(")");
+ }
+ }
+
+
void visitInvokeExpressionSyntaxNode(
RefPtr<InvokeExpressionSyntaxNode> callExpr,
ExprEmitArg const& arg)
@@ -1331,46 +1555,14 @@ struct EmitVisitor
auto funcDecl = funcDeclRef.getDecl();
if(!funcDecl)
{
- // This can occur when we are dealing with unchecked input syntax,
- // because we are in "rewriter" mode. In this case we should go
- // ahead and emit things in the form that they were written.
- if( auto infixExpr = callExpr.As<InfixExpr>() )
- {
- EmitBinExpr(
- outerPrec,
- kPrecedence_Comma,
- funcDeclRefExpr->name.Buffer(),
- callExpr);
- }
- else if( auto prefixExpr = callExpr.As<PrefixExpr>() )
- {
- EmitUnaryExpr(
- outerPrec,
- kPrecedence_Prefix,
- funcDeclRefExpr->name.Buffer(),
- "",
- callExpr);
- }
- else if(auto postfixExpr = callExpr.As<PostfixExpr>())
- {
- EmitUnaryExpr(
- outerPrec,
- kPrecedence_Postfix,
- "",
- funcDeclRefExpr->name.Buffer(),
- callExpr);
- }
- else
- {
- emitSimpleCallExpr(callExpr, outerPrec);
- }
+ emitUncheckedCallExpr(callExpr, funcDeclRef.GetName(), arg);
return;
}
else if (auto intrinsicOpModifier = funcDecl->FindModifier<IntrinsicOpModifier>())
{
switch (intrinsicOpModifier->op)
{
- #define CASE(NAME, OP) case IntrinsicOp::NAME: EmitBinExpr(outerPrec, kPrecedence_##NAME, #OP, callExpr); return
+ #define CASE(NAME, OP) case IntrinsicOp::NAME: EmitBinExpr(outerPrec, kEOp_##NAME, #OP, callExpr); return
CASE(Mul, *);
CASE(Div, / );
CASE(Mod, %);
@@ -1391,7 +1583,7 @@ struct EmitVisitor
CASE(Or, || );
#undef CASE
- #define CASE(NAME, OP) case IntrinsicOp::NAME: EmitBinAssignExpr(outerPrec, kPrecedence_##NAME, #OP, callExpr); return
+ #define CASE(NAME, OP) case IntrinsicOp::NAME: EmitBinAssignExpr(outerPrec, kEOp_##NAME, #OP, callExpr); return
CASE(Assign, =);
CASE(AddAssign, +=);
CASE(SubAssign, -=);
@@ -1405,20 +1597,21 @@ struct EmitVisitor
CASE(XorAssign, ^=);
#undef CASE
- case IntrinsicOp::Sequence: EmitBinExpr(outerPrec, kPrecedence_Comma, ",", callExpr); return;
+ case IntrinsicOp::Sequence: EmitBinExpr(outerPrec, kEOp_Comma, ",", callExpr); return;
- #define CASE(NAME, OP) case IntrinsicOp::NAME: EmitUnaryExpr(outerPrec, kPrecedence_Prefix, #OP, "", callExpr); return
+ #define CASE(NAME, OP) case IntrinsicOp::NAME: EmitUnaryExpr(outerPrec, kEOp_Prefix, #OP, "", callExpr); return
+ CASE(Pos, +);
CASE(Neg, -);
CASE(Not, !);
CASE(BitNot, ~);
#undef CASE
- #define CASE(NAME, OP) case IntrinsicOp::NAME: EmitUnaryAssignExpr(outerPrec, kPrecedence_Prefix, #OP, "", callExpr); return
+ #define CASE(NAME, OP) case IntrinsicOp::NAME: EmitUnaryAssignExpr(outerPrec, kEOp_Prefix, #OP, "", callExpr); return
CASE(PreInc, ++);
CASE(PreDec, --);
#undef CASE
- #define CASE(NAME, OP) case IntrinsicOp::NAME: EmitUnaryAssignExpr(outerPrec, kPrecedence_Postfix, "", #OP, callExpr); return
+ #define CASE(NAME, OP) case IntrinsicOp::NAME: EmitUnaryAssignExpr(outerPrec, kEOp_Postfix, "", #OP, callExpr); return
CASE(PostInc, ++);
CASE(PostDec, --);
#undef CASE
@@ -1603,6 +1796,11 @@ struct EmitVisitor
}
}
}
+ else if (auto overloadedExpr = funcExpr.As<OverloadedExpr>())
+ {
+ emitUncheckedCallExpr(callExpr, overloadedExpr->lookupResult2.getName(), arg);
+ return;
+ }
// Fall through to default handling...
emitSimpleCallExpr(callExpr, outerPrec);
@@ -1612,8 +1810,9 @@ struct EmitVisitor
void visitMemberExpressionSyntaxNode(MemberExpressionSyntaxNode* memberExpr, ExprEmitArg const& arg)
{
+ auto prec = kEOp_Postfix;
auto outerPrec = arg.outerPrec;
- bool needClose = MaybeEmitParens(outerPrec, kPrecedence_Postfix);
+ bool needClose = MaybeEmitParens(outerPrec, prec);
// TODO(tfoley): figure out a good way to reference
// declarations that might be generic and/or might
@@ -1629,21 +1828,31 @@ struct EmitVisitor
}
else
{
- EmitExprWithPrecedence(memberExpr->BaseExpression, kPrecedence_Postfix);
+ EmitExprWithPrecedence(memberExpr->BaseExpression, leftSide(outerPrec, prec));
Emit(".");
}
- emitName(memberExpr->declRef.GetName());
+ if (!memberExpr->declRef)
+ {
+ // This case arises when checking didn't find anything, but we were
+ // in "rewrite" mode so we blazed ahead anyway.
+ emitName(memberExpr->name);
+ }
+ else
+ {
+ emit(memberExpr->declRef.GetName());
+ }
if(needClose) Emit(")");
}
void visitSwizzleExpr(SwizzleExpr* swizExpr, ExprEmitArg const& arg)
{
+ auto prec = kEOp_Postfix;
auto outerPrec = arg.outerPrec;
- bool needClose = MaybeEmitParens(outerPrec, kPrecedence_Postfix);
+ bool needClose = MaybeEmitParens(outerPrec, prec);
- EmitExprWithPrecedence(swizExpr->base, kPrecedence_Postfix);
+ EmitExprWithPrecedence(swizExpr->base, leftSide(outerPrec, prec));
Emit(".");
static const char* kComponentNames[] = { "x", "y", "z", "w" };
int elementCount = swizExpr->elementCount;
@@ -1655,27 +1864,33 @@ struct EmitVisitor
if(needClose) Emit(")");
}
- void visitIndexExpressionSyntaxNode(IndexExpressionSyntaxNode* indexExpr, ExprEmitArg const& arg)
+ void visitIndexExpressionSyntaxNode(IndexExpressionSyntaxNode* subscriptExpr, ExprEmitArg const& arg)
{
+ auto prec = kEOp_Postfix;
auto outerPrec = arg.outerPrec;
- bool needClose = MaybeEmitParens(outerPrec, kPrecedence_Postfix);
+ bool needClose = MaybeEmitParens(outerPrec, prec);
- EmitExprWithPrecedence(indexExpr->BaseExpression, kPrecedence_Postfix);
+ EmitExprWithPrecedence(subscriptExpr->BaseExpression, leftSide(outerPrec, prec));
Emit("[");
- EmitExpr(indexExpr->IndexExpression);
+ if (auto indexExpr = subscriptExpr->IndexExpression)
+ {
+ EmitExpr(indexExpr);
+ }
Emit("]");
if(needClose) Emit(")");
}
- void visitOverloadedExpr(OverloadedExpr* expr, ExprEmitArg const& arg)
+ void visitOverloadedExpr(OverloadedExpr* expr, ExprEmitArg const&)
{
emitName(expr->lookupResult2.getName());
}
void visitVarExpressionSyntaxNode(VarExpressionSyntaxNode* varExpr, ExprEmitArg const& arg)
{
- bool needClose = MaybeEmitParens(arg.outerPrec, kPrecedence_Atomic);
+ auto prec = kEOp_Atomic;
+ auto outerPrec = arg.outerPrec;
+ bool needClose = MaybeEmitParens(outerPrec, kEOp_Atomic);
// TODO: This won't be valid if we had to generate a qualified
// reference for some reason.
@@ -1696,7 +1911,7 @@ struct EmitVisitor
}
else
{
- emitName(varExpr->name);
+ emit(varExpr->name);
}
if(needClose) Emit(")");
@@ -1704,16 +1919,14 @@ struct EmitVisitor
void visitDerefExpr(DerefExpr* derefExpr, ExprEmitArg const& arg)
{
- auto outerPrec = arg.outerPrec;
-
// TODO(tfoley): dereference shouldn't always be implicit
- EmitExprWithPrecedence(derefExpr->base, outerPrec);
+ ExprVisitorWithArg::dispatch(derefExpr->base, arg);
}
void visitConstantExpressionSyntaxNode(ConstantExpressionSyntaxNode* litExpr, ExprEmitArg const& arg)
{
auto outerPrec = arg.outerPrec;
- bool needClose = MaybeEmitParens(outerPrec, kPrecedence_Atomic);
+ bool needClose = MaybeEmitParens(outerPrec, kEOp_Atomic);
char const* suffix = "";
auto type = litExpr->Type.type;
@@ -1775,6 +1988,13 @@ struct EmitVisitor
if(needClose) Emit(")");
}
+ void visitHiddenImplicitCastExpr(HiddenImplicitCastExpr* castExpr, ExprEmitArg const& arg)
+ {
+ // This was an implicit cast inserted in code parsed in "rewriter" mode,
+ // so we don't want to output it and change what the user's code looked like.
+ ExprVisitorWithArg::dispatch(castExpr->Expression, arg);
+ }
+
void visitTypeCastExpressionSyntaxNode(TypeCastExpressionSyntaxNode* castExpr, ExprEmitArg const& arg)
{
bool needClose = false;
@@ -1791,19 +2011,23 @@ struct EmitVisitor
default:
// HLSL (and C/C++) prefer cast syntax
// (In fact, HLSL doesn't allow constructor syntax for some conversions it allows as a cast)
- needClose = MaybeEmitParens(arg.outerPrec, kPrecedence_Prefix);
-
- Emit("(");
- EmitType(castExpr->Type);
- Emit(")(");
- EmitExpr(castExpr->Expression);
- Emit(")");
+ {
+ auto prec = kEOp_Prefix;
+ auto outerPrec = arg.outerPrec;
+ needClose = MaybeEmitParens(outerPrec, prec);
+
+ Emit("(");
+ EmitType(castExpr->Type);
+ Emit(")(");
+ EmitExpr(castExpr->Expression);
+ Emit(")");
+ }
break;
}
if(needClose) Emit(")");
}
- void visitInitializerListExpr(InitializerListExpr* expr, ExprEmitArg const& arg)
+ void visitInitializerListExpr(InitializerListExpr* expr, ExprEmitArg const&)
{
Emit("{ ");
for(auto& arg : expr->args)
@@ -1858,7 +2082,6 @@ struct EmitVisitor
}
}
-
void EmitUnparsedStmt(RefPtr<UnparsedStmt> stmt)
{
// TODO: actually emit the tokens that made up the statement...
@@ -1946,12 +2169,10 @@ struct EmitVisitor
// The one wrinkle is that HLSL implements the
// bad approach to scoping a `for` loop variable,
// so we need to avoid those outer `{...}` when
- // we are generating HLSL via "rewrite" (that is,
- // without our semantic checks).
+ // we are emitting code that was written in HLSL.
//
bool brokenScoping = false;
- if (context->shared->target == CodeGenTarget::HLSL
- && context->isRewrite)
+ if (forStmt.As<UnscopedForStmt>())
{
brokenScoping = true;
}
@@ -3001,165 +3222,8 @@ struct EmitVisitor
throw "unimplemented";
}
}
-
- void registerReservedWord(
- String const& name)
- {
- context->shared->reservedWords.Add(name, name);
- }
-
- void registerReservedWords()
- {
- #define WORD(NAME) registerReservedWord(#NAME)
-
- switch (context->shared->target)
- {
- case CodeGenTarget::GLSL:
- WORD(attribute);
- WORD(const);
- WORD(uniform);
- WORD(varying);
- WORD(buffer);
-
- WORD(shared);
- WORD(coherent);
- WORD(volatile);
- WORD(restrict);
- WORD(readonly);
- WORD(writeonly);
- WORD(atomic_unit);
- WORD(layout);
- WORD(centroid);
- WORD(flat);
- WORD(smooth);
- WORD(noperspective);
- WORD(patch);
- WORD(sample);
- WORD(break);
- WORD(continue);
- WORD(do);
- WORD(for);
- WORD(while);
- WORD(switch);
- WORD(case);
- WORD(default);
- WORD(if);
- WORD(else);
- WORD(subroutine);
- WORD(in);
- WORD(out);
- WORD(inout);
- WORD(float);
- WORD(double);
- WORD(int);
- WORD(void);
- WORD(bool);
- WORD(true);
- WORD(false);
- WORD(invariant);
- WORD(precise);
- WORD(discard);
- WORD(return);
-
- WORD(lowp);
- WORD(mediump);
- WORD(highp);
- WORD(precision);
- WORD(struct);
- WORD(uint);
-
- WORD(common);
- WORD(partition);
- WORD(active);
- WORD(asm);
- WORD(class);
- WORD(union);
- WORD(enum);
- WORD(typedef);
- WORD(template);
- WORD(this);
- WORD(resource);
-
- WORD(goto);
- WORD(inline);
- WORD(noinline);
- WORD(public);
- WORD(static);
- WORD(extern);
- WORD(external);
- WORD(interface);
- WORD(long);
- WORD(short);
- WORD(half);
- WORD(fixed);
- WORD(unsigned);
- WORD(superp);
- WORD(input);
- WORD(output);
- WORD(filter);
- WORD(sizeof);
- WORD(cast);
- WORD(namespace);
- WORD(using);
-
- #define CASE(NAME) \
- WORD(NAME ## 2); WORD(NAME ## 3); WORD(NAME ## 4)
-
- CASE(mat);
- CASE(dmat);
- CASE(mat2x);
- CASE(mat3x);
- CASE(mat4x);
- CASE(dmat2x);
- CASE(dmat3x);
- CASE(dmat4x);
- CASE(vec);
- CASE(ivec);
- CASE(bvec);
- CASE(dvec);
- CASE(uvec);
- CASE(hvec);
- CASE(fvec);
-
- #undef CASE
-
- #define CASE(NAME) \
- WORD(NAME ## 1D); \
- WORD(NAME ## 2D); \
- WORD(NAME ## 3D); \
- WORD(NAME ## Cube); \
- WORD(NAME ## 1DArray); \
- WORD(NAME ## 2DArray); \
- WORD(NAME ## 3DArray); \
- WORD(NAME ## CubeArray);\
- WORD(NAME ## 2DMS); \
- WORD(NAME ## 2DMSArray) \
- /* end */
-
- #define CASE2(NAME) \
- CASE(NAME); \
- CASE(i ## NAME); \
- CASE(u ## NAME) \
- /* end */
-
- CASE2(sampler);
- CASE2(image);
- CASE2(texture);
-
- #undef CASE2
- #undef CASE
- break;
-
- default:
- break;
- }
- }
};
-bool isRewriteRequest(
- SourceLanguage sourceLanguage,
- CodeGenTarget target);
-
String emitEntryPoint(
EntryPointRequest* entryPoint,
ProgramLayout* programLayout,
@@ -3215,15 +3279,9 @@ String emitEntryPoint(
EmitContext context;
context.shared = &sharedContext;
- context.isRewrite = isRewriteRequest(
- translationUnit->sourceLanguage,
- target);
EmitVisitor visitor(&context);
- // TODO: this should only need to take the shared context
- visitor.registerReservedWords();
-
auto translationUnitSyntax = translationUnit->SyntaxNode.Ptr();
diff --git a/source/slang/expr-defs.h b/source/slang/expr-defs.h
index ca5bfacb8..0dac324b9 100644
--- a/source/slang/expr-defs.h
+++ b/source/slang/expr-defs.h
@@ -91,11 +91,25 @@ SYNTAX_CLASS(DerefExpr, ExpressionSyntaxNode)
SYNTAX_FIELD(RefPtr<ExpressionSyntaxNode>, base)
END_SYNTAX_CLASS()
+// Any operation that performs type-casting
SYNTAX_CLASS(TypeCastExpressionSyntaxNode, ExpressionSyntaxNode)
SYNTAX_FIELD(TypeExp, TargetType)
SYNTAX_FIELD(RefPtr<ExpressionSyntaxNode>, Expression)
END_SYNTAX_CLASS()
+// An explicit type-cast that appear in the user's code with `(Type) expr` syntax
+SYNTAX_CLASS(ExplicitCastExpr, TypeCastExpressionSyntaxNode)
+END_SYNTAX_CLASS()
+
+// An implicit type-cast inserted during semantic checking
+SYNTAX_CLASS(ImplicitCastExpr, TypeCastExpressionSyntaxNode)
+END_SYNTAX_CLASS()
+
+// An implicit type-cast that should also be hidden on output,
+// because we don't want to mess with the user's code
+SYNTAX_CLASS(HiddenImplicitCastExpr, ImplicitCastExpr)
+END_SYNTAX_CLASS()
+
SIMPLE_SYNTAX_CLASS(SelectExpressionSyntaxNode, OperatorExpressionSyntaxNode)
SIMPLE_SYNTAX_CLASS(GenericAppExpr, AppExprBase)
@@ -112,3 +126,10 @@ SYNTAX_CLASS(AssignExpr, ExpressionSyntaxNode)
SYNTAX_FIELD(RefPtr<ExpressionSyntaxNode>, right);
END_SYNTAX_CLASS()
+// Just an expression inside parentheses `(exp)`
+//
+// We keep this around explicitly to be sure we don't lose any structure
+// when we do rewriter stuff.
+SYNTAX_CLASS(ParenExpr, ExpressionSyntaxNode)
+ SYNTAX_FIELD(RefPtr<ExpressionSyntaxNode>, base);
+END_SYNTAX_CLASS()
diff --git a/source/slang/intrinsic-defs.h b/source/slang/intrinsic-defs.h
index 19a3899a3..a272bd51c 100644
--- a/source/slang/intrinsic-defs.h
+++ b/source/slang/intrinsic-defs.h
@@ -46,6 +46,7 @@ INTRINSIC(RshAssign)
INTRINSIC(OrAssign)
INTRINSIC(AndAssign)
INTRINSIC(XorAssign)
+INTRINSIC(Pos)
INTRINSIC(Neg)
INTRINSIC(Not)
INTRINSIC(BitNot)
diff --git a/source/slang/lexer.cpp b/source/slang/lexer.cpp
index 2d75e1900..d8211fb20 100644
--- a/source/slang/lexer.cpp
+++ b/source/slang/lexer.cpp
@@ -517,7 +517,7 @@ namespace Slang
if(base > 10)
{
cursor++;
- return c - 'a';
+ return 10 + c - 'a';
}
return -1;
@@ -525,7 +525,7 @@ namespace Slang
if(base > 10)
{
cursor++;
- return c - 'A';
+ return 10 + c - 'A';
}
return -1;
}
@@ -957,7 +957,7 @@ namespace Slang
switch(peek(lexer))
{
default:
- return TokenType::IntegerLiteral;
+ return maybeLexNumberSuffix(lexer, TokenType::IntegerLiteral);
case '.':
advance(lexer);
diff --git a/source/slang/lower.cpp b/source/slang/lower.cpp
index b90573495..0bb047791 100644
--- a/source/slang/lower.cpp
+++ b/source/slang/lower.cpp
@@ -194,8 +194,17 @@ public:
struct SharedLoweringContext
{
ProgramLayout* programLayout;
+
+ // The target we are going to generate code for.
+ //
+ // We may need to specialize how constructs get lowered based
+ // on the capabilities of the target language.
CodeGenTarget target;
+ // A set of words reserved by the target
+ Dictionary<String, String> reservedWords;
+
+
RefPtr<ProgramSyntaxNode> loweredProgram;
Dictionary<Decl*, RefPtr<Decl>> loweredDecls;
@@ -238,6 +247,165 @@ struct LoweringVisitor
CodeGenTarget getTarget() { return shared->target; }
+ bool isReservedWord(String const& name)
+ {
+ return shared->reservedWords.TryGetValue(name) != nullptr;
+ }
+
+ void registerReservedWord(
+ String const& name)
+ {
+ shared->reservedWords.Add(name, name);
+ }
+
+ void registerReservedWords()
+ {
+ #define WORD(NAME) registerReservedWord(#NAME)
+
+ switch (shared->target)
+ {
+ case CodeGenTarget::GLSL:
+ WORD(attribute);
+ WORD(const);
+ WORD(uniform);
+ WORD(varying);
+ WORD(buffer);
+
+ WORD(shared);
+ WORD(coherent);
+ WORD(volatile);
+ WORD(restrict);
+ WORD(readonly);
+ WORD(writeonly);
+ WORD(atomic_unit);
+ WORD(layout);
+ WORD(centroid);
+ WORD(flat);
+ WORD(smooth);
+ WORD(noperspective);
+ WORD(patch);
+ WORD(sample);
+ WORD(break);
+ WORD(continue);
+ WORD(do);
+ WORD(for);
+ WORD(while);
+ WORD(switch);
+ WORD(case);
+ WORD(default);
+ WORD(if);
+ WORD(else);
+ WORD(subroutine);
+ WORD(in);
+ WORD(out);
+ WORD(inout);
+ WORD(float);
+ WORD(double);
+ WORD(int);
+ WORD(void);
+ WORD(bool);
+ WORD(true);
+ WORD(false);
+ WORD(invariant);
+ WORD(precise);
+ WORD(discard);
+ WORD(return);
+
+ WORD(lowp);
+ WORD(mediump);
+ WORD(highp);
+ WORD(precision);
+ WORD(struct);
+ WORD(uint);
+
+ WORD(common);
+ WORD(partition);
+ WORD(active);
+ WORD(asm);
+ WORD(class);
+ WORD(union);
+ WORD(enum);
+ WORD(typedef);
+ WORD(template);
+ WORD(this);
+ WORD(resource);
+
+ WORD(goto);
+ WORD(inline);
+ WORD(noinline);
+ WORD(public);
+ WORD(static);
+ WORD(extern);
+ WORD(external);
+ WORD(interface);
+ WORD(long);
+ WORD(short);
+ WORD(half);
+ WORD(fixed);
+ WORD(unsigned);
+ WORD(superp);
+ WORD(input);
+ WORD(output);
+ WORD(filter);
+ WORD(sizeof);
+ WORD(cast);
+ WORD(namespace);
+ WORD(using);
+
+ #define CASE(NAME) \
+ WORD(NAME ## 2); WORD(NAME ## 3); WORD(NAME ## 4)
+
+ CASE(mat);
+ CASE(dmat);
+ CASE(mat2x);
+ CASE(mat3x);
+ CASE(mat4x);
+ CASE(dmat2x);
+ CASE(dmat3x);
+ CASE(dmat4x);
+ CASE(vec);
+ CASE(ivec);
+ CASE(bvec);
+ CASE(dvec);
+ CASE(uvec);
+ CASE(hvec);
+ CASE(fvec);
+
+ #undef CASE
+
+ #define CASE(NAME) \
+ WORD(NAME ## 1D); \
+ WORD(NAME ## 2D); \
+ WORD(NAME ## 3D); \
+ WORD(NAME ## Cube); \
+ WORD(NAME ## 1DArray); \
+ WORD(NAME ## 2DArray); \
+ WORD(NAME ## 3DArray); \
+ WORD(NAME ## CubeArray);\
+ WORD(NAME ## 2DMS); \
+ WORD(NAME ## 2DMSArray) \
+ /* end */
+
+ #define CASE2(NAME) \
+ CASE(NAME); \
+ CASE(i ## NAME); \
+ CASE(u ## NAME) \
+ /* end */
+
+ CASE2(sampler);
+ CASE2(image);
+ CASE2(texture);
+
+ #undef CASE2
+ #undef CASE
+ break;
+
+ default:
+ break;
+ }
+ }
+
+
//
// Values
//
@@ -451,6 +619,7 @@ struct LoweringVisitor
lowerExprCommon(loweredExpr, expr);
loweredExpr->BaseExpression = loweredBase;
loweredExpr->declRef = loweredDeclRef;
+ loweredExpr->name = expr->name;
return loweredExpr;
}
@@ -732,10 +901,10 @@ struct LoweringVisitor
addStmt(loweredStmt);
}
-
- void visitForStatementSyntaxNode(ForStatementSyntaxNode* stmt)
+ void lowerForStmtCommon(
+ RefPtr<ForStatementSyntaxNode> loweredStmt,
+ ForStatementSyntaxNode* stmt)
{
- RefPtr<ForStatementSyntaxNode> loweredStmt = new ForStatementSyntaxNode();
lowerScopeStmtFields(loweredStmt, stmt);
LoweringVisitor subVisitor = pushScope(loweredStmt, stmt);
@@ -748,6 +917,16 @@ struct LoweringVisitor
addStmt(loweredStmt);
}
+ void visitForStatementSyntaxNode(ForStatementSyntaxNode* stmt)
+ {
+ lowerForStmtCommon(new ForStatementSyntaxNode(), stmt);
+ }
+
+ void visitUnscopedForStmt(UnscopedForStmt* stmt)
+ {
+ lowerForStmtCommon(new UnscopedForStmt(), stmt);
+ }
+
void visitWhileStatementSyntaxNode(WhileStatementSyntaxNode* stmt)
{
RefPtr<WhileStatementSyntaxNode> loweredStmt = new WhileStatementSyntaxNode();
@@ -964,6 +1143,43 @@ struct LoweringVisitor
shared->mapLoweredDeclToOriginal.Add(loweredDecl, decl);
}
+ // If the name of the declarations collides with a reserved word
+ // for the code generation target, then rename it to avoid the conflict
+ //
+ // Note that this does *not* implement any kind of comprehensive renaming
+ // to, e.g., avoid conflicts between user-defined and library functions.
+ void ensureDeclHasAValidName(Decl* decl)
+ {
+ // By default, we would like to emit a name in the generated
+ // code exactly as it appeared in the original program.
+ // When that isn't possible, we'd like to emit a name as
+ // close to the original as possible (to ensure that existing
+ // debugging tools still work reasonably well).
+ //
+ // One reason why a name might not be allowed as-is is that
+ // it could collide with a reserved word in the target language.
+ // Another reason is that it might not follow a naming convention
+ // imposed by the target (e.g., in GLSL names starting with
+ // `gl_` or containing `__` are reserved).
+ //
+ // Given a name that should not be allowed, we want to
+ // change it to a name that *is* allowed. e.g., by adding
+ // `_` to the end of a reserved word.
+ //
+ // The next problem this creates is that the modified name
+ // could not collide with an existing use of the same
+ // (valid) name.
+ //
+ // For now we are going to solve this problem in a simple
+ // and ad hoc fashion, but longer term we'll want to do
+ // something sytematic.
+
+ if (isReservedWord(decl->getName()))
+ {
+ decl->Name.Content.append("_");
+ }
+ }
+
void lowerDeclCommon(
Decl* loweredDecl,
Decl* decl)
@@ -973,6 +1189,9 @@ struct LoweringVisitor
loweredDecl->Position = decl->Position;
loweredDecl->Name = decl->getNameToken();
+ // Deal with renaming - we shouldn't allow decls with names that are reserved words
+ ensureDeclHasAValidName(loweredDecl);
+
// Lower modifiers as needed
// HACK: just doing a shallow copy of modifiers, which will
@@ -1314,6 +1533,8 @@ struct LoweringVisitor
globalVarDecl->Name.Content = info.name;
globalVarDecl->Type.type = type;
+ ensureDeclHasAValidName(globalVarDecl);
+
addMember(shared->loweredProgram, globalVarDecl);
// Add the layout information
@@ -1515,6 +1736,8 @@ struct LoweringVisitor
localVarDecl->Name.Content = paramDecl->getName();
localVarDecl->Type = lowerType(paramDecl->Type);
+ ensureDeclHasAValidName(localVarDecl);
+
subVisitor.addDecl(localVarDecl);
EntryPointParamPair paramPair;
@@ -1549,6 +1772,8 @@ struct LoweringVisitor
resultVarDecl->Name.Content = "_main_result";
resultVarDecl->Type = TypeExp(loweredEntryPointFunc->ReturnType);
+ ensureDeclHasAValidName(resultVarDecl);
+
subVisitor.addDecl(resultVarDecl);
}
@@ -1793,6 +2018,9 @@ LoweredEntryPoint lowerEntryPoint(
visitor.shared = &sharedContext;
visitor.parentDecl = loweredProgram;
+ // TODO: this should only need to take the shared context
+ visitor.registerReservedWords();
+
// We need to register the lowered program as the lowered version
// of the existing translation unit declaration.
diff --git a/source/slang/parser.cpp b/source/slang/parser.cpp
index b134f9645..759fc0c20 100644
--- a/source/slang/parser.cpp
+++ b/source/slang/parser.cpp
@@ -44,6 +44,11 @@ namespace Slang
String fileName;
int genericDepth = 0;
+ // Have we seen any `import` declarations? If so, we need
+ // to parse function bodies completely, even if we are in
+ // "rewrite" mode.
+ bool haveSeenAnyImportDecls = false;
+
// Is the parser in a "recovering" state?
// During recovery we don't emit additional errors, until we find
// a token that we expected, when we exit recovery.
@@ -802,6 +807,8 @@ namespace Slang
static RefPtr<Decl> parseImportDecl(
Parser* parser)
{
+ parser->haveSeenAnyImportDecls = true;
+
parser->ReadToken("__import");
auto decl = new ImportDecl();
@@ -842,6 +849,8 @@ namespace Slang
static RefPtr<Decl> parsePoundImportDecl(
Parser* parser)
{
+ parser->haveSeenAnyImportDecls = true;
+
Token importToken = parser->ReadToken(TokenType::PoundImport);
auto decl = new ImportDecl();
@@ -1392,6 +1401,28 @@ namespace Slang
return genericApp;
}
+ // Parse option `[]` braces after a type expression, that indicate an array type
+ static RefPtr<ExpressionSyntaxNode> parsePostfixTypeSuffix(
+ Parser* parser,
+ RefPtr<ExpressionSyntaxNode> inTypeExpr)
+ {
+ auto typeExpr = inTypeExpr;
+ while (parser->LookAheadToken(TokenType::LBracket))
+ {
+ RefPtr<IndexExpressionSyntaxNode> arrType = new IndexExpressionSyntaxNode();
+ arrType->Position = typeExpr->Position;
+ arrType->BaseExpression = typeExpr;
+ parser->ReadToken(TokenType::LBracket);
+ if (!parser->LookAheadToken(TokenType::RBracket))
+ {
+ arrType->IndexExpression = parser->ParseExpression();
+ }
+ parser->ReadToken(TokenType::RBracket);
+ typeExpr = arrType;
+ }
+ return typeExpr;
+ }
+
static TypeSpec
parseTypeSpec(Parser* parser)
{
@@ -1431,11 +1462,16 @@ namespace Slang
typeExpr = parseGenericApp(parser, typeExpr);
}
+ // GLSL allows `[]` directly in a type specifier
+ if (parser->translationUnit->sourceLanguage == SourceLanguage::GLSL)
+ {
+ typeExpr = parsePostfixTypeSuffix(parser, typeExpr);
+ }
+
typeSpec.expr = typeExpr;
return typeSpec;
}
-
static RefPtr<DeclBase> ParseDeclaratorDecl(
Parser* parser,
ContainerDecl* containerDecl)
@@ -2572,7 +2608,11 @@ namespace Slang
RefPtr<StatementSyntaxNode> Parser::ParseBlockStatement()
{
- if( translationUnit->compileFlags & SLANG_COMPILE_FLAG_NO_CHECKING )
+ // If we are being asked not to check things *and* we haven't
+ // seen any `import` declarations yet, then we can safely assume
+ // that function bodies should be left as-is.
+ if( (translationUnit->compileFlags & SLANG_COMPILE_FLAG_NO_CHECKING)
+ && !haveSeenAnyImportDecls )
{
// We have been asked to parse the input, but not attempt to understand it.
@@ -2615,7 +2655,6 @@ namespace Slang
return unparsedStmt;
}
-
RefPtr<ScopeDecl> scopeDecl = new ScopeDecl();
RefPtr<BlockStmt> blockStatement = new BlockStmt();
blockStatement->scopeDecl = scopeDecl;
@@ -2690,12 +2729,32 @@ namespace Slang
RefPtr<ForStatementSyntaxNode> Parser::ParseForStatement()
{
RefPtr<ScopeDecl> scopeDecl = new ScopeDecl();
- RefPtr<ForStatementSyntaxNode> stmt = new ForStatementSyntaxNode();
+
+ // HLSL implements the bad approach to scoping a `for` loop
+ // variable, and we want to respect that, but *only* when
+ // parsing HLSL code.
+ //
+
+ bool brokenScoping = translationUnit->sourceLanguage == SourceLanguage::HLSL;
+
+ // We will create a distinct syntax node class for the unscoped
+ // case, just so that we can correctly handle it in downstream
+ // logic.
+ //
+ RefPtr<ForStatementSyntaxNode> stmt;
+ if (brokenScoping)
+ {
+ stmt = new UnscopedForStmt();
+ }
+ else
+ {
+ stmt = new ForStatementSyntaxNode();
+ }
+
stmt->scopeDecl = scopeDecl;
- // Note(tfoley): HLSL implements `for` with incorrect scoping.
- // We need an option to turn on this behavior in a kind of "legacy" mode
-// PushScope(scopeDecl.Ptr());
+ if(!brokenScoping)
+ PushScope(scopeDecl.Ptr());
FillPosition(stmt.Ptr());
ReadToken("for");
ReadToken(TokenType::LParent);
@@ -2721,7 +2780,10 @@ namespace Slang
stmt->SideEffectExpression = ParseExpression();
ReadToken(TokenType::RParent);
stmt->Statement = ParseStatement();
-// PopScope();
+
+ if (!brokenScoping)
+ PopScope();
+
return stmt;
}
@@ -2816,19 +2878,7 @@ namespace Slang
}
auto typeExpr = typeSpec.expr;
- while (LookAheadToken(TokenType::LBracket))
- {
- RefPtr<IndexExpressionSyntaxNode> arrType = new IndexExpressionSyntaxNode();
- arrType->Position = typeExpr->Position;
- arrType->BaseExpression = typeExpr;
- ReadToken(TokenType::LBracket);
- if (!LookAheadToken(TokenType::RBracket))
- {
- arrType->IndexExpression = ParseExpression();
- }
- ReadToken(TokenType::RBracket);
- typeExpr = arrType;
- }
+ typeExpr = parsePostfixTypeSuffix(this, typeExpr);
return typeExpr;
}
@@ -2915,83 +2965,6 @@ namespace Slang
}
}
- Operator GetOpFromToken(Token & token)
- {
- switch(token.Type)
- {
- case TokenType::Comma:
- return Operator::Sequence;
- case TokenType::OpAssign:
- return Operator::Assign;
- case TokenType::OpAddAssign:
- return Operator::AddAssign;
- case TokenType::OpSubAssign:
- return Operator::SubAssign;
- case TokenType::OpMulAssign:
- return Operator::MulAssign;
- case TokenType::OpDivAssign:
- return Operator::DivAssign;
- case TokenType::OpModAssign:
- return Operator::ModAssign;
- case TokenType::OpShlAssign:
- return Operator::LshAssign;
- case TokenType::OpShrAssign:
- return Operator::RshAssign;
- case TokenType::OpOrAssign:
- return Operator::OrAssign;
- case TokenType::OpAndAssign:
- return Operator::AddAssign;
- case TokenType::OpXorAssign:
- return Operator::XorAssign;
- case TokenType::OpOr:
- return Operator::Or;
- case TokenType::OpAnd:
- return Operator::And;
- case TokenType::OpBitOr:
- return Operator::BitOr;
- case TokenType::OpBitXor:
- return Operator::BitXor;
- case TokenType::OpBitAnd:
- return Operator::BitAnd;
- case TokenType::OpEql:
- return Operator::Eql;
- case TokenType::OpNeq:
- return Operator::Neq;
- case TokenType::OpGeq:
- return Operator::Geq;
- case TokenType::OpLeq:
- return Operator::Leq;
- case TokenType::OpGreater:
- return Operator::Greater;
- case TokenType::OpLess:
- return Operator::Less;
- case TokenType::OpLsh:
- return Operator::Lsh;
- case TokenType::OpRsh:
- return Operator::Rsh;
- case TokenType::OpAdd:
- return Operator::Add;
- case TokenType::OpSub:
- return Operator::Sub;
- case TokenType::OpMul:
- return Operator::Mul;
- case TokenType::OpDiv:
- return Operator::Div;
- case TokenType::OpMod:
- return Operator::Mod;
- case TokenType::OpInc:
- return Operator::PostInc;
- case TokenType::OpDec:
- return Operator::PostDec;
- case TokenType::OpNot:
- return Operator::Not;
- case TokenType::OpBitNot:
- return Operator::BitNot;
- default:
- throw "Illegal TokenType.";
- }
- }
-
static RefPtr<ExpressionSyntaxNode> parseOperator(Parser* parser)
{
Token opToken;
@@ -3194,25 +3167,27 @@ namespace Slang
// but for now we will follow some hueristics.
case TokenType::LParent:
{
- parser->ReadToken(TokenType::LParent);
+ Token openParen = parser->ReadToken(TokenType::LParent);
- RefPtr<ExpressionSyntaxNode> expr;
if (peekTypeName(parser) && parser->LookAheadToken(TokenType::RParent, 1))
{
- RefPtr<TypeCastExpressionSyntaxNode> tcexpr = new TypeCastExpressionSyntaxNode();
+ RefPtr<TypeCastExpressionSyntaxNode> tcexpr = new ExplicitCastExpr();
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;
+ return tcexpr;
}
else
{
- expr = parser->ParseExpression();
+ RefPtr<ExpressionSyntaxNode> base = parser->ParseExpression();
parser->ReadToken(TokenType::RParent);
- }
- return expr;
+ RefPtr<ParenExpr> parenExpr = new ParenExpr();
+ parenExpr->Position = openParen.Position;
+ parenExpr->base = base;
+ return parenExpr;
+ }
}
// An initializer list `{ expr, ... }`
@@ -3476,7 +3451,11 @@ namespace Slang
indexExpr->BaseExpression = expr;
parser->FillPosition(indexExpr.Ptr());
parser->ReadToken(TokenType::LBracket);
- indexExpr->IndexExpression = parser->ParseExpression();
+ // TODO: eventually we may want to support multiple arguments inside the `[]`
+ if (!parser->LookAheadToken(TokenType::RBracket))
+ {
+ indexExpr->IndexExpression = parser->ParseExpression();
+ }
parser->ReadToken(TokenType::RBracket);
expr = indexExpr;
@@ -3539,6 +3518,7 @@ namespace Slang
case TokenType::OpDec:
case TokenType::OpNot:
case TokenType::OpBitNot:
+ case TokenType::OpAdd:
case TokenType::OpSub:
{
RefPtr<PrefixExpr> prefixExpr = new PrefixExpr();
diff --git a/source/slang/slang-stdlib.cpp b/source/slang/slang-stdlib.cpp
index e1bba8885..e2d5829b4 100644
--- a/source/slang/slang-stdlib.cpp
+++ b/source/slang/slang-stdlib.cpp
@@ -7,18 +7,40 @@
#define STRINGIZE2(x) #x
#define LINE_STRING STRINGIZE(__LINE__)
-enum { kLibIncludeStringLine = __LINE__+1 };
-const char * LibIncludeStringChunks[] = { R"=(
+enum { kCoreLibIncludeStringLine = __LINE__ + 1 };
+const char* kCoreLibIncludeStringChunks[] = { R"=(
-typedef uint UINT;
+// A type that can be used as an operand for builtins
+interface __BuiltinType {}
+
+// A type that can be used for arithmetic operations
+interface __BuiltinArithmeticType : __BuiltinType {}
+
+// A type that logically has a sign (positive/negative/zero)
+interface __BuiltinSignedArithmeticType : __BuiltinArithmeticType {}
-__generic<T> __intrinsic_op(Assign) T operator=(out T left, T right);
+// A type that can represent integers
+interface __BuiltinIntegerType : __BuiltinArithmeticType {}
+
+// A type that can represent non-integers
+interface __BuiltinRealType : __BuiltinArithmeticType {}
+
+// A type that uses a floating-point representation
+interface __BuiltinFloatingPointType : __BuiltinRealType, __BuiltinSignedArithmeticType {}
__generic<T,U> __intrinsic_op(Sequence) U operator,(T left, U right);
__generic<T> __intrinsic_op(Select) T operator?:(bool condition, T ifTrue, T ifFalse);
__generic<T, let N : int> __intrinsic_op(Select) vector<T,N> operator?:(vector<bool,N> condition, vector<T,N> ifTrue, vector<T,N> ifFalse);
+)=" };
+
+
+enum { kHLSLLibIncludeStringLine = __LINE__+1 };
+const char * kHLSLLibIncludeStringChunks[] = { R"=(
+
+typedef uint UINT;
+
__generic<T> __magic_type(HLSLAppendStructuredBufferType) struct AppendStructuredBuffer
{
__intrinsic void Append(T value);
@@ -252,24 +274,6 @@ __generic<T> __magic_type(HLSLLineStreamType) struct TriangleStream
// Note(tfoley): Trying to systematically add all the HLSL builtins
-// A type that can be used as an operand for builtins
-interface __BuiltinType {}
-
-// A type that can be used for arithmetic operations
-interface __BuiltinArithmeticType : __BuiltinType {}
-
-// A type that logically has a sign (positive/negative/zero)
-interface __BuiltinSignedArithmeticType : __BuiltinArithmeticType {}
-
-// A type that can represent integers
-interface __BuiltinIntegerType : __BuiltinArithmeticType {}
-
-// A type that can represent non-integers
-interface __BuiltinRealType : __BuiltinArithmeticType {}
-
-// A type that uses a floating-point representation
-interface __BuiltinFloatingPointType : __BuiltinRealType, __BuiltinSignedArithmeticType {}
-
// Try to terminate the current draw or dispatch call (HLSL SM 4.0)
__intrinsic void abort();
@@ -1011,7 +1015,11 @@ namespace Slang
return stdlibPath;
}
- String SlangStdLib::code;
+ // Cached code for the various libraries
+ String coreLibraryCode;
+ String slangLibraryCode;
+ String hlslLibraryCode;
+ String glslLibraryCode;
enum
{
@@ -1029,93 +1037,88 @@ namespace Slang
ANY_MASK = INT_MASK | FLOAT_MASK | BOOL_MASK,
};
- String SlangStdLib::GetCode()
- {
- if (code.Length() > 0)
- return code;
- StringBuilder sb;
-
- // generate operator overloads
-
-
-
- struct OpInfo { IntrinsicOp opCode; char const* opName; unsigned flags; };
-
- OpInfo unaryOps[] = {
- { IntrinsicOp::Neg, "-", ARITHMETIC_MASK },
- { IntrinsicOp::Not, "!", ANY_MASK },
- { IntrinsicOp::BitNot, "~", INT_MASK },
- { IntrinsicOp::PreInc, "++", ARITHMETIC_MASK | ASSIGNMENT },
- { IntrinsicOp::PreDec, "--", ARITHMETIC_MASK | ASSIGNMENT },
- { IntrinsicOp::PostInc, "++", ARITHMETIC_MASK | ASSIGNMENT | POSTFIX },
- { IntrinsicOp::PostDec, "--", ARITHMETIC_MASK | ASSIGNMENT | POSTFIX },
- };
-
- OpInfo binaryOps[] = {
- { IntrinsicOp::Add, "+", ARITHMETIC_MASK },
- { IntrinsicOp::Sub, "-", ARITHMETIC_MASK },
- { IntrinsicOp::Mul, "*", ARITHMETIC_MASK },
- { IntrinsicOp::Div, "/", ARITHMETIC_MASK },
- { IntrinsicOp::Mod, "%", INT_MASK },
-
- { IntrinsicOp::And, "&&", LOGICAL_MASK },
- { IntrinsicOp::Or, "||", LOGICAL_MASK },
-
- { IntrinsicOp::BitAnd, "&", LOGICAL_MASK },
- { IntrinsicOp::BitOr, "|", LOGICAL_MASK },
- { IntrinsicOp::BitXor, "^", LOGICAL_MASK },
+ static const struct {
+ char const* name;
+ BaseType tag;
+ unsigned flags;
+ } kBaseTypes[] = {
+ { "void", BaseType::Void, 0 },
+ { "int", BaseType::Int, SINT_MASK },
+ { "half", BaseType::Half, FLOAT_MASK },
+ { "float", BaseType::Float, FLOAT_MASK },
+ { "double", BaseType::Double, FLOAT_MASK },
+ { "uint", BaseType::UInt, UINT_MASK },
+ { "bool", BaseType::Bool, BOOL_MASK },
+ { "uint64_t", BaseType::UInt64, UINT_MASK },
+ };
- { IntrinsicOp::Lsh, "<<", INT_MASK },
- { IntrinsicOp::Rsh, ">>", INT_MASK },
+ struct OpInfo { IntrinsicOp opCode; char const* opName; unsigned flags; };
+
+ static const OpInfo unaryOps[] = {
+ { IntrinsicOp::Pos, "+", ARITHMETIC_MASK },
+ { IntrinsicOp::Neg, "-", ARITHMETIC_MASK },
+ { IntrinsicOp::Not, "!", ANY_MASK },
+ { IntrinsicOp::BitNot, "~", INT_MASK },
+ { IntrinsicOp::PreInc, "++", ARITHMETIC_MASK | ASSIGNMENT },
+ { IntrinsicOp::PreDec, "--", ARITHMETIC_MASK | ASSIGNMENT },
+ { IntrinsicOp::PostInc, "++", ARITHMETIC_MASK | ASSIGNMENT | POSTFIX },
+ { IntrinsicOp::PostDec, "--", ARITHMETIC_MASK | ASSIGNMENT | POSTFIX },
+ };
- { IntrinsicOp::Eql, "==", ANY_MASK | COMPARISON },
- { IntrinsicOp::Neq, "!=", ANY_MASK | COMPARISON },
+ static const OpInfo binaryOps[] = {
+ { IntrinsicOp::Add, "+", ARITHMETIC_MASK },
+ { IntrinsicOp::Sub, "-", ARITHMETIC_MASK },
+ { IntrinsicOp::Mul, "*", ARITHMETIC_MASK },
+ { IntrinsicOp::Div, "/", ARITHMETIC_MASK },
+ { IntrinsicOp::Mod, "%", INT_MASK },
+
+ { IntrinsicOp::And, "&&", LOGICAL_MASK },
+ { IntrinsicOp::Or, "||", LOGICAL_MASK },
+
+ { IntrinsicOp::BitAnd, "&", LOGICAL_MASK },
+ { IntrinsicOp::BitOr, "|", LOGICAL_MASK },
+ { IntrinsicOp::BitXor, "^", LOGICAL_MASK },
+
+ { IntrinsicOp::Lsh, "<<", INT_MASK },
+ { IntrinsicOp::Rsh, ">>", INT_MASK },
+
+ { IntrinsicOp::Eql, "==", ANY_MASK | COMPARISON },
+ { IntrinsicOp::Neq, "!=", ANY_MASK | COMPARISON },
+
+ { IntrinsicOp::Greater, ">", ARITHMETIC_MASK | COMPARISON },
+ { IntrinsicOp::Less, "<", ARITHMETIC_MASK | COMPARISON },
+ { IntrinsicOp::Geq, ">=", ARITHMETIC_MASK | COMPARISON },
+ { IntrinsicOp::Leq, "<=", ARITHMETIC_MASK | COMPARISON },
+
+ { IntrinsicOp::AddAssign, "+=", ASSIGNMENT | ARITHMETIC_MASK },
+ { IntrinsicOp::SubAssign, "-=", ASSIGNMENT | ARITHMETIC_MASK },
+ { IntrinsicOp::MulAssign, "*=", ASSIGNMENT | ARITHMETIC_MASK },
+ { IntrinsicOp::DivAssign, "/=", ASSIGNMENT | ARITHMETIC_MASK },
+ { IntrinsicOp::ModAssign, "%=", ASSIGNMENT | ARITHMETIC_MASK },
+ { IntrinsicOp::AndAssign, "&=", ASSIGNMENT | LOGICAL_MASK },
+ { IntrinsicOp::OrAssign, "|=", ASSIGNMENT | LOGICAL_MASK },
+ { IntrinsicOp::XorAssign, "^=", ASSIGNMENT | LOGICAL_MASK },
+ { IntrinsicOp::LshAssign, "<<=", ASSIGNMENT | INT_MASK },
+ { IntrinsicOp::RshAssign, ">>=", ASSIGNMENT | INT_MASK },
+ };
- { IntrinsicOp::Greater, ">", ARITHMETIC_MASK | COMPARISON },
- { IntrinsicOp::Less, "<", ARITHMETIC_MASK | COMPARISON },
- { IntrinsicOp::Geq, ">=", ARITHMETIC_MASK | COMPARISON },
- { IntrinsicOp::Leq, "<=", ARITHMETIC_MASK | COMPARISON },
- { IntrinsicOp::AddAssign, "+=", ASSIGNMENT | ARITHMETIC_MASK },
- { IntrinsicOp::SubAssign, "-=", ASSIGNMENT | ARITHMETIC_MASK },
- { IntrinsicOp::MulAssign, "*=", ASSIGNMENT | ARITHMETIC_MASK },
- { IntrinsicOp::DivAssign, "/=", ASSIGNMENT | ARITHMETIC_MASK },
- { IntrinsicOp::ModAssign, "%=", ASSIGNMENT | ARITHMETIC_MASK },
- { IntrinsicOp::AndAssign, "&=", ASSIGNMENT | LOGICAL_MASK },
- { IntrinsicOp::OrAssign, "|=", ASSIGNMENT | LOGICAL_MASK },
- { IntrinsicOp::XorAssign, "^=", ASSIGNMENT | LOGICAL_MASK },
- { IntrinsicOp::LshAssign, "<<=", ASSIGNMENT | INT_MASK },
- { IntrinsicOp::RshAssign, ">>=", ASSIGNMENT | INT_MASK },
+ String getCoreLibraryCode()
+ {
+ if (coreLibraryCode.Length() > 0)
+ return coreLibraryCode;
+ StringBuilder sb;
- };
+ // generate operator overloads
- /*
- String floatTypes[] = { "float", "float2", "float3", "float4" };
- String intTypes[] = { "int", "int2", "int3", "int4" };
- String uintTypes[] = { "uint", "uint2", "uint3", "uint4" };
- */
String path = getStdlibPath();
-
-
#define EMIT_LINE_DIRECTIVE() sb << "#line " << (__LINE__+1) << " \"" << path << "\"\n"
// Generate declarations for all the base types
- static const struct {
- char const* name;
- BaseType tag;
- unsigned flags;
- } kBaseTypes[] = {
- { "void", BaseType::Void, 0 },
- { "int", BaseType::Int, SINT_MASK },
- { "float", BaseType::Float, FLOAT_MASK },
- { "uint", BaseType::UInt, UINT_MASK },
- { "bool", BaseType::Bool, BOOL_MASK },
- { "uint64_t", BaseType::UInt64, UINT_MASK },
- };
static const int kBaseTypeCount = sizeof(kBaseTypes) / sizeof(kBaseTypes[0]);
for (int tt = 0; tt < kBaseTypeCount; ++tt)
{
@@ -1126,7 +1129,7 @@ namespace Slang
sb << "\n : __BuiltinType\n";
- switch( kBaseTypes[tt].tag )
+ switch (kBaseTypes[tt].tag)
{
case BaseType::Float:
sb << "\n , __BuiltinFloatingPointType\n";
@@ -1151,9 +1154,9 @@ namespace Slang
// Declare initializers to convert from various other types
- for( int ss = 0; ss < kBaseTypeCount; ++ss )
+ for (int ss = 0; ss < kBaseTypeCount; ++ss)
{
- if( kBaseTypes[ss].tag == BaseType::Void )
+ if (kBaseTypes[ss].tag == BaseType::Void)
continue;
EMIT_LINE_DIRECTIVE();
@@ -1163,12 +1166,6 @@ namespace Slang
sb << "};\n";
}
- // Declare ad hoc aliases for some types, just to get things compiling
- //
- // TODO(tfoley): At the very least, `double` should be treated as a distinct type.
- sb << "typedef float double;\n";
- sb << "typedef float half;\n";
-
// Declare vector and matrix types
sb << "__generic<T = float, let N : int = 4> __magic_type(Vector) struct vector\n{\n";
@@ -1205,6 +1202,12 @@ namespace Slang
}
}
+ // 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";
+
+
static const char* kComponentNames[]{ "x", "y", "z", "w" };
static const char* kVectorNames[]{ "", "x", "xy", "xyz", "xyzw" };
@@ -1292,7 +1295,6 @@ namespace Slang
sb << "}\n";
}
-
// Declare built-in texture and sampler types
sb << "__magic_type(SamplerState," << int(SamplerStateType::Flavor::SamplerState) << ") struct SamplerState {};";
@@ -1372,11 +1374,11 @@ namespace Slang
for(int isFloat = 0; isFloat < 2; ++isFloat)
for(int includeMipInfo = 0; includeMipInfo < 2; ++includeMipInfo)
{
- char const* t = isFloat ? "out float " : "out UINT ";
+ char const* t = isFloat ? "out float " : "out uint ";
sb << "void GetDimensions(";
if(includeMipInfo)
- sb << "UINT mipLevel, ";
+ sb << "uint mipLevel, ";
switch(baseShape)
{
@@ -1671,27 +1673,6 @@ namespace Slang
}
}
- // 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";
-
- sb << "__generic<T> __magic_type(PackedBuffer) struct PackedBuffer {};\n";
- sb << "__generic<T> __magic_type(Uniform) struct Uniform {};\n";
- sb << "__generic<T> __magic_type(Patch) struct Patch {};\n";
-
-
- // Stale declarations for GLSL inner-product builtins
-#if 0
- sb << "__intrinsic vec3 operator * (vec3, mat3);\n";
- sb << "__intrinsic vec3 operator * (mat3, vec3);\n";
-
- sb << "__intrinsic vec4 operator * (vec4, mat4);\n";
- sb << "__intrinsic vec4 operator * (mat4, vec4);\n";
-
- sb << "__intrinsic mat3 operator * (mat3, mat3);\n";
- sb << "__intrinsic mat4 operator * (mat4, mat4);\n";
-#endif
for (auto op : unaryOps)
{
@@ -1745,29 +1726,93 @@ namespace Slang
sb << "__intrinsic_op(" << int(op.opCode) << ") vector<" << resultType << ",N> operator" << op.opName << "(" << leftQual << "vector<" << leftType << ",N> left, vector<" << rightType << ",N> right);\n";
// matrix version
+
+ // skip matrix-matrix multiply operations here, so that GLSL doesn't see them
+ switch (op.opCode)
+ {
+ case IntrinsicOp::Mul:
+ case IntrinsicOp::MulAssign:
+ break;
+
+ default:
+ sb << "__generic<let N : int, let M : int> ";
+ sb << "__intrinsic_op(" << int(op.opCode) << ") matrix<" << resultType << ",N,M> operator" << op.opName << "(" << leftQual << "matrix<" << leftType << ",N,M> left, matrix<" << rightType << ",N,M> right);\n";
+ break;
+ }
+ }
+ }
+
+ // Output a suitable `#line` directive to point at our raw stdlib code above
+ sb << "\n#line " << kCoreLibIncludeStringLine << " \"" << path << "\"\n";
+
+ int chunkCount = sizeof(kCoreLibIncludeStringChunks) / sizeof(kCoreLibIncludeStringChunks[0]);
+ for (int cc = 0; cc < chunkCount; ++cc)
+ {
+ sb << kCoreLibIncludeStringChunks[cc];
+ }
+
+ coreLibraryCode = sb.ProduceString();
+ return coreLibraryCode;
+ }
+
+ String getHLSLLibraryCode()
+ {
+ if (hlslLibraryCode.Length() > 0)
+ return hlslLibraryCode;
+
+ StringBuilder sb;
+
+
+// sb << "__generic<T> __magic_type(PackedBuffer) struct PackedBuffer {};\n";
+// sb << "__generic<T> __magic_type(Uniform) struct Uniform {};\n";
+// sb << "__generic<T> __magic_type(Patch) struct Patch {};\n";
+
+ // Component-wise multiplication ops
+ for(auto op : binaryOps)
+ {
+ switch (op.opCode)
+ {
+ default:
+ continue;
+
+ case IntrinsicOp::Mul:
+ case IntrinsicOp::MulAssign:
+ break;
+ }
+
+ for (auto type : kBaseTypes)
+ {
+ if ((type.flags & op.flags) == 0)
+ continue;
+
+ char const* leftType = type.name;
+ char const* rightType = leftType;
+ char const* resultType = leftType;
+
+ char const* leftQual = "";
+ if(op.flags & ASSIGNMENT) leftQual = "in out ";
+
sb << "__generic<let N : int, let M : int> ";
sb << "__intrinsic_op(" << int(op.opCode) << ") matrix<" << resultType << ",N,M> operator" << op.opName << "(" << leftQual << "matrix<" << leftType << ",N,M> left, matrix<" << rightType << ",N,M> right);\n";
}
}
// Output a suitable `#line` directive to point at our raw stdlib code above
- sb << "\n#line " << kLibIncludeStringLine << " \"" << path << "\"\n";
+ sb << "\n#line " << kHLSLLibIncludeStringLine << " \"" << getStdlibPath() << "\"\n";
- int chunkCount = sizeof(LibIncludeStringChunks) / sizeof(LibIncludeStringChunks[0]);
+ int chunkCount = sizeof(kHLSLLibIncludeStringChunks) / sizeof(kHLSLLibIncludeStringChunks[0]);
for (int cc = 0; cc < chunkCount; ++cc)
{
- sb << LibIncludeStringChunks[cc];
+ sb << kHLSLLibIncludeStringChunks[cc];
}
- code = sb.ProduceString();
- return code;
+ hlslLibraryCode = sb.ProduceString();
+ return hlslLibraryCode;
}
// GLSL-specific library code
- String glslLibraryCode;
-
String getGLSLLibraryCode()
{
if(glslLibraryCode.Length() != 0)
@@ -1794,16 +1839,42 @@ namespace Slang
// Declare GLSL aliases for HLSL types
for (int vv = 2; vv <= 4; ++vv)
{
- sb << "typedef " << kTypes[tt].name << vv << " " << kTypes[tt].glslPrefix << "vec" << vv << ";\n";
- sb << "typedef " << kTypes[tt].name << vv << "x" << vv << " " << kTypes[tt].glslPrefix << "mat" << vv << ";\n";
+ sb << "typedef vector<" << kTypes[tt].name << "," << vv << "> " << kTypes[tt].glslPrefix << "vec" << vv << ";\n";
+ sb << "typedef matrix<" << kTypes[tt].name << "," << vv << "," << vv << "> " << kTypes[tt].glslPrefix << "mat" << vv << ";\n";
}
for (int rr = 2; rr <= 4; ++rr)
for (int cc = 2; cc <= 4; ++cc)
{
- sb << "typedef " << kTypes[tt].name << rr << "x" << cc << " " << kTypes[tt].glslPrefix << "mat" << rr << "x" << cc << ";\n";
+ sb << "typedef matrix<" << kTypes[tt].name << "," << rr << "," << cc << "> " << kTypes[tt].glslPrefix << "mat" << rr << "x" << cc << ";\n";
}
}
+ // Multiplication operations for vectors + matrices
+
+ // scalar-vector and vector-scalar
+ sb << "__generic<T : __BuiltinArithmeticType, let N : int> __intrinsic_op(Mul) vector<T,N> operator*(vector<T,N> x, T y);\n";
+ sb << "__generic<T : __BuiltinArithmeticType, let N : int> __intrinsic_op(Mul) vector<T,N> operator*(T x, vector<T,N> y);\n";
+
+ // scalar-matrix and matrix-scalar
+ sb << "__generic<T : __BuiltinArithmeticType, let N : int, let M :int> __intrinsic_op(Mul) matrix<T,N,M> operator*(matrix<T,N,M> x, T y);\n";
+ sb << "__generic<T : __BuiltinArithmeticType, let N : int, let M :int> __intrinsic_op(Mul) matrix<T,N,M> operator*(T x, matrix<T,N,M> y);\n";
+
+ // vector-vector (dot product)
+ sb << "__generic<T : __BuiltinArithmeticType, let N : int> __intrinsic_op(Mul) T operator*(vector<T,N> x, vector<T,N> y);\n";
+
+ // vector-matrix
+ sb << "__generic<T : __BuiltinArithmeticType, let N : int, let M : int> __intrinsic_op(Mul) vector<T,M> operator*(vector<T,N> x, matrix<T,N,M> y);\n";
+
+ // matrix-vector
+ sb << "__generic<T : __BuiltinArithmeticType, let N : int, let M : int> __intrinsic_op(Mul) vector<T,N> operator*(matrix<T,N,M> x, vector<T,M> y);\n";
+
+ // matrix-matrix
+ sb << "__generic<T : __BuiltinArithmeticType, let R : int, let N : int, let C : int> __intrinsic_op(Mul) matrix<T,R,C> operator*(matrix<T,R,N> x, matrix<T,N,C> y);\n";
+
+
+
+ //
+
// TODO(tfoley): Need to handle `RW*` variants of texture types as well...
static const struct {
char const* name;
@@ -1909,6 +1980,7 @@ namespace Slang
sb << "__modifier(GLSLPatchModifier) patch;\n";
sb << "__modifier(SimpleModifier) flat;\n";
+ sb << "__modifier(SimpleModifier) highp;\n";
glslLibraryCode = sb.ProduceString();
return glslLibraryCode;
@@ -1918,10 +1990,12 @@ namespace Slang
//
- void SlangStdLib::Finalize()
+ void finalizeShaderLibrary()
{
- code = String();
stdlibPath = String();
+
+ coreLibraryCode = String();
+ hlslLibraryCode = String();
glslLibraryCode = String();
}
diff --git a/source/slang/slang-stdlib.h b/source/slang/slang-stdlib.h
index e4ee8cee3..d21b1e7f1 100644
--- a/source/slang/slang-stdlib.h
+++ b/source/slang/slang-stdlib.h
@@ -5,16 +5,11 @@
namespace Slang
{
- class SlangStdLib
- {
- private:
- static String code;
- public:
- static String GetCode();
- static void Finalize();
- };
-
+ String getCoreLibraryCode();
+ String getHLSLLibraryCode();
String getGLSLLibraryCode();
+
+ void finalizeShaderLibrary();
}
#endif \ No newline at end of file
diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp
index c4944c5a4..e5bfcb923 100644
--- a/source/slang/slang.cpp
+++ b/source/slang/slang.cpp
@@ -25,8 +25,9 @@ public:
bool useCache = false;
String cacheDir;
- RefPtr<Scope> slangLanguageScope;
+ RefPtr<Scope> coreLanguageScope;
RefPtr<Scope> hlslLanguageScope;
+ RefPtr<Scope> slangLanguageScope;
RefPtr<Scope> glslLanguageScope;
List<RefPtr<ProgramSyntaxNode>> loadedModuleCode;
@@ -43,15 +44,19 @@ public:
// TODO: load these on-demand to avoid parsing
// stdlib code for languages the user won't use.
- slangLanguageScope = new Scope();
+ coreLanguageScope = new Scope();
hlslLanguageScope = new Scope();
- hlslLanguageScope->parent = slangLanguageScope;
+ hlslLanguageScope->nextSibling = coreLanguageScope;
+
+ slangLanguageScope = new Scope();
+ slangLanguageScope->nextSibling = hlslLanguageScope;
glslLanguageScope = new Scope();
- glslLanguageScope->parent = slangLanguageScope;
+ glslLanguageScope->nextSibling = coreLanguageScope;
- addBuiltinSource(slangLanguageScope, "stdlib", SlangStdLib::GetCode());
+ addBuiltinSource(coreLanguageScope, "core", getCoreLibraryCode());
+ addBuiltinSource(hlslLanguageScope, "hlsl", getHLSLLibraryCode());
addBuiltinSource(glslLanguageScope, "glsl", getGLSLLibraryCode());
}
@@ -61,7 +66,7 @@ public:
// code that we might have allocated and loaded into static
// variables (TODO: don't use `static` variables for this stuff)
- SlangStdLib::Finalize();
+ finalizeShaderLibrary();
// Ditto for our type represnetation stuff
diff --git a/source/slang/stmt-defs.h b/source/slang/stmt-defs.h
index c5bcda63b..9dea40fbf 100644
--- a/source/slang/stmt-defs.h
+++ b/source/slang/stmt-defs.h
@@ -16,6 +16,8 @@ SYNTAX_CLASS(BlockStmt, ScopeStmt)
SYNTAX_FIELD(RefPtr<StatementSyntaxNode>, body);
END_SYNTAX_CLASS()
+// A statement that we aren't going to parse or check, because
+// we want to let a downstream compiler handle any issues
SYNTAX_CLASS(UnparsedStmt, StatementSyntaxNode)
// The tokens that were contained between `{` and `}`
FIELD(List<Token>, tokens)
@@ -71,6 +73,7 @@ SIMPLE_SYNTAX_CLASS(DefaultStmt, CaseStmtBase)
ABSTRACT_SYNTAX_CLASS(LoopStmt, BreakableStmt)
END_SYNTAX_CLASS()
+// A `for` statement
SYNTAX_CLASS(ForStatementSyntaxNode, LoopStmt)
SYNTAX_FIELD(RefPtr<StatementSyntaxNode>, InitialStatement)
SYNTAX_FIELD(RefPtr<ExpressionSyntaxNode>, SideEffectExpression)
@@ -78,6 +81,10 @@ SYNTAX_CLASS(ForStatementSyntaxNode, LoopStmt)
SYNTAX_FIELD(RefPtr<StatementSyntaxNode>, Statement)
END_SYNTAX_CLASS()
+// A `for` statement in a language that doesn't restrict the scope
+// of the loop variable to the body.
+SYNTAX_CLASS(UnscopedForStmt, ForStatementSyntaxNode);
+END_SYNTAX_CLASS()
SYNTAX_CLASS(WhileStatementSyntaxNode, LoopStmt)
SYNTAX_FIELD(RefPtr<ExpressionSyntaxNode>, Predicate)
diff --git a/source/slang/syntax.h b/source/slang/syntax.h
index 1704c1224..de5467c71 100644
--- a/source/slang/syntax.h
+++ b/source/slang/syntax.h
@@ -176,6 +176,7 @@ namespace Slang
Int,
UInt,
UInt64,
+ Half,
Float,
Double,
};
@@ -690,22 +691,6 @@ namespace Slang
LookupMask mask = LookupMask::All;
};
- enum class Operator
- {
- Neg, Not, BitNot, PreInc, PreDec, PostInc, PostDec,
- Mul, Div, Mod,
- Add, Sub,
- Lsh, Rsh,
- Eql, Neq, Greater, Less, Geq, Leq,
- BitAnd, BitXor, BitOr,
- And,
- Or,
- Sequence,
- Select,
- Assign = 200, AddAssign, SubAssign, MulAssign, DivAssign, ModAssign,
- LshAssign, RshAssign, OrAssign, AndAssign, XorAssign,
- };
-
// Generate class definition for all syntax classes
#define SYNTAX_FIELD(TYPE, NAME) TYPE NAME;
#define FIELD(TYPE, NAME) TYPE NAME;