{"aint", {{"a", SameReal}, MatchingDefaultKIND}, KINDReal},
{"all", {{"mask", SameLogical, Rank::array}, OptionalDIM}, SameLogical,
Rank::dimReduced},
+ {"allocated", {{"array", Anything, Rank::array}}, DefaultLogical},
+ {"allocated", {{"scalar", Anything, Rank::scalar}}, DefaultLogical},
{"anint", {{"a", SameReal}, MatchingDefaultKIND}, KINDReal},
{"any", {{"mask", SameLogical, Rank::array}, OptionalDIM}, SameLogical,
Rank::dimReduced},
// NUM_IMAGES, STOPPED_IMAGES, TEAM_NUMBER, THIS_IMAGE,
// COSHAPE
// TODO: Object characteristic inquiry functions
-// ALLOCATED, ASSOCIATED, EXTENDS_TYPE_OF, IS_CONTIGUOUS,
+// ASSOCIATED, EXTENDS_TYPE_OF, IS_CONTIGUOUS,
// SAME_TYPE, STORAGE_SIZE
// TODO: Type inquiry intrinsic functions - these return constants
// BIT_SIZE, DIGITS, EPSILON, HUGE, KIND, MAXEXPONENT, MINEXPONENT,
std::move(arguments)};
}
+// Applies any semantic checks peculiar to an intrinsic.
+static bool ApplySpecificChecks(
+ SpecificCall &call, parser::ContextualMessages &messages) {
+ bool ok{true};
+ const std::string &name{call.specificIntrinsic.name};
+ if (name == "allocated") {
+ if (const auto &arg{call.arguments[0]}) {
+ if (const auto *expr{arg->UnwrapExpr()}) {
+ if (const Symbol * symbol{GetLastSymbol(*expr)}) {
+ ok = symbol->has<semantics::ObjectEntityDetails>() &&
+ symbol->attrs().test(semantics::Attr::ALLOCATABLE);
+ }
+ }
+ }
+ if (!ok) {
+ messages.Say(
+ "Argument of ALLOCATED() must be an ALLOCATABLE object or component"_err_en_US);
+ }
+ } else if (name == "present") {
+ if (const auto &arg{call.arguments[0]}) {
+ if (const auto *expr{arg->UnwrapExpr()}) {
+ if (const Symbol * symbol{UnwrapWholeSymbolDataRef(*expr)}) {
+ ok = symbol->attrs().test(semantics::Attr::OPTIONAL);
+ }
+ }
+ }
+ if (!ok) {
+ messages.Say(
+ "Argument of PRESENT() must be the name of an OPTIONAL dummy argument"_err_en_US);
+ }
+ }
+ return ok;
+};
+
// Probe the configured intrinsic procedure pattern tables in search of a
// match for a given procedure reference.
std::optional<SpecificCall> IntrinsicProcTable::Implementation::Probe(
CHECK(localBuffer.empty());
if (auto specificCall{
iter->second->Match(call, defaults_, arguments, localContext)}) {
- // Apply any semantic checks peculiar to the intrinsic
- if (call.name == "present") {
- bool ok{false};
- if (const auto &arg{specificCall->arguments[0]}) {
- if (const auto *expr{arg->UnwrapExpr()}) {
- if (const Symbol * symbol{UnwrapWholeSymbolDataRef(*expr)}) {
- ok = symbol->attrs().test(semantics::Attr::OPTIONAL);
- }
- }
- }
- if (!ok) {
- localMessages.Say(
- "Argument of PRESENT() must be the name of an OPTIONAL dummy argument"_err_en_US);
- }
- }
+ ApplySpecificChecks(*specificCall, localMessages);
if (finalBuffer != nullptr) {
finalBuffer->Annex(std::move(localBuffer));
}
} andOperand;
inline std::optional<Expr> AndOperand::Parse(ParseState &state) {
- static constexpr auto op{attempt(".NOT."_tok)};
- int complements{0};
- while (op.Parse(state)) {
- ++complements;
+ static constexpr auto notOp{attempt(".NOT."_tok >> andOperand)};
+ if (std::optional<Expr> negation{notOp.Parse(state)}) {
+ return Expr{Expr::NOT{std::move(*negation)}};
+ } else {
+ return level4Expr.Parse(state);
}
- std::optional<Expr> result{level4Expr.Parse(state)};
- if (result.has_value()) {
- while (complements-- > 0) {
- result = Expr{Expr::NOT{std::move(*result)}};
- }
- }
- return result;
}
// R1015 or-operand -> [or-operand and-op] and-operand
using resultType = Expr;
constexpr OrOperand() {}
static inline std::optional<Expr> Parse(ParseState &state) {
- std::optional<Expr> result{andOperand.Parse(state)};
+ static constexpr auto operand{sourced(andOperand)};
+ std::optional<Expr> result{operand.Parse(state)};
if (result) {
auto source{result->source};
std::function<Expr(Expr &&)> logicalAnd{[&result](Expr &&right) {