diff options
| -rw-r--r-- | source/slang/check.cpp | 419 | ||||
| -rw-r--r-- | source/slang/emit.cpp | 166 | ||||
| -rw-r--r-- | source/slang/expr-defs.h | 10 | ||||
| -rw-r--r-- | source/slang/intrinsic-defs.h | 1 | ||||
| -rw-r--r-- | source/slang/lexer.cpp | 6 | ||||
| -rw-r--r-- | source/slang/lower.cpp | 11 | ||||
| -rw-r--r-- | source/slang/parser.cpp | 185 | ||||
| -rw-r--r-- | source/slang/slang-stdlib.cpp | 356 | ||||
| -rw-r--r-- | source/slang/slang-stdlib.h | 13 | ||||
| -rw-r--r-- | source/slang/slang.cpp | 17 | ||||
| -rw-r--r-- | source/slang/stmt-defs.h | 5 | ||||
| -rw-r--r-- | source/slang/syntax.h | 17 |
12 files changed, 647 insertions, 559 deletions
diff --git a/source/slang/check.cpp b/source/slang/check.cpp index 7c67473be..f21f9480c 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,7 @@ namespace Slang RefPtr<ExpressionType> toType, RefPtr<ExpressionSyntaxNode> fromExpr) { - auto castExpr = new TypeCastExpressionSyntaxNode(); + auto castExpr = new ImplicitCastExpr(); castExpr->Position = fromExpr->Position; castExpr->TargetType.type = toType; castExpr->Type = QualType(toType); @@ -980,6 +995,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 +1009,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 +1021,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 +1060,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 +1148,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 +1167,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 +1535,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 +1552,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 +1577,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 +1599,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 +1661,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 +1673,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 +1745,10 @@ namespace Slang if (!switchStmt) { - getSink()->diagnose(stmt, Diagnostics::caseOutsideSwitch); + if (!isRewriteMode()) + { + getSink()->diagnose(stmt, Diagnostics::caseOutsideSwitch); + } } else { @@ -1707,7 +1764,10 @@ namespace Slang auto switchStmt = FindOuterStmt<SwitchStmt>(); if (!switchStmt) { - getSink()->diagnose(stmt, Diagnostics::defaultOutsideSwitch); + if (!isRewriteMode()) + { + getSink()->diagnose(stmt, Diagnostics::defaultOutsideSwitch); + } } stmt->parentStmt = switchStmt; } @@ -1718,12 +1778,6 @@ namespace Slang checkStmt(stmt->NegativeStatement); } - void visitUnparsedStmt(UnparsedStmt*) - { - // Nothing to do - } - - void visitEmptyStatementSyntaxNode(EmptyStatementSyntaxNode*) { // Nothing to do @@ -1739,7 +1793,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 +1891,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 +1915,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) { @@ -2160,7 +2227,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 +2247,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 +2393,10 @@ namespace Slang fail: { - getSink()->diagnose(subscriptExpr, Diagnostics::subscriptNonArray, baseType); + if (!isRewriteMode()) + { + getSink()->diagnose(subscriptExpr, Diagnostics::subscriptNonArray, baseType); + } return CreateErrorExpr(subscriptExpr); } } @@ -2419,6 +2495,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 +2517,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 +2549,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 +2561,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 +3168,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 +3201,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 +3217,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 +3418,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 +4333,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 +4386,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 +4405,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 +4455,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 +4553,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 +4587,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 +4643,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 +4688,10 @@ namespace Slang expr); } - getSink()->diagnose(expr, Diagnostics::undefinedIdentifier2, expr->name); + if (!isRewriteMode()) + { + getSink()->diagnose(expr, Diagnostics::undefinedIdentifier2, expr->name); + } return expr; } @@ -4651,32 +4732,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 +4833,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 +4847,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 +4874,7 @@ namespace Slang if (anyError) { - swizExpr->Type = QualType(ExpressionType::Error); + return CreateErrorExpr(memberRefExpr); } else if (elementCount == 1) { @@ -4844,7 +4912,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 +4999,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 +5014,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..830ff6d97 100644 --- a/source/slang/emit.cpp +++ b/source/slang/emit.cpp @@ -238,7 +238,9 @@ struct EmitVisitor if (isReservedWord(name)) { - name = name + "_"; + // TODO(tfoley): Need to put this back in, as part of lowering. + +// name = name + "_"; } advanceToSourceLocation(loc); @@ -970,6 +972,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>()) { @@ -1308,6 +1318,13 @@ struct EmitVisitor if(needClose) Emit(")"); } + void visitParenExpr(ParenExpr* expr, ExprEmitArg const& arg) + { + Emit("("); + EmitExpr(expr->base); + Emit(")"); + } + void visitAssignExpr(AssignExpr* assignExpr, ExprEmitArg const& arg) { auto outerPrec = arg.outerPrec; @@ -1318,6 +1335,64 @@ struct EmitVisitor 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>() ) + { + EmitBinExpr( + outerPrec, + kPrecedence_Comma, + funcName.Buffer(), + callExpr); + } + else if( auto prefixExpr = callExpr.As<PrefixExpr>() ) + { + EmitUnaryExpr( + outerPrec, + kPrecedence_Prefix, + funcName.Buffer(), + "", + callExpr); + } + else if(auto postfixExpr = callExpr.As<PostfixExpr>()) + { + EmitUnaryExpr( + outerPrec, + kPrecedence_Postfix, + "", + funcName.Buffer(), + callExpr); + } + else + { + bool needClose = MaybeEmitParens(outerPrec, kPrecedence_Postfix); + + auto funcExpr = callExpr->FunctionExpr; + 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,39 +1406,7 @@ 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>()) @@ -1408,6 +1451,7 @@ struct EmitVisitor case IntrinsicOp::Sequence: EmitBinExpr(outerPrec, kPrecedence_Comma, ",", callExpr); return; #define CASE(NAME, OP) case IntrinsicOp::NAME: EmitUnaryExpr(outerPrec, kPrecedence_Prefix, #OP, "", callExpr); return + CASE(Pos, +); CASE(Neg, -); CASE(Not, !); CASE(BitNot, ~); @@ -1603,6 +1647,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); @@ -1633,7 +1682,16 @@ struct EmitVisitor 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(")"); } @@ -1655,14 +1713,17 @@ struct EmitVisitor if(needClose) Emit(")"); } - void visitIndexExpressionSyntaxNode(IndexExpressionSyntaxNode* indexExpr, ExprEmitArg const& arg) + void visitIndexExpressionSyntaxNode(IndexExpressionSyntaxNode* subscriptExpr, ExprEmitArg const& arg) { auto outerPrec = arg.outerPrec; bool needClose = MaybeEmitParens(outerPrec, kPrecedence_Postfix); - EmitExprWithPrecedence(indexExpr->BaseExpression, kPrecedence_Postfix); + EmitExprWithPrecedence(subscriptExpr->BaseExpression, kPrecedence_Postfix); Emit("["); - EmitExpr(indexExpr->IndexExpression); + if (auto indexExpr = subscriptExpr->IndexExpression) + { + EmitExpr(indexExpr); + } Emit("]"); if(needClose) Emit(")"); @@ -1696,7 +1757,7 @@ struct EmitVisitor } else { - emitName(varExpr->name); + emit(varExpr->name); } if(needClose) Emit(")"); @@ -1777,6 +1838,16 @@ struct EmitVisitor void visitTypeCastExpressionSyntaxNode(TypeCastExpressionSyntaxNode* castExpr, ExprEmitArg const& arg) { + if (context->isRewrite) + { + if (dynamic_cast<ImplicitCastExpr*>(castExpr)) + { + // This was an implicit cast, so don't try to output it + EmitExprWithPrecedence(castExpr->Expression, arg.outerPrec); + return; + } + } + bool needClose = false; switch(context->shared->target) { @@ -1858,18 +1929,6 @@ struct EmitVisitor } } - - void EmitUnparsedStmt(RefPtr<UnparsedStmt> stmt) - { - // TODO: actually emit the tokens that made up the statement... - Emit("{\n"); - for( auto& token : stmt->tokens ) - { - emitTokenWithLocation(token); - } - Emit("}\n"); - } - void EmitStmt(RefPtr<StatementSyntaxNode> stmt) { // Try to ensure that debugging can find the right location @@ -1888,11 +1947,6 @@ struct EmitVisitor } return; } - else if( auto unparsedStmt = stmt.As<UnparsedStmt>() ) - { - EmitUnparsedStmt(unparsedStmt); - return; - } else if (auto exprStmt = stmt.As<ExpressionStatementSyntaxNode>()) { EmitExpr(exprStmt->Expression); diff --git a/source/slang/expr-defs.h b/source/slang/expr-defs.h index ca5bfacb8..5ca6629b9 100644 --- a/source/slang/expr-defs.h +++ b/source/slang/expr-defs.h @@ -96,6 +96,9 @@ SYNTAX_CLASS(TypeCastExpressionSyntaxNode, ExpressionSyntaxNode) SYNTAX_FIELD(RefPtr<ExpressionSyntaxNode>, Expression) END_SYNTAX_CLASS() +SYNTAX_CLASS(ImplicitCastExpr, TypeCastExpressionSyntaxNode) +END_SYNTAX_CLASS() + SIMPLE_SYNTAX_CLASS(SelectExpressionSyntaxNode, OperatorExpressionSyntaxNode) SIMPLE_SYNTAX_CLASS(GenericAppExpr, AppExprBase) @@ -112,3 +115,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..c154c96c8 100644 --- a/source/slang/lower.cpp +++ b/source/slang/lower.cpp @@ -451,6 +451,7 @@ struct LoweringVisitor lowerExprCommon(loweredExpr, expr); loweredExpr->BaseExpression = loweredBase; loweredExpr->declRef = loweredDeclRef; + loweredExpr->name = expr->name; return loweredExpr; } @@ -687,16 +688,6 @@ struct LoweringVisitor addStmt(loweredStmt); } - void visitUnparsedStmt(UnparsedStmt* stmt) - { - RefPtr<UnparsedStmt> loweredStmt = new UnparsedStmt(); - lowerStmtFields(loweredStmt, stmt); - - loweredStmt->tokens = stmt->tokens; - - addStmt(loweredStmt); - } - void visitCaseStmt(CaseStmt* stmt) { RefPtr<CaseStmt> loweredStmt = new CaseStmt(); diff --git a/source/slang/parser.cpp b/source/slang/parser.cpp index b134f9645..2056bf809 100644 --- a/source/slang/parser.cpp +++ b/source/slang/parser.cpp @@ -1392,6 +1392,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 +1453,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,50 +2599,6 @@ namespace Slang RefPtr<StatementSyntaxNode> Parser::ParseBlockStatement() { - if( translationUnit->compileFlags & SLANG_COMPILE_FLAG_NO_CHECKING ) - { - // We have been asked to parse the input, but not attempt to understand it. - - // TODO: record start/end locations... - - List<Token> tokens; - - ReadToken(TokenType::LBrace); - - int depth = 1; - for( ;;) - { - switch( tokenReader.PeekTokenType() ) - { - case TokenType::EndOfFile: - goto done; - - case TokenType::RBrace: - depth--; - if(depth == 0) - goto done; - break; - - case TokenType::LBrace: - depth++; - break; - - default: - break; - } - - auto token = tokenReader.AdvanceToken(); - tokens.Add(token); - } - done: - ReadToken(TokenType::RBrace); - - RefPtr<UnparsedStmt> unparsedStmt = new UnparsedStmt(); - unparsedStmt->tokens = tokens; - return unparsedStmt; - } - - RefPtr<ScopeDecl> scopeDecl = new ScopeDecl(); RefPtr<BlockStmt> blockStatement = new BlockStmt(); blockStatement->scopeDecl = scopeDecl; @@ -2816,19 +2799,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 +2886,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,9 +3088,8 @@ 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(); @@ -3204,15 +3097,18 @@ namespace Slang 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 +3372,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 +3439,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..165ffea83 100644 --- a/source/slang/stmt-defs.h +++ b/source/slang/stmt-defs.h @@ -16,11 +16,6 @@ SYNTAX_CLASS(BlockStmt, ScopeStmt) SYNTAX_FIELD(RefPtr<StatementSyntaxNode>, body); END_SYNTAX_CLASS() -SYNTAX_CLASS(UnparsedStmt, StatementSyntaxNode) - // The tokens that were contained between `{` and `}` - FIELD(List<Token>, tokens) -END_SYNTAX_CLASS() - SIMPLE_SYNTAX_CLASS(EmptyStatementSyntaxNode, StatementSyntaxNode) SIMPLE_SYNTAX_CLASS(DiscardStatementSyntaxNode, StatementSyntaxNode) 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; |
