blob: 0b5504bf5fbcf86213a4cdf8938b4379c38ba3be [file] [log] [blame]
/*
* 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 "ASTVisitor.h"
#include "AST.h"
#include "WGSLShaderModule.h"
namespace WGSL::AST {
bool Visitor::hasError() const
{
return !m_expectedError;
}
Result<void> Visitor::result()
{
return m_expectedError;
}
// Shader Module
void Visitor::visit(ShaderModule& shaderModule)
{
for (auto& directive : shaderModule.directives())
checkErrorAndVisit(directive);
for (auto& declaration : shaderModule.declarations())
checkErrorAndVisit(declaration);
}
// Directive
void Visitor::visit(AST::Directive& directive)
{
switch (directive.kind()) {
case AST::NodeKind::DiagnosticDirective:
checkErrorAndVisit(uncheckedDowncast<AST::DiagnosticDirective>(directive));
break;
default:
ASSERT_NOT_REACHED("Unhandled Directive");
}
}
void Visitor::visit(AST::DiagnosticDirective& directive)
{
visit(directive.diagnostic());
}
// Diagnostic
void Visitor::visit(AST::Diagnostic&)
{
}
// Declarations
void Visitor::visit(AST::Declaration& declaration)
{
switch (declaration.kind()) {
case AST::NodeKind::Function:
checkErrorAndVisit(uncheckedDowncast<AST::Function>(declaration));
break;
case AST::NodeKind::Variable:
checkErrorAndVisit(uncheckedDowncast<AST::Variable>(declaration));
break;
case AST::NodeKind::Structure:
checkErrorAndVisit(uncheckedDowncast<AST::Structure>(declaration));
break;
case AST::NodeKind::TypeAlias:
checkErrorAndVisit(uncheckedDowncast<AST::TypeAlias>(declaration));
break;
case AST::NodeKind::ConstAssert:
checkErrorAndVisit(uncheckedDowncast<AST::ConstAssert>(declaration));
break;
default:
ASSERT_NOT_REACHED("Unhandled Declaration");
}
}
void Visitor::visit(AST::TypeAlias& alias)
{
visit(alias.type());
}
void Visitor::visit(AST::ConstAssert& assertion)
{
visit(assertion.test());
}
// Attribute
void Visitor::visit(Attribute& attribute)
{
switch (attribute.kind()) {
case AST::NodeKind::AlignAttribute:
checkErrorAndVisit(uncheckedDowncast<AST::AlignAttribute>(attribute));
break;
case AST::NodeKind::BindingAttribute:
checkErrorAndVisit(uncheckedDowncast<AST::BindingAttribute>(attribute));
break;
case AST::NodeKind::BuiltinAttribute:
checkErrorAndVisit(uncheckedDowncast<AST::BuiltinAttribute>(attribute));
break;
case AST::NodeKind::ConstAttribute:
checkErrorAndVisit(uncheckedDowncast<AST::ConstAttribute>(attribute));
break;
case AST::NodeKind::DiagnosticAttribute:
checkErrorAndVisit(uncheckedDowncast<AST::DiagnosticAttribute>(attribute));
break;
case AST::NodeKind::GroupAttribute:
checkErrorAndVisit(uncheckedDowncast<AST::GroupAttribute>(attribute));
break;
case AST::NodeKind::IdAttribute:
checkErrorAndVisit(uncheckedDowncast<AST::IdAttribute>(attribute));
break;
case AST::NodeKind::InterpolateAttribute:
checkErrorAndVisit(uncheckedDowncast<AST::InterpolateAttribute>(attribute));
break;
case AST::NodeKind::InvariantAttribute:
checkErrorAndVisit(uncheckedDowncast<AST::InvariantAttribute>(attribute));
break;
case AST::NodeKind::LocationAttribute:
checkErrorAndVisit(uncheckedDowncast<AST::LocationAttribute>(attribute));
break;
case AST::NodeKind::MustUseAttribute:
checkErrorAndVisit(uncheckedDowncast<AST::MustUseAttribute>(attribute));
break;
case AST::NodeKind::SizeAttribute:
checkErrorAndVisit(uncheckedDowncast<AST::SizeAttribute>(attribute));
break;
case AST::NodeKind::StageAttribute:
checkErrorAndVisit(uncheckedDowncast<AST::StageAttribute>(attribute));
break;
case AST::NodeKind::WorkgroupSizeAttribute:
checkErrorAndVisit(uncheckedDowncast<AST::WorkgroupSizeAttribute>(attribute));
break;
default:
ASSERT_NOT_REACHED("Unhandled Attribute");
}
}
void Visitor::visit(AST::AlignAttribute& attribute)
{
visit(attribute.alignment());
}
void Visitor::visit(AST::BindingAttribute& attribute)
{
visit(attribute.binding());
}
void Visitor::visit(AST::ConstAttribute&)
{
}
void Visitor::visit(AST::DiagnosticAttribute& attribute)
{
visit(attribute.diagnostic());
}
void Visitor::visit(AST::BuiltinAttribute&)
{
}
void Visitor::visit(GroupAttribute& attribute)
{
visit(attribute.group());
}
void Visitor::visit(AST::IdAttribute& attribute)
{
visit(attribute.value());
}
void Visitor::visit(AST::InterpolateAttribute&)
{
}
void Visitor::visit(AST::InvariantAttribute&)
{
}
void Visitor::visit(AST::LocationAttribute& attribute)
{
visit(attribute.location());
}
void Visitor::visit(AST::MustUseAttribute&)
{
}
void Visitor::visit(AST::SizeAttribute& attribute)
{
visit(attribute.size());
}
void Visitor::visit(AST::StageAttribute&)
{
}
void Visitor::visit(AST::WorkgroupSizeAttribute& attribute)
{
checkErrorAndVisit(attribute.x());
maybeCheckErrorAndVisit(attribute.maybeY());
maybeCheckErrorAndVisit(attribute.maybeZ());
}
// Expression
void Visitor::visit(Expression& expression)
{
switch (expression.kind()) {
case AST::NodeKind::AbstractFloatLiteral:
checkErrorAndVisit(uncheckedDowncast<AST::AbstractFloatLiteral>(expression));
break;
case AST::NodeKind::AbstractIntegerLiteral:
checkErrorAndVisit(uncheckedDowncast<AST::AbstractIntegerLiteral>(expression));
break;
case AST::NodeKind::BinaryExpression:
checkErrorAndVisit(uncheckedDowncast<AST::BinaryExpression>(expression));
break;
case AST::NodeKind::BoolLiteral:
checkErrorAndVisit(uncheckedDowncast<AST::BoolLiteral>(expression));
break;
case AST::NodeKind::CallExpression:
checkErrorAndVisit(uncheckedDowncast<AST::CallExpression>(expression));
break;
case AST::NodeKind::FieldAccessExpression:
checkErrorAndVisit(uncheckedDowncast<AST::FieldAccessExpression>(expression));
break;
case AST::NodeKind::Float32Literal:
checkErrorAndVisit(uncheckedDowncast<AST::Float32Literal>(expression));
break;
case AST::NodeKind::Float16Literal:
checkErrorAndVisit(uncheckedDowncast<AST::Float16Literal>(expression));
break;
case AST::NodeKind::IdentifierExpression:
checkErrorAndVisit(uncheckedDowncast<AST::IdentifierExpression>(expression));
break;
case AST::NodeKind::IdentityExpression:
checkErrorAndVisit(uncheckedDowncast<IdentityExpression>(expression));
break;
case AST::NodeKind::IndexAccessExpression:
checkErrorAndVisit(uncheckedDowncast<AST::IndexAccessExpression>(expression));
break;
case AST::NodeKind::Signed32Literal:
checkErrorAndVisit(uncheckedDowncast<AST::Signed32Literal>(expression));
break;
case AST::NodeKind::UnaryExpression:
checkErrorAndVisit(uncheckedDowncast<AST::UnaryExpression>(expression));
break;
case AST::NodeKind::Unsigned32Literal:
checkErrorAndVisit(uncheckedDowncast<AST::Unsigned32Literal>(expression));
break;
case AST::NodeKind::ArrayTypeExpression:
checkErrorAndVisit(uncheckedDowncast<AST::ArrayTypeExpression>(expression));
break;
case AST::NodeKind::ElaboratedTypeExpression:
checkErrorAndVisit(uncheckedDowncast<AST::ElaboratedTypeExpression>(expression));
break;
case AST::NodeKind::ReferenceTypeExpression:
checkErrorAndVisit(uncheckedDowncast<AST::ReferenceTypeExpression>(expression));
break;
default:
ASSERT_NOT_REACHED("Unhandled Expression");
}
}
void Visitor::visit(AbstractFloatLiteral&)
{
}
void Visitor::visit(AST::AbstractIntegerLiteral&)
{
}
void Visitor::visit(AST::BinaryExpression& binaryExpression)
{
checkErrorAndVisit(binaryExpression.leftExpression());
checkErrorAndVisit(binaryExpression.rightExpression());
}
void Visitor::visit(BoolLiteral&)
{
}
void Visitor::visit(AST::CallExpression& callExpression)
{
checkErrorAndVisit(callExpression.target());
for (auto& argument : callExpression.arguments())
checkErrorAndVisit(argument);
}
void Visitor::visit(AST::FieldAccessExpression& fieldAccessExpression)
{
checkErrorAndVisit(fieldAccessExpression.base());
}
void Visitor::visit(AST::Float32Literal&)
{
}
void Visitor::visit(AST::Float16Literal&)
{
}
void Visitor::visit(AST::IdentifierExpression& identifierExpression)
{
checkErrorAndVisit(identifierExpression.identifier());
}
void Visitor::visit(AST::IndexAccessExpression& indexAccessExpression)
{
checkErrorAndVisit(indexAccessExpression.base());
checkErrorAndVisit(indexAccessExpression.index());
}
void Visitor::visit(AST::PointerDereferenceExpression&)
{
}
void Visitor::visit(AST::Signed32Literal&)
{
}
void Visitor::visit(UnaryExpression& unaryExpression)
{
checkErrorAndVisit(unaryExpression.expression());
}
void Visitor::visit(AST::Unsigned32Literal&)
{
}
// Function
void Visitor::visit(AST::Function& function)
{
for (auto& attribute : function.attributes())
checkErrorAndVisit(attribute);
for (auto& parameter : function.parameters())
checkErrorAndVisit(parameter);
for (auto& attribute : function.returnAttributes())
checkErrorAndVisit(attribute);
maybeCheckErrorAndVisit(function.maybeReturnType());
checkErrorAndVisit(function.body());
}
void Visitor::visit(AST::Parameter& parameterValue)
{
for (auto& attribute : parameterValue.attributes())
checkErrorAndVisit(attribute);
checkErrorAndVisit(parameterValue.typeName());
}
// Identifier
void Visitor::visit(AST::Identifier&)
{
}
void Visitor::visit(IdentityExpression& identity)
{
checkErrorAndVisit(identity.expression());
}
// Statement
void Visitor::visit(Statement& statement)
{
switch (statement.kind()) {
case AST::NodeKind::AssignmentStatement:
checkErrorAndVisit(uncheckedDowncast<AST::AssignmentStatement>(statement));
break;
case AST::NodeKind::BreakStatement:
checkErrorAndVisit(uncheckedDowncast<AST::BreakStatement>(statement));
break;
case AST::NodeKind::CallStatement:
checkErrorAndVisit(uncheckedDowncast<AST::CallStatement>(statement));
break;
case AST::NodeKind::CompoundAssignmentStatement:
checkErrorAndVisit(uncheckedDowncast<AST::CompoundAssignmentStatement>(statement));
break;
case AST::NodeKind::CompoundStatement:
checkErrorAndVisit(uncheckedDowncast<AST::CompoundStatement>(statement));
break;
case AST::NodeKind::ConstAssertStatement:
checkErrorAndVisit(uncheckedDowncast<AST::ConstAssertStatement>(statement));
break;
case AST::NodeKind::ContinueStatement:
checkErrorAndVisit(uncheckedDowncast<AST::ContinueStatement>(statement));
break;
case AST::NodeKind::DecrementIncrementStatement:
checkErrorAndVisit(uncheckedDowncast<AST::DecrementIncrementStatement>(statement));
break;
case AST::NodeKind::DiscardStatement:
checkErrorAndVisit(uncheckedDowncast<AST::DiscardStatement>(statement));
break;
case AST::NodeKind::ForStatement:
checkErrorAndVisit(uncheckedDowncast<AST::ForStatement>(statement));
break;
case AST::NodeKind::IfStatement:
checkErrorAndVisit(uncheckedDowncast<AST::IfStatement>(statement));
break;
case AST::NodeKind::LoopStatement:
checkErrorAndVisit(uncheckedDowncast<AST::LoopStatement>(statement));
break;
case AST::NodeKind::PhonyAssignmentStatement:
checkErrorAndVisit(uncheckedDowncast<AST::PhonyAssignmentStatement>(statement));
break;
case AST::NodeKind::ReturnStatement:
checkErrorAndVisit(uncheckedDowncast<AST::ReturnStatement>(statement));
break;
case AST::NodeKind::SwitchStatement:
checkErrorAndVisit(uncheckedDowncast<AST::SwitchStatement>(statement));
break;
case AST::NodeKind::VariableStatement:
checkErrorAndVisit(uncheckedDowncast<AST::VariableStatement>(statement));
break;
case AST::NodeKind::WhileStatement:
checkErrorAndVisit(uncheckedDowncast<AST::WhileStatement>(statement));
break;
default:
ASSERT_NOT_REACHED("Unhandled Statement");
}
}
void Visitor::visit(AST::AssignmentStatement& assignmentStatement)
{
checkErrorAndVisit(assignmentStatement.lhs());
checkErrorAndVisit(assignmentStatement.rhs());
}
void Visitor::visit(AST::BreakStatement&)
{
}
void Visitor::visit(AST::CallStatement& callStatement)
{
checkErrorAndVisit(callStatement.call());
}
void Visitor::visit(AST::CompoundAssignmentStatement& compoundAssignmentStatement)
{
checkErrorAndVisit(compoundAssignmentStatement.leftExpression());
checkErrorAndVisit(compoundAssignmentStatement.rightExpression());
}
void Visitor::visit(CompoundStatement& compoundStatement)
{
for (auto& statement : compoundStatement.statements())
checkErrorAndVisit(statement);
}
void Visitor::visit(AST::ConstAssertStatement& statement)
{
checkErrorAndVisit(statement.assertion());
}
void Visitor::visit(AST::ContinueStatement&)
{
}
void Visitor::visit(AST::DecrementIncrementStatement& decrementIncrementStatement)
{
checkErrorAndVisit(decrementIncrementStatement.expression());
}
void Visitor::visit(AST::DiscardStatement&)
{
}
void Visitor::visit(AST::ForStatement& forStatement)
{
maybeCheckErrorAndVisit(forStatement.maybeInitializer());
maybeCheckErrorAndVisit(forStatement.maybeTest());
maybeCheckErrorAndVisit(forStatement.maybeUpdate());
checkErrorAndVisit(forStatement.body());
}
void Visitor::visit(AST::IfStatement& ifStatement)
{
for (auto& attribute : ifStatement.attributes())
checkErrorAndVisit(attribute);
checkErrorAndVisit(ifStatement.test());
checkErrorAndVisit(ifStatement.trueBody());
maybeCheckErrorAndVisit(ifStatement.maybeFalseBody());
}
void Visitor::visit(AST::LoopStatement& loopStatement)
{
for (auto& attribute : loopStatement.attributes())
checkErrorAndVisit(attribute);
for (auto& statement : loopStatement.body())
checkErrorAndVisit(statement);
if (auto& continuing = loopStatement.continuing())
checkErrorAndVisit(*continuing);
}
void Visitor::visit(AST::Continuing& continuing)
{
for (auto& statement : continuing.body)
checkErrorAndVisit(statement);
for (auto& attribute : continuing.attributes)
checkErrorAndVisit(attribute);
maybeCheckErrorAndVisit(continuing.breakIf);
}
void Visitor::visit(AST::PhonyAssignmentStatement& phonyAssignmentStatement)
{
checkErrorAndVisit(phonyAssignmentStatement.rhs());
}
void Visitor::visit(AST::ReturnStatement& returnStatement)
{
maybeCheckErrorAndVisit(returnStatement.maybeExpression());
}
void Visitor::visit(AST::SwitchStatement& statement)
{
checkErrorAndVisit(statement.value());
for (auto& attribute : statement.valueAttributes())
checkErrorAndVisit(attribute);
for (auto& clause : statement.clauses())
checkErrorAndVisit(clause);
checkErrorAndVisit(statement.defaultClause());
}
void Visitor::visit(AST::SwitchClause& clause)
{
for (auto& selector : clause.selectors)
checkErrorAndVisit(selector);
checkErrorAndVisit(clause.body);
}
void Visitor::visit(AST::VariableStatement& varStatement)
{
checkErrorAndVisit(varStatement.variable());
}
void Visitor::visit(AST::WhileStatement& whileStatement)
{
checkErrorAndVisit(whileStatement.test());
checkErrorAndVisit(whileStatement.body());
}
// Structure
void Visitor::visit(AST::Structure& structure)
{
for (auto& attribute : structure.attributes())
checkErrorAndVisit(attribute);
for (auto& member : structure.members())
checkErrorAndVisit(member);
}
void Visitor::visit(AST::StructureMember& structureMember)
{
for (auto& attribute : structureMember.attributes())
checkErrorAndVisit(attribute);
checkErrorAndVisit(structureMember.type());
}
// Types
void Visitor::visit(AST::ArrayTypeExpression& arrayTypeExpression)
{
maybeCheckErrorAndVisit(arrayTypeExpression.maybeElementType());
maybeCheckErrorAndVisit(arrayTypeExpression.maybeElementCount());
}
void Visitor::visit(AST::ElaboratedTypeExpression& elaboratedExpression)
{
for (auto& argument : elaboratedExpression.arguments())
checkErrorAndVisit(argument);
}
void Visitor::visit(AST::ReferenceTypeExpression& referenceTypeExpression)
{
checkErrorAndVisit(referenceTypeExpression.type());
}
// Variable
void Visitor::visit(AST::Variable& variable)
{
for (auto& attribute : variable.attributes())
checkErrorAndVisit(attribute);
maybeCheckErrorAndVisit(variable.maybeQualifier());
maybeCheckErrorAndVisit(variable.maybeTypeName());
maybeCheckErrorAndVisit(variable.maybeInitializer());
}
void Visitor::visit(VariableQualifier&)
{
}
} // namespace WGSL::AST