/* * Copyright 2017 WebAssembly Community Group participants * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "src/expr-visitor.h" #include "src/cast.h" #include "src/ir.h" namespace wabt { ExprVisitor::ExprVisitor(Delegate* delegate) : delegate_(delegate) {} Result ExprVisitor::VisitExpr(Expr* root_expr) { state_stack_.clear(); expr_stack_.clear(); expr_iter_stack_.clear(); PushDefault(root_expr); while (!state_stack_.empty()) { State state = state_stack_.back(); auto* expr = expr_stack_.back(); switch (state) { case State::Default: PopDefault(); CHECK_RESULT(HandleDefaultState(expr)); break; case State::Block: { auto block_expr = cast(expr); auto& iter = expr_iter_stack_.back(); if (iter != block_expr->block.exprs.end()) { PushDefault(&*iter++); } else { CHECK_RESULT(delegate_->EndBlockExpr(block_expr)); PopExprlist(); } break; } case State::IfTrue: { auto if_expr = cast(expr); auto& iter = expr_iter_stack_.back(); if (iter != if_expr->true_.exprs.end()) { PushDefault(&*iter++); } else { CHECK_RESULT(delegate_->AfterIfTrueExpr(if_expr)); PopExprlist(); PushExprlist(State::IfFalse, expr, if_expr->false_); } break; } case State::IfFalse: { auto if_expr = cast(expr); auto& iter = expr_iter_stack_.back(); if (iter != if_expr->false_.end()) { PushDefault(&*iter++); } else { CHECK_RESULT(delegate_->EndIfExpr(if_expr)); PopExprlist(); } break; } case State::IfExceptTrue: { auto if_except_expr = cast(expr); auto& iter = expr_iter_stack_.back(); if (iter != if_except_expr->true_.exprs.end()) { PushDefault(&*iter++); } else { CHECK_RESULT(delegate_->AfterIfExceptTrueExpr(if_except_expr)); PopExprlist(); PushExprlist(State::IfExceptFalse, expr, if_except_expr->false_); } break; } case State::IfExceptFalse: { auto if_except_expr = cast(expr); auto& iter = expr_iter_stack_.back(); if (iter != if_except_expr->false_.end()) { PushDefault(&*iter++); } else { CHECK_RESULT(delegate_->EndIfExceptExpr(if_except_expr)); PopExprlist(); } break; } case State::Loop: { auto loop_expr = cast(expr); auto& iter = expr_iter_stack_.back(); if (iter != loop_expr->block.exprs.end()) { PushDefault(&*iter++); } else { CHECK_RESULT(delegate_->EndLoopExpr(loop_expr)); PopExprlist(); } break; } case State::Try: { auto try_expr = cast(expr); auto& iter = expr_iter_stack_.back(); if (iter != try_expr->block.exprs.end()) { PushDefault(&*iter++); } else { if (try_expr->catch_.empty()) { CHECK_RESULT(delegate_->EndTryExpr(try_expr)); PopExprlist(); } else { CHECK_RESULT(delegate_->OnCatchExpr(try_expr)); PopExprlist(); PushExprlist(State::Catch, expr, try_expr->catch_); } } break; } case State::Catch: { auto try_expr = cast(expr); auto& iter = expr_iter_stack_.back(); if (iter != try_expr->catch_.end()) { PushDefault(&*iter++); } else { CHECK_RESULT(delegate_->EndTryExpr(try_expr)); PopExprlist(); } break; } } } return Result::Ok; } Result ExprVisitor::VisitExprList(ExprList& exprs) { for (Expr& expr : exprs) CHECK_RESULT(VisitExpr(&expr)); return Result::Ok; } Result ExprVisitor::VisitFunc(Func* func) { return VisitExprList(func->exprs); } Result ExprVisitor::HandleDefaultState(Expr* expr) { switch (expr->type()) { case ExprType::AtomicLoad: CHECK_RESULT(delegate_->OnAtomicLoadExpr(cast(expr))); break; case ExprType::AtomicStore: CHECK_RESULT(delegate_->OnAtomicStoreExpr(cast(expr))); break; case ExprType::AtomicRmw: CHECK_RESULT(delegate_->OnAtomicRmwExpr(cast(expr))); break; case ExprType::AtomicRmwCmpxchg: CHECK_RESULT( delegate_->OnAtomicRmwCmpxchgExpr(cast(expr))); break; case ExprType::AtomicWait: CHECK_RESULT(delegate_->OnAtomicWaitExpr(cast(expr))); break; case ExprType::AtomicWake: CHECK_RESULT(delegate_->OnAtomicWakeExpr(cast(expr))); break; case ExprType::Binary: CHECK_RESULT(delegate_->OnBinaryExpr(cast(expr))); break; case ExprType::Block: { auto block_expr = cast(expr); CHECK_RESULT(delegate_->BeginBlockExpr(block_expr)); PushExprlist(State::Block, expr, block_expr->block.exprs); break; } case ExprType::Br: CHECK_RESULT(delegate_->OnBrExpr(cast(expr))); break; case ExprType::BrIf: CHECK_RESULT(delegate_->OnBrIfExpr(cast(expr))); break; case ExprType::BrTable: CHECK_RESULT(delegate_->OnBrTableExpr(cast(expr))); break; case ExprType::Call: CHECK_RESULT(delegate_->OnCallExpr(cast(expr))); break; case ExprType::CallIndirect: CHECK_RESULT(delegate_->OnCallIndirectExpr(cast(expr))); break; case ExprType::Compare: CHECK_RESULT(delegate_->OnCompareExpr(cast(expr))); break; case ExprType::Const: CHECK_RESULT(delegate_->OnConstExpr(cast(expr))); break; case ExprType::Convert: CHECK_RESULT(delegate_->OnConvertExpr(cast(expr))); break; case ExprType::Drop: CHECK_RESULT(delegate_->OnDropExpr(cast(expr))); break; case ExprType::GetGlobal: CHECK_RESULT(delegate_->OnGetGlobalExpr(cast(expr))); break; case ExprType::GetLocal: CHECK_RESULT(delegate_->OnGetLocalExpr(cast(expr))); break; case ExprType::If: { auto if_expr = cast(expr); CHECK_RESULT(delegate_->BeginIfExpr(if_expr)); PushExprlist(State::IfTrue, expr, if_expr->true_.exprs); break; } case ExprType::IfExcept: { auto if_except_expr = cast(expr); CHECK_RESULT(delegate_->BeginIfExceptExpr(if_except_expr)); PushExprlist(State::IfExceptTrue, expr, if_except_expr->true_.exprs); break; } case ExprType::Load: CHECK_RESULT(delegate_->OnLoadExpr(cast(expr))); break; case ExprType::Loop: { auto loop_expr = cast(expr); CHECK_RESULT(delegate_->BeginLoopExpr(loop_expr)); PushExprlist(State::Loop, expr, loop_expr->block.exprs); break; } case ExprType::MemoryGrow: CHECK_RESULT(delegate_->OnMemoryGrowExpr(cast(expr))); break; case ExprType::MemorySize: CHECK_RESULT(delegate_->OnMemorySizeExpr(cast(expr))); break; case ExprType::Nop: CHECK_RESULT(delegate_->OnNopExpr(cast(expr))); break; case ExprType::Rethrow: CHECK_RESULT(delegate_->OnRethrowExpr(cast(expr))); break; case ExprType::Return: CHECK_RESULT(delegate_->OnReturnExpr(cast(expr))); break; case ExprType::Select: CHECK_RESULT(delegate_->OnSelectExpr(cast(expr))); break; case ExprType::SetGlobal: CHECK_RESULT(delegate_->OnSetGlobalExpr(cast(expr))); break; case ExprType::SetLocal: CHECK_RESULT(delegate_->OnSetLocalExpr(cast(expr))); break; case ExprType::Store: CHECK_RESULT(delegate_->OnStoreExpr(cast(expr))); break; case ExprType::TeeLocal: CHECK_RESULT(delegate_->OnTeeLocalExpr(cast(expr))); break; case ExprType::Throw: CHECK_RESULT(delegate_->OnThrowExpr(cast(expr))); break; case ExprType::Try: { auto try_expr = cast(expr); CHECK_RESULT(delegate_->BeginTryExpr(try_expr)); PushExprlist(State::Try, expr, try_expr->block.exprs); break; } case ExprType::Unary: CHECK_RESULT(delegate_->OnUnaryExpr(cast(expr))); break; case ExprType::Ternary: CHECK_RESULT(delegate_->OnTernaryExpr(cast(expr))); break; case ExprType::SimdLaneOp: { CHECK_RESULT(delegate_->OnSimdLaneOpExpr(cast(expr))); break; } case ExprType::SimdShuffleOp: { CHECK_RESULT( delegate_->OnSimdShuffleOpExpr(cast(expr))); break; } case ExprType::Unreachable: CHECK_RESULT(delegate_->OnUnreachableExpr(cast(expr))); break; } return Result::Ok; } void ExprVisitor::PushDefault(Expr* expr) { state_stack_.emplace_back(State::Default); expr_stack_.emplace_back(expr); } void ExprVisitor::PopDefault() { state_stack_.pop_back(); expr_stack_.pop_back(); } void ExprVisitor::PushExprlist(State state, Expr* expr, ExprList& expr_list) { state_stack_.emplace_back(state); expr_stack_.emplace_back(expr); expr_iter_stack_.emplace_back(expr_list.begin()); } void ExprVisitor::PopExprlist() { state_stack_.pop_back(); expr_stack_.pop_back(); expr_iter_stack_.pop_back(); } } // namespace wabt