summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEllie Hermaszewska <ellieh@nvidia.com>2025-05-07 07:43:45 +0800
committerGitHub <noreply@github.com>2025-05-07 07:43:45 +0800
commit90ecf185a742efffc7e1fcf399961289b3e00d08 (patch)
tree755d79605c845576e87d6deef0e9846e4e1c62d2
parentcf8e75fae7702855b3d81ed11b2fb480c31a7fde (diff)
Output default parameter values on language server hover (#6902)
* Output default parameter values on language server hover Closes https://github.com/shader-slang/slang/issues/5782 * Add parens around binay expressions in ast print * More cases in ast print test * format code --------- Co-authored-by: slangbot <186143334+slangbot@users.noreply.github.com>
-rw-r--r--source/slang/slang-ast-print.cpp1054
-rw-r--r--source/slang/slang-ast-print.h4
-rw-r--r--source/slang/slang-language-server.cpp3
-rw-r--r--tests/language-server/default-values.slang13
-rw-r--r--tests/language-server/default-values.slang.expected.txt9
5 files changed, 1082 insertions, 1 deletions
diff --git a/source/slang/slang-ast-print.cpp b/source/slang/slang-ast-print.cpp
index 597a35f4b..7b239c88c 100644
--- a/source/slang/slang-ast-print.cpp
+++ b/source/slang/slang-ast-print.cpp
@@ -74,6 +74,1054 @@ void ASTPrinter::addType(Type* type)
type->toText(m_builder);
}
+void ASTPrinter::addExpr(Expr* expr)
+{
+ if (!expr)
+ {
+ m_builder << "<error>";
+ return;
+ }
+
+ auto& sb = m_builder;
+
+ if (const auto incompleteExpr = as<IncompleteExpr>(expr))
+ {
+ sb << "<incomplete>";
+ }
+ else if (const auto varExpr = as<VarExpr>(expr))
+ {
+ if (varExpr->declRef)
+ {
+ addDeclPath(varExpr->declRef);
+ }
+ else if (varExpr->name)
+ {
+ sb << varExpr->name->text;
+ }
+ else
+ {
+ sb << "<unknown-var>";
+ }
+ }
+ else if (const auto memberExpr = as<MemberExpr>(expr))
+ {
+ if (memberExpr->baseExpression)
+ {
+ addExpr(memberExpr->baseExpression);
+ sb << ".";
+ }
+
+ if (memberExpr->declRef)
+ {
+ _addDeclName(memberExpr->declRef.getDecl());
+ }
+ else if (memberExpr->name)
+ {
+ sb << memberExpr->name->text;
+ }
+ else
+ {
+ sb << "<unknown-member>";
+ }
+ }
+ else if (const auto staticMemberExpr = as<StaticMemberExpr>(expr))
+ {
+ if (staticMemberExpr->baseExpression)
+ {
+ addExpr(staticMemberExpr->baseExpression);
+ sb << "::";
+ }
+
+ if (staticMemberExpr->declRef)
+ {
+ _addDeclName(staticMemberExpr->declRef.getDecl());
+ }
+ else if (staticMemberExpr->name)
+ {
+ sb << staticMemberExpr->name->text;
+ }
+ else
+ {
+ sb << "<unknown-static-member>";
+ }
+ }
+ else if (const auto derefMemberExpr = as<DerefMemberExpr>(expr))
+ {
+ if (derefMemberExpr->baseExpression)
+ {
+ addExpr(derefMemberExpr->baseExpression);
+ sb << "->";
+ }
+
+ if (derefMemberExpr->declRef)
+ {
+ _addDeclName(derefMemberExpr->declRef.getDecl());
+ }
+ else if (derefMemberExpr->name)
+ {
+ sb << derefMemberExpr->name->text;
+ }
+ else
+ {
+ sb << "<unknown-deref-member>";
+ }
+ }
+ else if (const auto intLit = as<IntegerLiteralExpr>(expr))
+ {
+ sb << intLit->value;
+ // Handle suffix types without using getBaseTypeName
+ switch (intLit->suffixType)
+ {
+ case BaseType::Int:
+ // No suffix for default int
+ break;
+ case BaseType::UInt:
+ sb << "u";
+ break;
+ case BaseType::Int64:
+ sb << "l";
+ break;
+ case BaseType::UInt64:
+ sb << "ul";
+ break;
+ case BaseType::Int16:
+ sb << "s";
+ break;
+ case BaseType::UInt16:
+ sb << "us";
+ break;
+ case BaseType::Int8:
+ sb << "b";
+ break;
+ case BaseType::UInt8:
+ sb << "ub";
+ break;
+ default:
+ // Don't add a suffix for other types
+ break;
+ }
+ }
+ else if (const auto floatLit = as<FloatingPointLiteralExpr>(expr))
+ {
+ sb << floatLit->value;
+ // Handle suffix types without using getBaseTypeName
+ switch (floatLit->suffixType)
+ {
+ case BaseType::Float:
+ sb << "f";
+ break;
+ case BaseType::Double:
+ // No suffix for default double
+ break;
+ case BaseType::Half:
+ sb << "h";
+ break;
+ default:
+ // Don't add a suffix for other types
+ break;
+ }
+ }
+ else if (const auto boolLit = as<BoolLiteralExpr>(expr))
+ {
+ sb << (boolLit->value ? "true" : "false");
+ }
+ else if (as<NullPtrLiteralExpr>(expr))
+ {
+ sb << "nullptr";
+ }
+ else if (as<NoneLiteralExpr>(expr))
+ {
+ sb << "none";
+ }
+ else if (const auto stringLit = as<StringLiteralExpr>(expr))
+ {
+ sb << "\"" << stringLit->value << "\"";
+ }
+ else if (const auto initList = as<InitializerListExpr>(expr))
+ {
+ sb << "{";
+ bool first = true;
+ for (auto arg : initList->args)
+ {
+ if (!first)
+ sb << ", ";
+ addExpr(arg);
+ first = false;
+ }
+ sb << "}";
+ }
+ else if (const auto arrayLengthExpr = as<GetArrayLengthExpr>(expr))
+ {
+ if (arrayLengthExpr->arrayExpr)
+ {
+ addExpr(arrayLengthExpr->arrayExpr);
+ sb << ".Length";
+ }
+ else
+ {
+ sb << "<unknown-array-length>";
+ }
+ }
+ else if (const auto expandExpr = as<ExpandExpr>(expr))
+ {
+ sb << "...";
+ if (expandExpr->baseExpr)
+ {
+ addExpr(expandExpr->baseExpr);
+ }
+ }
+ else if (const auto eachExpr = as<EachExpr>(expr))
+ {
+ sb << "each ";
+ if (eachExpr->baseExpr)
+ {
+ addExpr(eachExpr->baseExpr);
+ }
+ }
+ else if (const auto aggTypeCtorExpr = as<AggTypeCtorExpr>(expr))
+ {
+ addType(aggTypeCtorExpr->base.type);
+ sb << "(";
+ bool first = true;
+ for (auto arg : aggTypeCtorExpr->arguments)
+ {
+ if (!first)
+ sb << ", ";
+ addExpr(arg);
+ first = false;
+ }
+ sb << ")";
+ }
+ else if (const auto invokeExpr = as<InvokeExpr>(expr))
+ {
+ if (const auto operatorExpr = as<OperatorExpr>(invokeExpr))
+ {
+ if (const auto infixExpr = as<InfixExpr>(operatorExpr))
+ {
+ // Binary operator
+ if (invokeExpr->arguments.getCount() == 2)
+ {
+ sb << "(";
+ addExpr(invokeExpr->arguments[0]);
+ if (operatorExpr->functionExpr && as<VarExpr>(operatorExpr->functionExpr) &&
+ as<VarExpr>(operatorExpr->functionExpr)->name)
+ {
+ sb << " " << as<VarExpr>(operatorExpr->functionExpr)->name->text << " ";
+ }
+ else
+ {
+ sb << " <op> ";
+ }
+ addExpr(invokeExpr->arguments[1]);
+ sb << ")";
+ return;
+ }
+ }
+ else if (const auto prefixExpr = as<PrefixExpr>(operatorExpr))
+ {
+ // Prefix operator
+ if (operatorExpr->functionExpr && as<VarExpr>(operatorExpr->functionExpr) &&
+ as<VarExpr>(operatorExpr->functionExpr)->name)
+ {
+ sb << as<VarExpr>(operatorExpr->functionExpr)->name->text;
+ }
+ else
+ {
+ sb << "<op>";
+ }
+
+ if (invokeExpr->arguments.getCount() > 0)
+ {
+ addExpr(invokeExpr->arguments[0]);
+ }
+ return;
+ }
+ else if (const auto postfixExpr = as<PostfixExpr>(operatorExpr))
+ {
+ // Postfix operator
+ if (invokeExpr->arguments.getCount() > 0)
+ {
+ addExpr(invokeExpr->arguments[0]);
+ }
+
+ if (operatorExpr->functionExpr && as<VarExpr>(operatorExpr->functionExpr) &&
+ as<VarExpr>(operatorExpr->functionExpr)->name)
+ {
+ sb << as<VarExpr>(operatorExpr->functionExpr)->name->text;
+ }
+ else
+ {
+ sb << "<op>";
+ }
+ return;
+ }
+ else if (const auto selectExpr = as<SelectExpr>(operatorExpr))
+ {
+ // Ternary operator: cond ? ifTrue : ifFalse
+ if (invokeExpr->arguments.getCount() == 3)
+ {
+ addExpr(invokeExpr->arguments[0]);
+ sb << " ? ";
+ addExpr(invokeExpr->arguments[1]);
+ sb << " : ";
+ addExpr(invokeExpr->arguments[2]);
+ return;
+ }
+ }
+ else if (const auto logicExpr = as<LogicOperatorShortCircuitExpr>(operatorExpr))
+ {
+ // Logical operators with short-circuit behavior
+ if (invokeExpr->arguments.getCount() == 2)
+ {
+ addExpr(invokeExpr->arguments[0]);
+ sb
+ << (logicExpr->flavor == LogicOperatorShortCircuitExpr::And ? " && "
+ : " || ");
+ addExpr(invokeExpr->arguments[1]);
+ return;
+ }
+ }
+ }
+
+ // Regular function call
+ if (invokeExpr->functionExpr)
+ {
+ addExpr(invokeExpr->functionExpr);
+ }
+ else
+ {
+ sb << "<unknown-func>";
+ }
+
+ sb << "(";
+ bool first = true;
+ for (auto arg : invokeExpr->arguments)
+ {
+ if (!first)
+ sb << ", ";
+ addExpr(arg);
+ first = false;
+ }
+ sb << ")";
+ }
+ else if (const auto indexExpr = as<IndexExpr>(expr))
+ {
+ if (indexExpr->baseExpression)
+ {
+ addExpr(indexExpr->baseExpression);
+ }
+
+ sb << "[";
+ bool first = true;
+ for (auto i : indexExpr->indexExprs)
+ {
+ if (!first)
+ sb << ", ";
+ addExpr(i);
+ first = false;
+ }
+ sb << "]";
+ }
+ else if (const auto swizzleExpr = as<SwizzleExpr>(expr))
+ {
+ if (swizzleExpr->base)
+ {
+ addExpr(swizzleExpr->base);
+ }
+
+ sb << ".";
+
+ // Print swizzle components (like .xyzw or .rgba)
+ static const char* xyzwComponents = "xyzw";
+
+ // Choose component naming based on type if possible
+ const char* components = xyzwComponents;
+
+ for (auto index : swizzleExpr->elementIndices)
+ {
+ if (index < 4)
+ {
+ sb << components[index];
+ }
+ else
+ {
+ sb << "?";
+ }
+ }
+ }
+ else if (const auto matrixSwizzleExpr = as<MatrixSwizzleExpr>(expr))
+ {
+ if (matrixSwizzleExpr->base)
+ {
+ addExpr(matrixSwizzleExpr->base);
+ }
+
+ sb << ".";
+
+ // Print matrix swizzle components (like _m00, _m01, etc.)
+ for (int i = 0; i < matrixSwizzleExpr->elementCount; ++i)
+ {
+ if (i > 0)
+ sb << "";
+ sb << "_m" << matrixSwizzleExpr->elementCoords[i].row
+ << matrixSwizzleExpr->elementCoords[i].col;
+ }
+ }
+ else if (const auto makeRefExpr = as<MakeRefExpr>(expr))
+ {
+ sb << "&";
+ if (makeRefExpr->base)
+ {
+ addExpr(makeRefExpr->base);
+ }
+ }
+ else if (const auto derefExpr = as<DerefExpr>(expr))
+ {
+ sb << "*";
+ if (derefExpr->base)
+ {
+ addExpr(derefExpr->base);
+ }
+ }
+ else if (const auto typeCastExpr = as<TypeCastExpr>(expr))
+ {
+ if (as<ExplicitCastExpr>(typeCastExpr))
+ {
+ sb << "(";
+ addType(expr->type);
+ sb << ")";
+
+ if (typeCastExpr->arguments.getCount() > 0)
+ {
+ addExpr(typeCastExpr->arguments[0]);
+ }
+ }
+ else if (
+ as<ImplicitCastExpr>(typeCastExpr) || as<LValueImplicitCastExpr>(typeCastExpr) ||
+ as<OutImplicitCastExpr>(typeCastExpr) || as<InOutImplicitCastExpr>(typeCastExpr))
+ {
+ // For implicit casts, just print the inner expression
+ if (typeCastExpr->arguments.getCount() > 0)
+ {
+ addExpr(typeCastExpr->arguments[0]);
+ }
+ else
+ {
+ sb << "<implicit-cast>";
+ }
+ }
+ }
+ else if (const auto builtinCastExpr = as<BuiltinCastExpr>(expr))
+ {
+ if (builtinCastExpr->base)
+ {
+ addExpr(builtinCastExpr->base);
+ }
+ else
+ {
+ sb << "<builtin-cast>";
+ }
+ }
+ else if (const auto castToSuperTypeExpr = as<CastToSuperTypeExpr>(expr))
+ {
+ sb << "((";
+ addType(expr->type);
+ sb << ")";
+
+ if (castToSuperTypeExpr->valueArg)
+ {
+ addExpr(castToSuperTypeExpr->valueArg);
+ }
+
+ sb << ")";
+ }
+ else if (const auto isTypeExpr = as<IsTypeExpr>(expr))
+ {
+ if (isTypeExpr->value)
+ {
+ addExpr(isTypeExpr->value);
+ }
+
+ sb << " is ";
+
+ if (isTypeExpr->typeExpr.type)
+ {
+ addType(isTypeExpr->typeExpr.type);
+ }
+ else
+ {
+ sb << "<unknown-type>";
+ }
+ }
+ else if (const auto asTypeExpr = as<AsTypeExpr>(expr))
+ {
+ if (asTypeExpr->value)
+ {
+ addExpr(asTypeExpr->value);
+ }
+
+ sb << " as ";
+
+ if (asTypeExpr->typeExpr)
+ {
+ addExpr(asTypeExpr->typeExpr);
+ }
+ else
+ {
+ sb << "<unknown-type>";
+ }
+ }
+ else if (const auto sizeOfExpr = as<SizeOfExpr>(expr))
+ {
+ sb << "sizeof(";
+ if (sizeOfExpr->sizedType)
+ {
+ addType(sizeOfExpr->sizedType);
+ }
+ else if (sizeOfExpr->value)
+ {
+ addExpr(sizeOfExpr->value);
+ }
+ sb << ")";
+ }
+ else if (const auto alignOfExpr = as<AlignOfExpr>(expr))
+ {
+ sb << "alignof(";
+ if (alignOfExpr->sizedType)
+ {
+ addType(alignOfExpr->sizedType);
+ }
+ else if (alignOfExpr->value)
+ {
+ addExpr(alignOfExpr->value);
+ }
+ sb << ")";
+ }
+ else if (const auto countOfExpr = as<CountOfExpr>(expr))
+ {
+ sb << "countof(";
+ if (countOfExpr->sizedType)
+ {
+ addType(countOfExpr->sizedType);
+ }
+ else if (countOfExpr->value)
+ {
+ addExpr(countOfExpr->value);
+ }
+ sb << ")";
+ }
+ else if (const auto makeOptionalExpr = as<MakeOptionalExpr>(expr))
+ {
+ if (makeOptionalExpr->value)
+ {
+ sb << "Optional(";
+ addExpr(makeOptionalExpr->value);
+ sb << ")";
+ }
+ else
+ {
+ sb << "Optional<";
+ if (makeOptionalExpr->typeExpr)
+ {
+ addExpr(makeOptionalExpr->typeExpr);
+ }
+ else
+ {
+ addType(expr->type);
+ }
+ sb << ">.none";
+ }
+ }
+ else if (const auto modifierCastExpr = as<ModifierCastExpr>(expr))
+ {
+ sb << "(";
+ addType(expr->type);
+ sb << ")";
+
+ if (modifierCastExpr->valueArg)
+ {
+ addExpr(modifierCastExpr->valueArg);
+ }
+ }
+ else if (const auto assignExpr = as<AssignExpr>(expr))
+ {
+ if (assignExpr->left)
+ {
+ addExpr(assignExpr->left);
+ }
+
+ sb << " = ";
+
+ if (assignExpr->right)
+ {
+ addExpr(assignExpr->right);
+ }
+ }
+ else if (const auto parenExpr = as<ParenExpr>(expr))
+ {
+ sb << "(";
+ if (parenExpr->base)
+ {
+ addExpr(parenExpr->base);
+ }
+ sb << ")";
+ }
+ else if (as<ThisExpr>(expr))
+ {
+ sb << "this";
+ }
+ else if (as<ReturnValExpr>(expr))
+ {
+ sb << "__return_val";
+ }
+ else if (const auto letExpr = as<LetExpr>(expr))
+ {
+ sb << "let ";
+ if (letExpr->decl)
+ {
+ _addDeclName(letExpr->decl);
+
+ if (letExpr->decl->type.type)
+ {
+ sb << " : ";
+ addType(letExpr->decl->type.type);
+ }
+
+ if (letExpr->decl->initExpr)
+ {
+ sb << " = ";
+ addExpr(letExpr->decl->initExpr);
+ }
+ }
+
+ if (letExpr->body)
+ {
+ sb << " in ";
+ addExpr(letExpr->body);
+ }
+ }
+ else if (const auto extractExistentialValueExpr = as<ExtractExistentialValueExpr>(expr))
+ {
+ if (extractExistentialValueExpr->declRef)
+ {
+ addDeclPath(extractExistentialValueExpr->declRef);
+ }
+ else if (extractExistentialValueExpr->originalExpr)
+ {
+ addExpr(extractExistentialValueExpr->originalExpr);
+ }
+ else
+ {
+ sb << "<extract-existential>";
+ }
+ }
+ else if (const auto openRefExpr = as<OpenRefExpr>(expr))
+ {
+ sb << "open(";
+ if (openRefExpr->innerExpr)
+ {
+ addExpr(openRefExpr->innerExpr);
+ }
+ sb << ")";
+ }
+ else if (const auto detachExpr = as<DetachExpr>(expr))
+ {
+ sb << "detach(";
+ if (detachExpr->inner)
+ {
+ addExpr(detachExpr->inner);
+ }
+ sb << ")";
+ }
+ else if (const auto higherOrderInvokeExpr = as<HigherOrderInvokeExpr>(expr))
+ {
+ if (const auto primalSubstituteExpr = as<PrimalSubstituteExpr>(higherOrderInvokeExpr))
+ {
+ sb << "__primal(";
+ }
+ else if (const auto forwardDiffExpr = as<ForwardDifferentiateExpr>(higherOrderInvokeExpr))
+ {
+ sb << "__fwd_diff(";
+ }
+ else if (const auto backwardDiffExpr = as<BackwardDifferentiateExpr>(higherOrderInvokeExpr))
+ {
+ sb << "__bwd_diff(";
+ }
+ else if (const auto dispatchKernelExpr = as<DispatchKernelExpr>(higherOrderInvokeExpr))
+ {
+ sb << "__dispatch_kernel(";
+ }
+ else
+ {
+ sb << "<higher-order>(";
+ }
+
+ if (higherOrderInvokeExpr->baseFunction)
+ {
+ addExpr(higherOrderInvokeExpr->baseFunction);
+ }
+
+ // Add additional parameters for specific higher-order expressions
+ if (const auto dispatchKernelExpr = as<DispatchKernelExpr>(higherOrderInvokeExpr))
+ {
+ sb << ", ";
+ if (dispatchKernelExpr->threadGroupSize)
+ {
+ addExpr(dispatchKernelExpr->threadGroupSize);
+ }
+ else
+ {
+ sb << "<unknown-thread-group-size>";
+ }
+
+ sb << ", ";
+
+ if (dispatchKernelExpr->dispatchSize)
+ {
+ addExpr(dispatchKernelExpr->dispatchSize);
+ }
+ else
+ {
+ sb << "<unknown-dispatch-size>";
+ }
+ }
+
+ sb << ")";
+ }
+ else if (const auto treatAsDiffExpr = as<TreatAsDifferentiableExpr>(expr))
+ {
+ if (treatAsDiffExpr->flavor == TreatAsDifferentiableExpr::NoDiff)
+ {
+ sb << "no_diff(";
+ }
+ else
+ {
+ sb << "differentiable(";
+ }
+
+ if (treatAsDiffExpr->innerExpr)
+ {
+ addExpr(treatAsDiffExpr->innerExpr);
+ }
+
+ sb << ")";
+ }
+ else if (as<ThisTypeExpr>(expr))
+ {
+ sb << "This";
+ }
+ else if (const auto andTypeExpr = as<AndTypeExpr>(expr))
+ {
+ if (andTypeExpr->left.type)
+ {
+ addType(andTypeExpr->left.type);
+ }
+ else
+ {
+ sb << "<unknown-type>";
+ }
+
+ sb << " & ";
+
+ if (andTypeExpr->right.type)
+ {
+ addType(andTypeExpr->right.type);
+ }
+ else
+ {
+ sb << "<unknown-type>";
+ }
+ }
+ else if (const auto modifiedTypeExpr = as<ModifiedTypeExpr>(expr))
+ {
+ // Print modifiers
+ for (auto modifier : modifiedTypeExpr->modifiers)
+ {
+ if (modifier->getKeywordName())
+ {
+ sb << modifier->getKeywordName()->text << " ";
+ }
+ }
+
+ if (modifiedTypeExpr->base.type)
+ {
+ addType(modifiedTypeExpr->base.type);
+ }
+ else
+ {
+ sb << "<unknown-type>";
+ }
+ }
+ else if (const auto pointerTypeExpr = as<PointerTypeExpr>(expr))
+ {
+ if (pointerTypeExpr->base.type)
+ {
+ addType(pointerTypeExpr->base.type);
+ }
+ else
+ {
+ sb << "<unknown-type>";
+ }
+
+ sb << "*";
+ }
+ else if (const auto funcTypeExpr = as<FuncTypeExpr>(expr))
+ {
+ sb << "(";
+ bool first = true;
+ for (auto& param : funcTypeExpr->parameters)
+ {
+ if (!first)
+ sb << ", ";
+
+ if (param.type)
+ {
+ addType(param.type);
+ }
+ else
+ {
+ sb << "<unknown-type>";
+ }
+
+ first = false;
+ }
+ sb << ") -> ";
+
+ if (funcTypeExpr->result.type)
+ {
+ addType(funcTypeExpr->result.type);
+ }
+ else
+ {
+ sb << "<unknown-type>";
+ }
+ }
+ else if (const auto tupleTypeExpr = as<TupleTypeExpr>(expr))
+ {
+ sb << "(";
+ bool first = true;
+ for (auto& member : tupleTypeExpr->members)
+ {
+ if (!first)
+ sb << ", ";
+
+ if (member.type)
+ {
+ addType(member.type);
+ }
+ else
+ {
+ sb << "<unknown-type>";
+ }
+
+ first = false;
+ }
+ sb << ")";
+ }
+ else if (const auto partiallyAppliedGenericExpr = as<PartiallyAppliedGenericExpr>(expr))
+ {
+ if (partiallyAppliedGenericExpr->baseGenericDeclRef)
+ {
+ addDeclPath(partiallyAppliedGenericExpr->baseGenericDeclRef);
+ }
+ else if (partiallyAppliedGenericExpr->originalExpr)
+ {
+ addExpr(partiallyAppliedGenericExpr->originalExpr);
+ }
+ else
+ {
+ sb << "<partially-applied-generic>";
+ }
+
+ sb << "<";
+ bool first = true;
+ for (auto arg : partiallyAppliedGenericExpr->knownGenericArgs)
+ {
+ if (!first)
+ sb << ", ";
+
+ addVal(arg);
+
+ first = false;
+ }
+ sb << ", ...>";
+ }
+ else if (const auto packExpr = as<PackExpr>(expr))
+ {
+ sb << "(";
+ bool first = true;
+ for (auto arg : packExpr->args)
+ {
+ if (!first)
+ sb << ", ";
+
+ addExpr(arg);
+
+ first = false;
+ }
+ sb << ")";
+ }
+ else if (const auto spirvAsmExpr = as<SPIRVAsmExpr>(expr))
+ {
+ sb << "spirv_asm {";
+ bool first = true;
+ for (auto& inst : spirvAsmExpr->insts)
+ {
+ if (!first)
+ sb << "\n ";
+ else
+ sb << " ";
+
+ // Print opcode
+ if (inst.opcode.flavor == SPIRVAsmOperand::NamedValue &&
+ inst.opcode.token.type != TokenType::Unknown)
+ {
+ sb << inst.opcode.token.getContent();
+ }
+ else
+ {
+ sb << "<unknown-opcode>";
+ }
+
+ // Print operands
+ for (auto& operand : inst.operands)
+ {
+ sb << " ";
+
+ switch (operand.flavor)
+ {
+ case SPIRVAsmOperand::Literal:
+ if (operand.token.type != TokenType::Unknown)
+ sb << operand.token.getContent();
+ else
+ sb << operand.knownValue;
+ break;
+
+ case SPIRVAsmOperand::Id:
+ sb << "%" << operand.token.getContent();
+ break;
+
+ case SPIRVAsmOperand::ResultMarker:
+ sb << "result";
+ break;
+
+ case SPIRVAsmOperand::NamedValue:
+ sb << operand.token.getContent();
+ break;
+
+ case SPIRVAsmOperand::SlangValue:
+ case SPIRVAsmOperand::SlangValueAddr:
+ case SPIRVAsmOperand::SlangImmediateValue:
+ if (operand.expr)
+ addExpr(operand.expr);
+ else
+ sb << "<unknown-slang-value>";
+ break;
+
+ case SPIRVAsmOperand::SlangType:
+ case SPIRVAsmOperand::SampledType:
+ case SPIRVAsmOperand::ImageType:
+ case SPIRVAsmOperand::SampledImageType:
+ if (operand.type.type)
+ addType(operand.type.type);
+ else
+ sb << "<unknown-type>";
+ break;
+
+ default:
+ sb << "<unknown-operand>";
+ break;
+ }
+ }
+
+ first = false;
+ }
+ sb << " }";
+ }
+ else if (const auto genericAppExpr = as<GenericAppExpr>(expr))
+ {
+ if (genericAppExpr->functionExpr)
+ {
+ addExpr(genericAppExpr->functionExpr);
+ }
+ else
+ {
+ sb << "<unknown-generic>";
+ }
+
+ sb << "<";
+ bool first = true;
+ for (auto arg : genericAppExpr->arguments)
+ {
+ if (!first)
+ sb << ", ";
+ addExpr(arg);
+ first = false;
+ }
+ sb << ">";
+ }
+ else if (const auto tryExpr = as<TryExpr>(expr))
+ {
+ switch (tryExpr->tryClauseType)
+ {
+ case TryClauseType::Standard:
+ sb << "try ";
+ break;
+ case TryClauseType::Optional:
+ sb << "try? ";
+ break;
+ case TryClauseType::Assert:
+ sb << "try! ";
+ break;
+ default:
+ break;
+ }
+
+ if (tryExpr->base)
+ {
+ addExpr(tryExpr->base);
+ }
+ }
+ else if (const auto defaultConstructExpr = as<DefaultConstructExpr>(expr))
+ {
+ sb << "default(";
+ addType(expr->type);
+ sb << ")";
+ }
+ else if (const auto overloadedExpr = as<OverloadedExpr>(expr))
+ {
+ if (overloadedExpr->base)
+ {
+ addExpr(overloadedExpr->base);
+ sb << ".";
+ }
+
+ if (overloadedExpr->name)
+ {
+ sb << overloadedExpr->name->text;
+ }
+ else
+ {
+ sb << "<overloaded>";
+ }
+ }
+ else if (const auto overloadedExpr2 = as<OverloadedExpr2>(expr))
+ {
+ if (overloadedExpr2->base)
+ {
+ addExpr(overloadedExpr2->base);
+ sb << ".";
+ }
+
+ sb << "<overloaded>";
+ }
+ else
+ {
+ // For any other expression types
+ sb << "<expr>";
+ }
+}
+
void ASTPrinter::addVal(Val* val)
{
val->toText(m_builder);
@@ -361,6 +1409,12 @@ void ASTPrinter::addDeclParams(const DeclRef<Decl>& declRef, List<Range<Index>>*
}
}
+ if (m_optionFlags & OptionFlag::DefaultParamValues && paramDecl->initExpr)
+ {
+ sb << " = ";
+ addExpr(paramDecl->initExpr);
+ }
+
auto rangeEnd = sb.getLength();
if (outParamRange)
diff --git a/source/slang/slang-ast-print.h b/source/slang/slang-ast-print.h
index c7b20b26b..6521fdafe 100644
--- a/source/slang/slang-ast-print.h
+++ b/source/slang/slang-ast-print.h
@@ -28,6 +28,8 @@ public:
/// type name defined on an extension when
/// printing the target type of an extension decl.
NoSpecializedExtensionTypeName = 0x10,
+ // Output `= blah` when function type parameters have a default value
+ DefaultParamValues = 0x20,
};
};
@@ -125,6 +127,8 @@ public:
/// Add a type
void addType(Type* type);
+ /// Add an expr
+ void addExpr(Expr* type);
/// Add a value
void addVal(Val* val);
diff --git a/source/slang/slang-language-server.cpp b/source/slang/slang-language-server.cpp
index 43e5b31ef..1813fa953 100644
--- a/source/slang/slang-language-server.cpp
+++ b/source/slang/slang-language-server.cpp
@@ -320,7 +320,8 @@ String getDeclSignatureString(DeclRef<Decl> declRef, WorkspaceVersion* version)
ASTPrinter printer(
astBuilder,
ASTPrinter::OptionFlag::ParamNames | ASTPrinter::OptionFlag::NoInternalKeywords |
- ASTPrinter::OptionFlag::SimplifiedBuiltinType);
+ ASTPrinter::OptionFlag::SimplifiedBuiltinType |
+ ASTPrinter::OptionFlag::DefaultParamValues);
printer.getStringBuilder() << getDeclKindString(declRef);
printer.addDeclSignature(declRef);
auto printInitExpr = [&](Module* module, Type* declType, Expr* initExpr)
diff --git a/tests/language-server/default-values.slang b/tests/language-server/default-values.slang
new file mode 100644
index 000000000..abb08b6a8
--- /dev/null
+++ b/tests/language-server/default-values.slang
@@ -0,0 +1,13 @@
+//TEST(smoke):LANG_SERVER:
+
+void bar()
+{
+ foo(1, 2.0);
+//HOVER:5,5
+}
+
+void foo(int i = 0, float j = 1.0, int k = 1+1, int l = -10, int m = MY_CONST)
+{
+}
+
+const int MY_CONST = 10;
diff --git a/tests/language-server/default-values.slang.expected.txt b/tests/language-server/default-values.slang.expected.txt
new file mode 100644
index 000000000..2d2cc2452
--- /dev/null
+++ b/tests/language-server/default-values.slang.expected.txt
@@ -0,0 +1,9 @@
+--------
+range: 4,4 - 4,7
+content:
+```
+func foo(int i = 0, float j = 1f, int k = (1 + 1), int l = -10, int m = MY_CONST) -> void
+```
+
+
+{REDACTED}.slang(9)