1 // Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef FORTRAN_SEMANTICS_CHECK_IO_H_ 16 #define FORTRAN_SEMANTICS_CHECK_IO_H_ 17 18 #include "semantics.h" 19 #include "tools.h" 20 #include "../common/enum-set.h" 21 #include "../parser/parse-tree.h" 22 23 namespace Fortran::semantics { 24 25 using common::IoSpecKind; 26 using common::IoStmtKind; 27 28 class IoChecker : public virtual BaseChecker { 29 public: IoChecker(SemanticsContext & context)30 explicit IoChecker(SemanticsContext &context) : context_{context} {} 31 Enter(const parser::BackspaceStmt &)32 void Enter(const parser::BackspaceStmt &) { Init(IoStmtKind::Backspace); } Enter(const parser::CloseStmt &)33 void Enter(const parser::CloseStmt &) { Init(IoStmtKind::Close); } Enter(const parser::EndfileStmt &)34 void Enter(const parser::EndfileStmt &) { Init(IoStmtKind::Endfile); } Enter(const parser::FlushStmt &)35 void Enter(const parser::FlushStmt &) { Init(IoStmtKind::Flush); } Enter(const parser::InquireStmt &)36 void Enter(const parser::InquireStmt &) { Init(IoStmtKind::Inquire); } Enter(const parser::OpenStmt &)37 void Enter(const parser::OpenStmt &) { Init(IoStmtKind::Open); } Enter(const parser::PrintStmt &)38 void Enter(const parser::PrintStmt &) { Init(IoStmtKind::Print); } Enter(const parser::ReadStmt &)39 void Enter(const parser::ReadStmt &) { Init(IoStmtKind::Read); } Enter(const parser::RewindStmt &)40 void Enter(const parser::RewindStmt &) { Init(IoStmtKind::Rewind); } Enter(const parser::WaitStmt &)41 void Enter(const parser::WaitStmt &) { Init(IoStmtKind::Wait); } Enter(const parser::WriteStmt &)42 void Enter(const parser::WriteStmt &) { Init(IoStmtKind::Write); } 43 44 void Enter( 45 const parser::Statement<common::Indirection<parser::FormatStmt>> &); 46 47 void Enter(const parser::ConnectSpec &); 48 void Enter(const parser::ConnectSpec::CharExpr &); 49 void Enter(const parser::ConnectSpec::Newunit &); 50 void Enter(const parser::ConnectSpec::Recl &); 51 void Enter(const parser::EndLabel &); 52 void Enter(const parser::EorLabel &); 53 void Enter(const parser::ErrLabel &); 54 void Enter(const parser::FileUnitNumber &); 55 void Enter(const parser::Format &); 56 void Enter(const parser::IdExpr &); 57 void Enter(const parser::IdVariable &); 58 void Enter(const parser::InputItem &); 59 void Enter(const parser::InquireSpec &); 60 void Enter(const parser::InquireSpec::CharVar &); 61 void Enter(const parser::InquireSpec::IntVar &); 62 void Enter(const parser::InquireSpec::LogVar &); 63 void Enter(const parser::IoControlSpec &); 64 void Enter(const parser::IoControlSpec::Asynchronous &); 65 void Enter(const parser::IoControlSpec::CharExpr &); 66 void Enter(const parser::IoControlSpec::Pos &); 67 void Enter(const parser::IoControlSpec::Rec &); 68 void Enter(const parser::IoControlSpec::Size &); 69 void Enter(const parser::IoUnit &); 70 void Enter(const parser::MsgVariable &); 71 void Enter(const parser::OutputItem &); 72 void Enter(const parser::StatusExpr &); 73 void Enter(const parser::StatVariable &); 74 75 void Leave(const parser::BackspaceStmt &); 76 void Leave(const parser::CloseStmt &); 77 void Leave(const parser::EndfileStmt &); 78 void Leave(const parser::FlushStmt &); 79 void Leave(const parser::InquireStmt &); 80 void Leave(const parser::OpenStmt &); 81 void Leave(const parser::PrintStmt &); 82 void Leave(const parser::ReadStmt &); 83 void Leave(const parser::RewindStmt &); 84 void Leave(const parser::WaitStmt &); 85 void Leave(const parser::WriteStmt &); 86 87 private: 88 // Presence flag values. ENUM_CLASS(Flag,IoControlList,InternalUnit,NumberUnit,StarUnit,CharFmt,LabelFmt,StarFmt,FmtOrNml,KnownAccess,AccessDirect,AccessStream,AdvanceYes,AsynchronousYes,KnownStatus,StatusNew,StatusReplace,StatusScratch,DataList)89 ENUM_CLASS(Flag, IoControlList, InternalUnit, NumberUnit, StarUnit, CharFmt, 90 LabelFmt, StarFmt, FmtOrNml, KnownAccess, AccessDirect, AccessStream, 91 AdvanceYes, AsynchronousYes, KnownStatus, StatusNew, StatusReplace, 92 StatusScratch, DataList) 93 94 template<typename R, typename T> std::optional<R> GetConstExpr(const T &x) { 95 using DefaultCharConstantType = 96 evaluate::Type<common::TypeCategory::Character, 1>; 97 if (const SomeExpr * expr{GetExpr(x)}) { 98 const auto foldExpr{ 99 evaluate::Fold(context_.foldingContext(), common::Clone(*expr))}; 100 if constexpr (std::is_same_v<R, std::string>) { 101 return evaluate::GetScalarConstantValue<DefaultCharConstantType>( 102 foldExpr); 103 } else { 104 static_assert(std::is_same_v<R, std::int64_t>, "unexpected type"); 105 return evaluate::ToInt64(foldExpr); 106 } 107 } 108 return std::nullopt; 109 } 110 111 void LeaveReadWrite() const; 112 113 void SetSpecifier(IoSpecKind); 114 115 void CheckStringValue( 116 IoSpecKind, const std::string &, const parser::CharBlock &) const; 117 118 void CheckForRequiredSpecifier(IoSpecKind) const; 119 void CheckForRequiredSpecifier(bool, const std::string &) const; 120 void CheckForRequiredSpecifier(IoSpecKind, IoSpecKind) const; 121 void CheckForRequiredSpecifier(IoSpecKind, bool, const std::string &) const; 122 void CheckForRequiredSpecifier(bool, const std::string &, IoSpecKind) const; 123 void CheckForRequiredSpecifier( 124 bool, const std::string &, bool, const std::string &) const; 125 126 void CheckForProhibitedSpecifier(IoSpecKind) const; 127 void CheckForProhibitedSpecifier(IoSpecKind, IoSpecKind) const; 128 void CheckForProhibitedSpecifier(IoSpecKind, bool, const std::string &) const; 129 void CheckForProhibitedSpecifier(bool, const std::string &, IoSpecKind) const; 130 Init(IoStmtKind s)131 void Init(IoStmtKind s) { 132 stmt_ = s; 133 specifierSet_.reset(); 134 flags_.reset(); 135 } 136 137 SemanticsContext &context_; 138 IoStmtKind stmt_ = IoStmtKind::None; 139 common::EnumSet<IoSpecKind, common::IoSpecKind_enumSize> specifierSet_; 140 common::EnumSet<Flag, Flag_enumSize> flags_; 141 }; 142 143 } 144 #endif // FORTRAN_SEMANTICS_CHECK_IO_H_ 145