Files
carbon-lang/toolchain/parser/precedence_test.cpp
T
Jon Meow fa07a016b8 Sync the keyword list (#1097)
I was mainly looking at keywords trying to figure out what needs work and the amount to which it doesn't reflect the design confused me (including some things that we've decided not to include, and some things I'm not aware of discussion about). I figured this cleanup would at least make it somewhat clearer why things are in there.

I'm treating https://github.com/carbon-language/carbon-lang/blob/trunk/docs/design/lexical_conventions/words.md as canonical, with `_` and `xor` as presumably deliberate exceptions. Similarly avoiding symbol tokens because I assume you'll push proposals for the difference.

I dropped the `Keyword` qualifier because `is` makes `IsKeyword` a name conflict, and dropping the qualifier seemed like the more consistent solution (it doesn't do `AmpSymbol`, after all). If we need clarity I might lean towards a separate namespace to avoid naming conflicts.
2022-02-24 13:46:17 -08:00

156 lines
6.9 KiB
C++

// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "toolchain/parser/precedence.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "toolchain/lexer/token_kind.h"
namespace Carbon::Testing {
namespace {
using ::testing::Eq;
TEST(PrecedenceTest, OperatorsAreRecognized) {
EXPECT_TRUE(PrecedenceGroup::ForLeading(TokenKind::Minus()).hasValue());
EXPECT_TRUE(PrecedenceGroup::ForLeading(TokenKind::Tilde()).hasValue());
EXPECT_FALSE(PrecedenceGroup::ForLeading(TokenKind::Slash()).hasValue());
EXPECT_FALSE(PrecedenceGroup::ForLeading(TokenKind::Identifier()).hasValue());
EXPECT_TRUE(
PrecedenceGroup::ForTrailing(TokenKind::Minus(), false).hasValue());
EXPECT_FALSE(
PrecedenceGroup::ForTrailing(TokenKind::Tilde(), false).hasValue());
EXPECT_TRUE(
PrecedenceGroup::ForTrailing(TokenKind::Slash(), true).hasValue());
EXPECT_FALSE(
PrecedenceGroup::ForTrailing(TokenKind::Identifier(), false).hasValue());
EXPECT_TRUE(
PrecedenceGroup::ForTrailing(TokenKind::Minus(), true)->is_binary);
EXPECT_FALSE(
PrecedenceGroup::ForTrailing(TokenKind::MinusMinus(), false)->is_binary);
}
TEST(PrecedenceTest, InfixVsPostfix) {
// A trailing `-` is always infix; a trailing `--` is always postfix.
EXPECT_TRUE(
PrecedenceGroup::ForTrailing(TokenKind::Minus(), false)->is_binary);
EXPECT_FALSE(
PrecedenceGroup::ForTrailing(TokenKind::MinusMinus(), true)->is_binary);
// A trailing `*` is interpreted based on context.
EXPECT_TRUE(PrecedenceGroup::ForTrailing(TokenKind::Star(), true)->is_binary);
EXPECT_FALSE(
PrecedenceGroup::ForTrailing(TokenKind::Star(), false)->is_binary);
// Infix `*` can appear in type contexts; binary `*` cannot.
EXPECT_THAT(PrecedenceGroup::GetPriority(
PrecedenceGroup::ForTrailing(TokenKind::Star(), true)->level,
PrecedenceGroup::ForType()),
Eq(OperatorPriority::Ambiguous));
EXPECT_THAT(PrecedenceGroup::GetPriority(
PrecedenceGroup::ForTrailing(TokenKind::Star(), false)->level,
PrecedenceGroup::ForType()),
Eq(OperatorPriority::LeftFirst));
// Binary `*` can appear in `+` contexts; binary `*` cannot.
EXPECT_THAT(PrecedenceGroup::GetPriority(
PrecedenceGroup::ForTrailing(TokenKind::Star(), true)->level,
PrecedenceGroup::ForTrailing(TokenKind::Plus(), true)->level),
Eq(OperatorPriority::LeftFirst));
EXPECT_THAT(PrecedenceGroup::GetPriority(
PrecedenceGroup::ForTrailing(TokenKind::Star(), false)->level,
PrecedenceGroup::ForTrailing(TokenKind::Plus(), true)->level),
Eq(OperatorPriority::Ambiguous));
}
TEST(PrecedenceTest, Associativity) {
EXPECT_THAT(
PrecedenceGroup::ForLeading(TokenKind::Minus())->GetAssociativity(),
Eq(Associativity::RightToLeft));
EXPECT_THAT(PrecedenceGroup::ForTrailing(TokenKind::PlusPlus(), false)
->level.GetAssociativity(),
Eq(Associativity::LeftToRight));
EXPECT_THAT(PrecedenceGroup::ForTrailing(TokenKind::Plus(), true)
->level.GetAssociativity(),
Eq(Associativity::LeftToRight));
EXPECT_THAT(PrecedenceGroup::ForTrailing(TokenKind::Equal(), true)
->level.GetAssociativity(),
Eq(Associativity::RightToLeft));
EXPECT_THAT(PrecedenceGroup::ForTrailing(TokenKind::PlusEqual(), true)
->level.GetAssociativity(),
Eq(Associativity::None));
}
TEST(PrecedenceTest, DirectRelations) {
EXPECT_THAT(PrecedenceGroup::GetPriority(
PrecedenceGroup::ForTrailing(TokenKind::Star(), true)->level,
PrecedenceGroup::ForTrailing(TokenKind::Plus(), true)->level),
Eq(OperatorPriority::LeftFirst));
EXPECT_THAT(PrecedenceGroup::GetPriority(
PrecedenceGroup::ForTrailing(TokenKind::Plus(), true)->level,
PrecedenceGroup::ForTrailing(TokenKind::Star(), true)->level),
Eq(OperatorPriority::RightFirst));
EXPECT_THAT(PrecedenceGroup::GetPriority(
PrecedenceGroup::ForTrailing(TokenKind::Amp(), true)->level,
PrecedenceGroup::ForTrailing(TokenKind::Less(), true)->level),
Eq(OperatorPriority::LeftFirst));
EXPECT_THAT(PrecedenceGroup::GetPriority(
PrecedenceGroup::ForTrailing(TokenKind::Less(), true)->level,
PrecedenceGroup::ForTrailing(TokenKind::Amp(), true)->level),
Eq(OperatorPriority::RightFirst));
}
TEST(PrecedenceTest, IndirectRelations) {
EXPECT_THAT(PrecedenceGroup::GetPriority(
PrecedenceGroup::ForTrailing(TokenKind::Star(), true)->level,
PrecedenceGroup::ForTrailing(TokenKind::Or(), true)->level),
Eq(OperatorPriority::LeftFirst));
EXPECT_THAT(PrecedenceGroup::GetPriority(
PrecedenceGroup::ForTrailing(TokenKind::Or(), true)->level,
PrecedenceGroup::ForTrailing(TokenKind::Star(), true)->level),
Eq(OperatorPriority::RightFirst));
EXPECT_THAT(
PrecedenceGroup::GetPriority(
*PrecedenceGroup::ForLeading(TokenKind::Tilde()),
PrecedenceGroup::ForTrailing(TokenKind::Equal(), true)->level),
Eq(OperatorPriority::LeftFirst));
EXPECT_THAT(PrecedenceGroup::GetPriority(
PrecedenceGroup::ForTrailing(TokenKind::Equal(), true)->level,
*PrecedenceGroup::ForLeading(TokenKind::Tilde())),
Eq(OperatorPriority::RightFirst));
}
TEST(PrecedenceTest, IncomparableOperators) {
EXPECT_THAT(PrecedenceGroup::GetPriority(
*PrecedenceGroup::ForLeading(TokenKind::Tilde()),
*PrecedenceGroup::ForLeading(TokenKind::Not())),
Eq(OperatorPriority::Ambiguous));
EXPECT_THAT(PrecedenceGroup::GetPriority(
*PrecedenceGroup::ForLeading(TokenKind::Tilde()),
*PrecedenceGroup::ForLeading(TokenKind::Minus())),
Eq(OperatorPriority::Ambiguous));
EXPECT_THAT(PrecedenceGroup::GetPriority(
*PrecedenceGroup::ForLeading(TokenKind::Minus()),
PrecedenceGroup::ForTrailing(TokenKind::Amp(), true)->level),
Eq(OperatorPriority::Ambiguous));
EXPECT_THAT(
PrecedenceGroup::GetPriority(
PrecedenceGroup::ForTrailing(TokenKind::Equal(), true)->level,
PrecedenceGroup::ForTrailing(TokenKind::PipeEqual(), true)->level),
Eq(OperatorPriority::Ambiguous));
EXPECT_THAT(PrecedenceGroup::GetPriority(
PrecedenceGroup::ForTrailing(TokenKind::Plus(), true)->level,
PrecedenceGroup::ForTrailing(TokenKind::Amp(), true)->level),
Eq(OperatorPriority::Ambiguous));
}
} // namespace
} // namespace Carbon::Testing