blob: 56148ee342d6be5f39d10ea9d7c7853fdedfec49 [file] [log] [blame] [edit]
/*
* Copyright (C) 2022 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "ASTStringDumper.h"
#include "AST.h"
#include "WGSLShaderModule.h"
#include <wtf/DataLog.h>
#include <wtf/SetForScope.h>
#include <wtf/text/MakeString.h>
namespace WGSL::AST {
struct Indent {
Indent(StringDumper& dumper)
: scope(dumper.m_indent, makeString(dumper.m_indent, " "_s))
{ }
SetForScope<String> scope;
};
static Indent bumpIndent(StringDumper& dumper)
{
return Indent(dumper);
}
template<typename T, typename J>
void StringDumper::visitVector(T& nodes, J joiner)
{
if (nodes.isEmpty())
return;
visit(nodes[0]);
for (size_t n = 1; n < nodes.size(); ++n) {
m_out.print(joiner);
visit(nodes[n]);
}
}
String StringDumper::toString()
{
return m_out.toString();
}
// Shader Module
void StringDumper::visit(ShaderModule& shaderModule)
{
for (auto& directive : shaderModule.directives())
visit(directive);
if (!shaderModule.directives().isEmpty())
m_out.print("\n\n");
for (auto& declaration : shaderModule.declarations()) {
AST::Visitor::visit(declaration);
m_out.print("\n");
}
}
void StringDumper::visit(DiagnosticDirective&)
{
// FIXME: we still don't do anything with diagnostics
}
// Attribute
void StringDumper::visit(BindingAttribute& binding)
{
m_out.print("@binding(");
visit(binding.binding());
m_out.print(")");
}
void StringDumper::visit(BuiltinAttribute& builtin)
{
m_out.print("@builtin(", builtin.builtin(), ")");
}
void StringDumper::visit(GroupAttribute& group)
{
m_out.print("@group(");
visit(group.group());
m_out.print(")");
}
void StringDumper::visit(LocationAttribute& location)
{
m_out.print("@location(");
visit(location.location());
m_out.print(")");
}
void StringDumper::visit(StageAttribute& stage)
{
m_out.print("@", stage.stage());
}
void StringDumper::visit(WorkgroupSizeAttribute& workgroupSize)
{
m_out.print("@workgroup_size(");
visit(workgroupSize.x());
if (auto* y = workgroupSize.maybeY()) {
m_out.print(", ");
visit(*y);
if (auto* z = workgroupSize.maybeZ()) {
m_out.print(", ");
visit(*z);
}
}
m_out.print(")");
}
// Declaration
void StringDumper::visit(Function& function)
{
m_out.print(m_indent);
if (!function.attributes().isEmpty()) {
visitVector(function.attributes(), " ");
m_out.print("\n", m_indent);
}
m_out.print("fn ", function.name(), "(");
if (!function.parameters().isEmpty()) {
m_out.print("\n");
{
auto indent = bumpIndent(*this);
visitVector(function.parameters(), "\n");
}
m_out.print("\n", m_indent);
}
m_out.print(")");
if (function.maybeReturnType()) {
m_out.print(" -> ");
visitVector(function.returnAttributes(), " ");
m_out.print(" ");
visit(*function.maybeReturnType());
}
m_out.print("\n", m_indent);
visit(function.body());
}
void StringDumper::visit(Structure& structure)
{
m_out.print(m_indent);
if (!structure.attributes().isEmpty()) {
visitVector(structure.attributes(), " ");
m_out.print("\n", m_indent);
}
m_out.print("struct ", structure.name(), " {");
if (!structure.members().isEmpty()) {
m_out.print("\n");
{
auto indent = bumpIndent(*this);
visitVector(structure.members(), ",\n");
}
m_out.print("\n", m_indent);
}
m_out.print("}\n");
}
void StringDumper::visit(Variable& variable)
{
if (!variable.attributes().isEmpty()) {
visitVector(variable.attributes(), " ");
m_out.print(" ");
}
m_out.print("var");
if (variable.maybeQualifier())
visit(*variable.maybeQualifier());
m_out.print(" ", variable.name());
if (variable.maybeTypeName()) {
m_out.print(": ");
visit(*variable.maybeTypeName());
}
if (variable.maybeInitializer()) {
m_out.print(" = ");
visit(*variable.maybeInitializer());
}
m_out.print(";");
}
void StringDumper::visit(TypeAlias& alias)
{
m_out.print(m_indent);
m_out.print("alias ", alias.name(), " = ");
visit(alias.type());
m_out.print(";");
}
// Expression
void StringDumper::visit(AbstractFloatLiteral& literal)
{
m_out.print(literal.value());
}
void StringDumper::visit(AbstractIntegerLiteral& literal)
{
m_out.print(literal.value());
}
void StringDumper::visit(IndexAccessExpression& arrayAccess)
{
visit(arrayAccess.base());
m_out.print("[");
visit(arrayAccess.index());
m_out.print("]");
}
void StringDumper::visit(BoolLiteral& literal)
{
m_out.print(literal.value() ? "true": "false");
}
void StringDumper::visit(CallExpression& expression)
{
visit(expression.target());
m_out.print("(");
if (!expression.arguments().isEmpty()) {
auto indent = bumpIndent(*this);
visitVector(expression.arguments(), ", ");
}
m_out.print(")");
}
void StringDumper::visit(Float32Literal& literal)
{
m_out.print(literal.value(), "f");
}
void StringDumper::visit(Float16Literal& literal)
{
m_out.print(String::number(literal.value()), "h");
}
void StringDumper::visit(IdentifierExpression& identifier)
{
m_out.print(identifier.identifier());
}
void StringDumper::visit(Signed32Literal& literal)
{
m_out.print(literal.value(), "i");
}
void StringDumper::visit(FieldAccessExpression& fieldAccess)
{
visit(fieldAccess.base());
m_out.print(".", fieldAccess.fieldName());
}
void StringDumper::visit(Unsigned32Literal& literal)
{
m_out.print(literal.value(), "u");
}
void StringDumper::visit(UnaryExpression& expression)
{
m_out.print(expression.operation());
visit(expression.expression());
}
void StringDumper::visit(BinaryExpression& expression)
{
visit(expression.leftExpression());
m_out.print(" ", expression.operation(), " ");
visit(expression.rightExpression());
}
void StringDumper::visit(PointerDereferenceExpression& pointerDereference)
{
m_out.print("(*");
visit(pointerDereference.target());
m_out.print(")");
}
// Statement
void StringDumper::visit(AssignmentStatement& statement)
{
m_out.print(m_indent);
visit(statement.lhs());
m_out.print(" = ");
visit(statement.rhs());
m_out.print(";");
}
void StringDumper::visit(CallStatement& statement)
{
visit(statement.call());
m_out.print(";");
}
void StringDumper::visit(CompoundAssignmentStatement& statement)
{
m_out.print(m_indent);
visit(statement.leftExpression());
m_out.print(" ", statement.operation(), "= ");
visit(statement.rightExpression());
m_out.print(";");
}
void StringDumper::visit(CompoundStatement& block)
{
m_out.print(m_indent, "{");
if (!block.statements().isEmpty()) {
{
auto indent = bumpIndent(*this);
m_out.print("\n");
visitVector(block.statements(), "\n");
}
m_out.print("\n", m_indent);
}
m_out.print("}\n");
}
void StringDumper::visit(DecrementIncrementStatement& statement)
{
m_out.print(m_indent);
visit(statement.expression());
m_out.print(statement.operation(), ";");
}
void StringDumper::visit(IfStatement& statement)
{
m_out.print(m_indent, "if ");
visit(statement.test());
m_out.print("\n");
visit(statement.trueBody());
if (statement.maybeFalseBody()) {
m_out.print(m_indent, "else");
if (is<IfStatement>(*statement.maybeFalseBody()))
m_out.print(" ");
else
m_out.print("\n");
visit(*statement.maybeFalseBody());
}
}
void StringDumper::visit(PhonyAssignmentStatement& statement)
{
m_out.print(m_indent);
m_out.print("_ = ");
visit(statement.rhs());
m_out.print(";");
}
void StringDumper::visit(ReturnStatement& statement)
{
m_out.print(m_indent, "return");
if (statement.maybeExpression()) {
m_out.print(" ");
visit(*statement.maybeExpression());
}
m_out.print(";");
}
void StringDumper::visit(VariableStatement& statement)
{
m_out.print(m_indent);
visit(statement.variable());
}
void StringDumper::visit(ForStatement& statement)
{
m_out.print("for (");
if (auto* initializer = statement.maybeInitializer())
visit(*initializer);
m_out.print(";");
if (auto* test = statement.maybeTest())
visit(*test);
m_out.print(";");
if (auto* update = statement.maybeUpdate())
visit(*update);
m_out.print(")");
visit(statement.body());
}
// Types
void StringDumper::visit(ArrayTypeExpression& type)
{
m_out.print("array");
if (type.maybeElementType()) {
m_out.print("<");
visit(*type.maybeElementType());
if (type.maybeElementCount()) {
m_out.print(", ");
visit(*type.maybeElementCount());
}
m_out.print(">");
}
}
void StringDumper::visit(ElaboratedTypeExpression& type)
{
m_out.print(type.base(), "<");
bool first = true;
for (auto& argument : type.arguments()) {
if (!first)
m_out.print(", ");
first = false;
visit(argument);
}
m_out.print(">");
}
void StringDumper::visit(ReferenceTypeExpression& type)
{
visit(type.type());
m_out.print("&");
}
void StringDumper::visit(Parameter& parameter)
{
m_out.print(m_indent);
if (!parameter.attributes().isEmpty()) {
visitVector(parameter.attributes(), " ");
m_out.print(" ");
}
m_out.print(parameter.name(), ": ");
visit(parameter.typeName());
}
void StringDumper::visit(StructureMember& member)
{
m_out.print(m_indent);
if (!member.attributes().isEmpty()) {
visitVector(member.attributes(), " ");
m_out.print(" ");
}
m_out.print(member.name(), ": ");
visit(member.type());
}
void StringDumper::visit(VariableQualifier& qualifier)
{
m_out.print("<", qualifier.addressSpace(), ",", qualifier.accessMode(), ">");
}
void dumpAST(ShaderModule& shaderModule)
{
dataLogLn(ShaderModuleDumper(shaderModule));
}
} // namespace WGSL::AST