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