if (ctrl.has_value()) {
std::visit(
common::visitors{
- [&](const parser::LoopBounds<parser::ScalarIntExpr> &bounds) {
- auto name{builder_->CreateAddr(
- ToExpression(bounds.name.thing.thing))};
+ [&](const parser::LoopControl::Bounds &bounds) {
+ auto name{
+ builder_->CreateAddr(ToExpression(bounds.name.thing))};
// evaluate e1, e2 [, e3] ...
- auto *e1{
- builder_->CreateExpr(ExprRef(bounds.lower.thing.thing))};
- auto *e2{
- builder_->CreateExpr(ExprRef(bounds.upper.thing.thing))};
+ auto *e1{builder_->CreateExpr(ExprRef(bounds.lower.thing))};
+ auto *e2{builder_->CreateExpr(ExprRef(bounds.upper.thing))};
Statement *e3;
if (bounds.step.has_value()) {
- e3 = builder_->CreateExpr(ExprRef(bounds.step->thing.thing));
+ e3 = builder_->CreateExpr(ExprRef(bounds.step->thing));
} else {
e3 = builder_->CreateExpr(CreateConstant(1));
}
void FinishConstruct(const parser::NonLabelDoStmt *stmt) {
auto &ctrl{std::get<std::optional<parser::LoopControl>>(stmt->t)};
if (ctrl.has_value()) {
- using A = parser::LoopBounds<parser::ScalarIntExpr>;
- if (std::holds_alternative<A>(ctrl->u)) {
+ if (std::holds_alternative<parser::LoopControl::Bounds>(ctrl->u)) {
PopDoContext(stmt);
}
}
if (loopCtrl.has_value()) {
return std::visit(
common::visitors{
- [&](const parser::LoopBounds<parser::ScalarIntExpr> &) {
+ [&](const parser::LoopControl::Bounds &) {
return doMap_.find(stmt)->second.condition;
},
[&](const parser::ScalarLogicalExpr &sle) {
NODE(parser, LockStmt)
NODE(parser::LockStmt, LockStat)
NODE(parser, LogicalLiteralConstant)
- NODE_NAME(parser::LoopBounds<parser::ScalarIntConstantExpr>, "LoopBounds")
- NODE_NAME(parser::LoopBounds<parser::ScalarIntExpr>, "LoopBounds")
+ NODE_NAME(parser::LoopControl::Bounds, "LoopBounds")
+ NODE_NAME(parser::AcImpliedDoControl::Bounds, "LoopBounds")
+ NODE_NAME(parser::DataImpliedDo::Bounds, "LoopBounds")
NODE(parser, LoopControl)
NODE(parser::LoopControl, Concurrent)
NODE(parser, MainProgram)
// R1029 constant-expr -> expr
constexpr auto constantExpr{constant(indirect(expr))};
+constexpr auto scalarExpr{scalar(indirect(expr))};
// R1030 default-char-constant-expr -> default-char-expr
constexpr auto scalarDefaultCharConstantExpr{scalar(defaultChar(constantExpr))};
// R1124 do-variable -> scalar-int-variable-name
constexpr auto doVariable{scalar(integer(name))};
+// NOTE: In loop-control we allow REAL name and bounds too.
+// This means parse them without the integer constraint and check later.
template<typename PA> inline constexpr auto loopBounds(const PA &p) {
- return construct<LoopBounds<typename PA::resultType>>(
- doVariable / "=", p / ",", p, maybe("," >> p));
+ if constexpr (std::is_same_v<typename PA::resultType, ScalarExpr>) {
+ return construct<LoopBounds<ScalarName, typename PA::resultType>>(
+ scalar(name) / "=", p / ",", p, maybe("," >> p));
+ } else {
+ return construct<LoopBounds<DoVariable, typename PA::resultType>>(
+ doVariable / "=", p / ",", p, maybe("," >> p));
+ }
}
// R769 array-constructor -> (/ ac-spec /) | lbracket ac-spec rbracket
// R1129 concurrent-locality -> [locality-spec]...
TYPE_CONTEXT_PARSER("loop control"_en_US,
maybe(","_tok) >>
- (construct<LoopControl>(loopBounds(scalarIntExpr)) ||
+ (construct<LoopControl>(loopBounds(scalarExpr)) ||
construct<LoopControl>(
"WHILE" >> parenthesized(scalarLogicalExpr)) ||
construct<LoopControl>(construct<LoopControl::Concurrent>(
mutator.Post(x);
}
}
-template<typename T, typename V> void Walk(const LoopBounds<T> &x, V &visitor) {
+template<typename A, typename B, typename V>
+void Walk(const LoopBounds<A, B> &x, V &visitor) {
if (visitor.Pre(x)) {
Walk(x.name, visitor);
Walk(x.lower, visitor);
visitor.Post(x);
}
}
-template<typename T, typename M> void Walk(LoopBounds<T> &x, M &mutator) {
+template<typename A, typename B, typename M>
+void Walk(LoopBounds<A, B> &x, M &mutator) {
if (mutator.Pre(x)) {
Walk(x.name, mutator);
Walk(x.lower, mutator);
// R1124 do-variable -> scalar-int-variable-name
using DoVariable = Scalar<Integer<Name>>;
-template<typename A> struct LoopBounds {
+template<typename A, typename B> struct LoopBounds {
LoopBounds(LoopBounds &&that) = default;
- LoopBounds(DoVariable &&n, A &&a, A &&z, std::optional<A> &&s)
+ LoopBounds(A &&n, B &&a, B &&z, std::optional<B> &&s)
: name{std::move(n)}, lower{std::move(a)}, upper{std::move(z)},
step{std::move(s)} {}
LoopBounds &operator=(LoopBounds &&) = default;
- DoVariable name;
- A lower, upper;
- std::optional<A> step;
+ A name;
+ B lower, upper;
+ std::optional<B> step;
};
+using ScalarName = Scalar<Name>;
+using ScalarExpr = Scalar<common::Indirection<Expr>>;
+
// R775 ac-implied-do-control ->
// [integer-type-spec ::] ac-do-variable = scalar-int-expr ,
// scalar-int-expr [, scalar-int-expr]
// R776 ac-do-variable -> do-variable
struct AcImpliedDoControl {
TUPLE_CLASS_BOILERPLATE(AcImpliedDoControl);
- std::tuple<std::optional<IntegerTypeSpec>, LoopBounds<ScalarIntExpr>> t;
+ using Bounds = LoopBounds<DoVariable, ScalarIntExpr>;
+ std::tuple<std::optional<IntegerTypeSpec>, Bounds> t;
};
// R774 ac-implied-do -> ( ac-value-list , ac-implied-do-control )
// R842 data-i-do-variable -> do-variable
struct DataImpliedDo {
TUPLE_CLASS_BOILERPLATE(DataImpliedDo);
- std::tuple<std::list<DataIDoObject>, std::optional<IntegerTypeSpec>,
- LoopBounds<ScalarIntConstantExpr>>
+ using Bounds = LoopBounds<DoVariable, ScalarIntConstantExpr>;
+ std::tuple<std::list<DataIDoObject>, std::optional<IntegerTypeSpec>, Bounds>
t;
};
TUPLE_CLASS_BOILERPLATE(Concurrent);
std::tuple<ConcurrentHeader, std::list<LocalitySpec>> t;
};
- std::variant<LoopBounds<ScalarIntExpr>, ScalarLogicalExpr, Concurrent> u;
+ using Bounds = LoopBounds<ScalarName, ScalarExpr>;
+ std::variant<Bounds, ScalarLogicalExpr, Concurrent> u;
};
// R1121 label-do-stmt -> [do-construct-name :] DO label [loop-control]
// R1220 io-implied-do-control ->
// do-variable = scalar-int-expr , scalar-int-expr [, scalar-int-expr]
-using IoImpliedDoControl = LoopBounds<ScalarIntExpr>;
+using IoImpliedDoControl = LoopBounds<DoVariable, ScalarIntExpr>;
// R1218 io-implied-do -> ( io-implied-do-object-list , io-implied-do-control )
// R1219 io-implied-do-object -> input-item | output-item
void Unparse(const AcSpec &x) { // R770
Walk(x.type, "::"), Walk(x.values, ", ");
}
- template<typename A> void Unparse(const LoopBounds<A> &x) {
+ template<typename A, typename B> void Unparse(const LoopBounds<A, B> &x) {
Walk(x.name), Put('='), Walk(x.lower), Put(','), Walk(x.upper);
Walk(",", x.step);
}
}
void Unparse(const AcImpliedDoControl &x) { // R775
Walk(std::get<std::optional<IntegerTypeSpec>>(x.t), "::");
- Walk(std::get<LoopBounds<ScalarIntExpr>>(x.t));
+ Walk(std::get<AcImpliedDoControl::Bounds>(x.t));
}
void Unparse(const TypeDeclarationStmt &x) { // R801
void Unparse(const DataImpliedDo &x) { // R840, R842
Put('('), Walk(std::get<std::list<DataIDoObject>>(x.t), ", "), Put(',');
Walk(std::get<std::optional<IntegerTypeSpec>>(x.t), "::");
- Walk(std::get<LoopBounds<ScalarIntConstantExpr>>(x.t)), Put(')');
+ Walk(std::get<DataImpliedDo::Bounds>(x.t)), Put(')');
}
void Unparse(const DataStmtValue &x) { // R843
Walk(std::get<std::optional<DataStmtRepeat>>(x.t), "*");
const auto &control{
std::get<parser::AcImpliedDoControl>(impliedDo.value().t)};
const auto &bounds{
- std::get<parser::LoopBounds<parser::ScalarIntExpr>>(control.t)};
+ std::get<parser::AcImpliedDoControl::Bounds>(control.t)};
Analyze(bounds.name);
parser::CharBlock name{bounds.name.thing.thing.source};
int kind{IntType::kind};
void Post(const parser::AllocateObject &);
bool Pre(const parser::PointerAssignmentStmt &);
void Post(const parser::Designator &);
- template<typename T> void Post(const parser::LoopBounds<T> &);
+ template<typename A, typename B>
+ void Post(const parser::LoopBounds<A, B> &x) {
+ ResolveName(*parser::Unwrap<parser::Name>(x.name));
+ }
void Post(const parser::ProcComponentRef &);
bool Pre(const parser::FunctionReference &);
bool Pre(const parser::CallStmt &);
auto &values{std::get<std::list<parser::AcValue>>(x.t)};
auto &control{std::get<parser::AcImpliedDoControl>(x.t)};
auto &type{std::get<std::optional<parser::IntegerTypeSpec>>(control.t)};
- auto &bounds{std::get<parser::LoopBounds<parser::ScalarIntExpr>>(control.t)};
+ auto &bounds{std::get<parser::AcImpliedDoControl::Bounds>(control.t)};
DeclareStatementEntity(bounds.name.thing.thing, type);
Walk(bounds);
Walk(values);
bool ConstructVisitor::Pre(const parser::DataImpliedDo &x) {
auto &objects{std::get<std::list<parser::DataIDoObject>>(x.t)};
auto &type{std::get<std::optional<parser::IntegerTypeSpec>>(x.t)};
- auto &bounds{
- std::get<parser::LoopBounds<parser::ScalarIntConstantExpr>>(x.t)};
+ auto &bounds{std::get<parser::DataImpliedDo::Bounds>(x.t)};
DeclareStatementEntity(bounds.name.thing.thing, type);
Walk(bounds);
Walk(objects);
ResolveDesignator(x);
}
-template<typename T>
-void ResolveNamesVisitor::Post(const parser::LoopBounds<T> &x) {
- ResolveName(x.name.thing.thing);
-}
void ResolveNamesVisitor::Post(const parser::ProcComponentRef &x) {
ResolveStructureComponent(x.v.thing);
}