mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 14:31:03 +01:00
@@ -60,6 +60,10 @@ message OperatorExpression {
|
||||
BitwiseXor = 17;
|
||||
BitShiftLeft = 18;
|
||||
BitShiftRight = 19;
|
||||
Less = 20;
|
||||
LessEq = 21;
|
||||
Greater = 22;
|
||||
GreaterEq = 23;
|
||||
}
|
||||
optional Operator op = 1;
|
||||
repeated Expression arguments = 2;
|
||||
|
||||
@@ -149,6 +149,18 @@ static auto OperatorToCarbon(const Fuzzing::OperatorExpression& operator_expr,
|
||||
case Fuzzing::OperatorExpression::Eq:
|
||||
BinaryOperatorToCarbon(arg0, " == ", arg1, out);
|
||||
break;
|
||||
case Fuzzing::OperatorExpression::Less:
|
||||
BinaryOperatorToCarbon(arg0, " < ", arg1, out);
|
||||
break;
|
||||
case Fuzzing::OperatorExpression::LessEq:
|
||||
BinaryOperatorToCarbon(arg0, " <= ", arg1, out);
|
||||
break;
|
||||
case Fuzzing::OperatorExpression::GreaterEq:
|
||||
BinaryOperatorToCarbon(arg0, " >= ", arg1, out);
|
||||
break;
|
||||
case Fuzzing::OperatorExpression::Greater:
|
||||
BinaryOperatorToCarbon(arg0, " > ", arg1, out);
|
||||
break;
|
||||
|
||||
case Fuzzing::OperatorExpression::Or:
|
||||
BinaryOperatorToCarbon(arg0, " or ", arg1, out);
|
||||
|
||||
@@ -32,13 +32,15 @@ auto IntrinsicExpression::FindIntrinsic(std::string_view name,
|
||||
{"delete", Intrinsic::Dealloc},
|
||||
{"rand", Intrinsic::Rand},
|
||||
{"int_eq", Intrinsic::IntEq},
|
||||
{"int_compare", Intrinsic::IntCompare},
|
||||
{"int_bit_complement", Intrinsic::IntBitComplement},
|
||||
{"int_bit_and", Intrinsic::IntBitAnd},
|
||||
{"int_bit_or", Intrinsic::IntBitOr},
|
||||
{"int_bit_xor", Intrinsic::IntBitXor},
|
||||
{"int_left_shift", Intrinsic::IntLeftShift},
|
||||
{"int_right_shift", Intrinsic::IntRightShift},
|
||||
{"str_eq", Intrinsic::StrEq}});
|
||||
{"str_eq", Intrinsic::StrEq},
|
||||
{"str_compare", Intrinsic::StrCompare}});
|
||||
name.remove_prefix(std::strlen("__intrinsic_"));
|
||||
auto it = intrinsic_map.find(name);
|
||||
if (it == intrinsic_map.end()) {
|
||||
@@ -60,6 +62,8 @@ auto IntrinsicExpression::name() const -> std::string_view {
|
||||
return "__intrinsic_rand";
|
||||
case IntrinsicExpression::Intrinsic::IntEq:
|
||||
return "__intrinsic_int_eq";
|
||||
case IntrinsicExpression::Intrinsic::IntCompare:
|
||||
return "__intrinsic_int_compare";
|
||||
case IntrinsicExpression::Intrinsic::IntBitComplement:
|
||||
return "__intrinsic_int_bit_complement";
|
||||
case IntrinsicExpression::Intrinsic::IntBitAnd:
|
||||
@@ -74,6 +78,8 @@ auto IntrinsicExpression::name() const -> std::string_view {
|
||||
return "__intrinsic_int_right_shift";
|
||||
case IntrinsicExpression::Intrinsic::StrEq:
|
||||
return "__intrinsic_str_eq";
|
||||
case IntrinsicExpression::Intrinsic::StrCompare:
|
||||
return "__intrinsic_str_compare";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,6 +137,14 @@ auto ToString(Operator op) -> std::string_view {
|
||||
return "==";
|
||||
case Operator::Mod:
|
||||
return "%";
|
||||
case Operator::Less:
|
||||
return "<";
|
||||
case Operator::LessEq:
|
||||
return "<=";
|
||||
case Operator::Greater:
|
||||
return ">";
|
||||
case Operator::GreaterEq:
|
||||
return ">=";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -124,6 +124,10 @@ enum class Operator {
|
||||
Complement,
|
||||
Deref,
|
||||
Eq,
|
||||
Less,
|
||||
LessEq,
|
||||
Greater,
|
||||
GreaterEq,
|
||||
Mul,
|
||||
Mod,
|
||||
Neg,
|
||||
@@ -676,6 +680,8 @@ class IntrinsicExpression : public Expression {
|
||||
Rand,
|
||||
IntEq,
|
||||
StrEq,
|
||||
StrCompare,
|
||||
IntCompare,
|
||||
IntBitAnd,
|
||||
IntBitOr,
|
||||
IntBitXor,
|
||||
|
||||
@@ -57,6 +57,10 @@ impl forall [U1:! Type, U2:! Type, U3:! Type,
|
||||
// Comparison interfaces.
|
||||
// ----------------------
|
||||
|
||||
// ----------------------
|
||||
// EQUAL
|
||||
// ----------------------
|
||||
|
||||
interface EqWith(U:! Type) {
|
||||
fn Equal[me: Self](other: U) -> bool;
|
||||
// TODO: NotEqual with default impl
|
||||
@@ -86,6 +90,180 @@ impl String as EqWith(Self) {
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------
|
||||
// COMPARE
|
||||
// ----------------------
|
||||
|
||||
choice Ordering {
|
||||
Less,
|
||||
Equivalent,
|
||||
Greater,
|
||||
Incomparable
|
||||
}
|
||||
|
||||
interface CompareWith(U:! Type) {
|
||||
fn Compare[me: Self](u: U) -> Ordering;
|
||||
// TODO: Add `default fn` for Less, LessOrEquivalent, Greater, and GreaterOrEquivalent once it's available.
|
||||
}
|
||||
// TODO: constraint Ordered { ... }
|
||||
|
||||
impl i32 as CompareWith(Self) {
|
||||
fn Compare[me: Self](other: Self) -> Ordering {
|
||||
var comp: i32 = __intrinsic_int_compare(me, other);
|
||||
if (comp == -1) {
|
||||
return Ordering.Less();
|
||||
}
|
||||
if (comp == 0) {
|
||||
return Ordering.Equivalent();
|
||||
}
|
||||
if (comp == 1) {
|
||||
return Ordering.Greater();
|
||||
}
|
||||
return Ordering.Incomparable();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
impl String as CompareWith(Self) {
|
||||
fn Compare[me: Self](other: Self) -> Ordering {
|
||||
var comp: i32 = __intrinsic_str_compare(me, other);
|
||||
if (comp == -1) {
|
||||
return Ordering.Less();
|
||||
}
|
||||
if (comp == 0) {
|
||||
return Ordering.Equivalent();
|
||||
}
|
||||
if (comp == 1) {
|
||||
return Ordering.Greater();
|
||||
}
|
||||
return Ordering.Incomparable();
|
||||
}
|
||||
}
|
||||
|
||||
interface LessWith(U:! Type) {
|
||||
fn Less[me: Self](other: U) -> Bool;
|
||||
}
|
||||
|
||||
interface LessEqWith(U:! Type) {
|
||||
fn LessEq[me: Self](other: U) -> Bool;
|
||||
}
|
||||
|
||||
interface GreaterWith(U:! Type) {
|
||||
fn Greater[me: Self](other: U) -> Bool;
|
||||
}
|
||||
|
||||
interface GreaterEqWith(U:! Type) {
|
||||
fn GreaterEq[me: Self](other: U) -> Bool;
|
||||
}
|
||||
|
||||
impl i32 as LessWith(Self) {
|
||||
fn Less[me: Self](other: Self) -> Bool {
|
||||
var comp: Ordering = me.(CompareWith(i32).Compare)(other);
|
||||
match (comp) {
|
||||
case Ordering.Less() => {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
impl String as LessWith(Self) {
|
||||
fn Less[me: Self](other: Self) -> Bool {
|
||||
var comp: Ordering = me.(CompareWith(String).Compare)(other);
|
||||
match(comp){
|
||||
case Ordering.Less() => {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
impl i32 as LessEqWith(Self) {
|
||||
fn LessEq[me: Self](other: Self) -> Bool {
|
||||
var comp: Ordering = me.(CompareWith(i32).Compare)(other);
|
||||
match(comp){
|
||||
case Ordering.Less() => {
|
||||
return true;
|
||||
}
|
||||
case Ordering.Equivalent() => {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
impl String as LessEqWith(Self) {
|
||||
fn LessEq[me: Self](other: Self) -> Bool {
|
||||
var comp: Ordering = me.(CompareWith(String).Compare)(other);
|
||||
match(comp){
|
||||
case Ordering.Less() => {
|
||||
return true;
|
||||
}
|
||||
case Ordering.Equivalent() => {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
impl i32 as GreaterWith(Self) {
|
||||
fn Greater[me: Self](other: Self) -> Bool {
|
||||
var comp: Ordering = me.(CompareWith(i32).Compare)(other);
|
||||
match(comp){
|
||||
case Ordering.Greater() => {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
impl String as GreaterWith(Self) {
|
||||
fn Greater[me: Self](other: Self) -> Bool {
|
||||
var comp: Ordering = me.(CompareWith(String).Compare)(other);
|
||||
match(comp){
|
||||
case Ordering.Greater() => {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
impl i32 as GreaterEqWith(Self) {
|
||||
fn GreaterEq[me: Self](other: Self) -> Bool {
|
||||
var comp: Ordering = me.(CompareWith(i32).Compare)(other);
|
||||
match(comp){
|
||||
case Ordering.Greater() => {
|
||||
return true;
|
||||
}
|
||||
case Ordering.Equivalent() => {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
impl String as GreaterEqWith(Self) {
|
||||
fn GreaterEq[me: Self](other: Self) -> Bool {
|
||||
var comp: Ordering = me.(CompareWith(String).Compare)(other);
|
||||
match(comp){
|
||||
case Ordering.Greater() => {
|
||||
return true;
|
||||
}
|
||||
case Ordering.Equivalent() => {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------
|
||||
// Arithmetic interfaces.
|
||||
// ----------------------
|
||||
|
||||
@@ -53,6 +53,14 @@ static auto OperatorToProtoEnum(const Operator op)
|
||||
return Fuzzing::OperatorExpression::And;
|
||||
case Operator::Eq:
|
||||
return Fuzzing::OperatorExpression::Eq;
|
||||
case Operator::Less:
|
||||
return Fuzzing::OperatorExpression::Less;
|
||||
case Operator::LessEq:
|
||||
return Fuzzing::OperatorExpression::LessEq;
|
||||
case Operator::Greater:
|
||||
return Fuzzing::OperatorExpression::Greater;
|
||||
case Operator::GreaterEq:
|
||||
return Fuzzing::OperatorExpression::GreaterEq;
|
||||
case Operator::Mul:
|
||||
return Fuzzing::OperatorExpression::Mul;
|
||||
case Operator::Mod:
|
||||
|
||||
@@ -29,6 +29,11 @@ class Builtins {
|
||||
|
||||
// Comparison.
|
||||
EqWith,
|
||||
LessWith,
|
||||
LessEqWith,
|
||||
GreaterWith,
|
||||
GreaterEqWith,
|
||||
CompareWith,
|
||||
|
||||
// Arithmetic.
|
||||
Negate,
|
||||
@@ -51,6 +56,10 @@ class Builtins {
|
||||
static constexpr Builtin As = Builtin::As;
|
||||
static constexpr Builtin ImplicitAs = Builtin::ImplicitAs;
|
||||
static constexpr Builtin EqWith = Builtin::EqWith;
|
||||
static constexpr Builtin LessWith = Builtin::LessWith;
|
||||
static constexpr Builtin LessEqWith = Builtin::LessEqWith;
|
||||
static constexpr Builtin GreaterWith = Builtin::GreaterWith;
|
||||
static constexpr Builtin GreaterEqWith = Builtin::GreaterEqWith;
|
||||
static constexpr Builtin Negate = Builtin::Negate;
|
||||
static constexpr Builtin AddWith = Builtin::AddWith;
|
||||
static constexpr Builtin SubWith = Builtin::SubWith;
|
||||
@@ -62,6 +71,7 @@ class Builtins {
|
||||
static constexpr Builtin BitXorWith = Builtin::BitXorWith;
|
||||
static constexpr Builtin LeftShiftWith = Builtin::LeftShiftWith;
|
||||
static constexpr Builtin RightShiftWith = Builtin::RightShiftWith;
|
||||
static constexpr Builtin CompareWith = Builtin::CompareWith;
|
||||
|
||||
// Register a declaration that might be a builtin.
|
||||
void Register(Nonnull<const Declaration*> decl);
|
||||
@@ -78,9 +88,11 @@ class Builtins {
|
||||
private:
|
||||
static constexpr int NumBuiltins = static_cast<int>(Builtin::Last) + 1;
|
||||
static constexpr const char* BuiltinNames[NumBuiltins] = {
|
||||
"As", "ImplicitAs", "EqWith", "Negate", "AddWith",
|
||||
"SubWith", "MulWith", "ModWith", "BitComplement", "BitAndWith",
|
||||
"BitOrWith", "BitXorWith", "LeftShiftWith", "RightShiftWith"};
|
||||
"As", "ImplicitAs", "EqWith", "LessWith",
|
||||
"LessEqWith", "GreaterWith", "GreaterEqWith", "CompareWith",
|
||||
"Negate", "AddWith", "SubWith", "MulWith",
|
||||
"ModWith", "BitComplement", "BitAndWith", "BitOrWith",
|
||||
"BitXorWith", "LeftShiftWith", "RightShiftWith"};
|
||||
|
||||
std::optional<Nonnull<const Declaration*>> builtins_[NumBuiltins] = {};
|
||||
};
|
||||
|
||||
@@ -214,6 +214,10 @@ auto Interpreter::EvalPrim(Operator op, Nonnull<const Value*> static_type,
|
||||
return &cast<TypeOfConstraintType>(static_type)->constraint_type();
|
||||
case Operator::As:
|
||||
case Operator::Eq:
|
||||
case Operator::Less:
|
||||
case Operator::LessEq:
|
||||
case Operator::Greater:
|
||||
case Operator::GreaterEq:
|
||||
case Operator::BitwiseOr:
|
||||
case Operator::BitwiseXor:
|
||||
case Operator::BitShiftLeft:
|
||||
@@ -1227,6 +1231,36 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
|
||||
auto result = arena_->New<BoolValue>(lhs == rhs);
|
||||
return todo_.FinishAction(result);
|
||||
}
|
||||
case IntrinsicExpression::Intrinsic::IntCompare: {
|
||||
CARBON_CHECK(args.size() == 2);
|
||||
auto lhs = cast<IntValue>(*args[0]).value();
|
||||
auto rhs = cast<IntValue>(*args[1]).value();
|
||||
if (lhs < rhs) {
|
||||
auto result = arena_->New<IntValue>(-1);
|
||||
return todo_.FinishAction(result);
|
||||
}
|
||||
if (lhs == rhs) {
|
||||
auto result = arena_->New<IntValue>(0);
|
||||
return todo_.FinishAction(result);
|
||||
}
|
||||
auto result = arena_->New<IntValue>(1);
|
||||
return todo_.FinishAction(result);
|
||||
}
|
||||
case IntrinsicExpression::Intrinsic::StrCompare: {
|
||||
CARBON_CHECK(args.size() == 2);
|
||||
auto& lhs = cast<StringValue>(*args[0]).value();
|
||||
auto& rhs = cast<StringValue>(*args[1]).value();
|
||||
if (lhs < rhs) {
|
||||
auto result = arena_->New<IntValue>(-1);
|
||||
return todo_.FinishAction(result);
|
||||
}
|
||||
if (lhs == rhs) {
|
||||
auto result = arena_->New<IntValue>(0);
|
||||
return todo_.FinishAction(result);
|
||||
}
|
||||
auto result = arena_->New<IntValue>(1);
|
||||
return todo_.FinishAction(result);
|
||||
}
|
||||
case IntrinsicExpression::Intrinsic::IntBitComplement: {
|
||||
CARBON_CHECK(args.size() == 1);
|
||||
return todo_.FinishAction(
|
||||
|
||||
@@ -2086,6 +2086,62 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
|
||||
op.set_rewritten_form(*converted);
|
||||
return Success();
|
||||
}
|
||||
case Operator::Less: {
|
||||
ErrorOr<Nonnull<Expression*>> converted = BuildBuiltinMethodCall(
|
||||
impl_scope, op.arguments()[0],
|
||||
BuiltinInterfaceName{Builtins::LessWith, ts[1]},
|
||||
BuiltinMethodCall{"Less", op.arguments()[1]});
|
||||
if (!converted.ok()) {
|
||||
// We couldn't find a matching `impl`.
|
||||
return CompilationError(e->source_loc())
|
||||
<< *ts[0] << " is not less comparable with " << *ts[1]
|
||||
<< " (" << converted.error().message() << ")";
|
||||
}
|
||||
op.set_rewritten_form(*converted);
|
||||
return Success();
|
||||
}
|
||||
case Operator::LessEq: {
|
||||
ErrorOr<Nonnull<Expression*>> converted = BuildBuiltinMethodCall(
|
||||
impl_scope, op.arguments()[0],
|
||||
BuiltinInterfaceName{Builtins::LessEqWith, ts[1]},
|
||||
BuiltinMethodCall{"LessEq", op.arguments()[1]});
|
||||
if (!converted.ok()) {
|
||||
// We couldn't find a matching `impl`.
|
||||
return CompilationError(e->source_loc())
|
||||
<< *ts[0] << " is not less equal comparable with " << *ts[1]
|
||||
<< " (" << converted.error().message() << ")";
|
||||
}
|
||||
op.set_rewritten_form(*converted);
|
||||
return Success();
|
||||
}
|
||||
case Operator::GreaterEq: {
|
||||
ErrorOr<Nonnull<Expression*>> converted = BuildBuiltinMethodCall(
|
||||
impl_scope, op.arguments()[0],
|
||||
BuiltinInterfaceName{Builtins::GreaterEqWith, ts[1]},
|
||||
BuiltinMethodCall{"GreaterEq", op.arguments()[1]});
|
||||
if (!converted.ok()) {
|
||||
// We couldn't find a matching `impl`.
|
||||
return CompilationError(e->source_loc())
|
||||
<< *ts[0] << " is not greater equal comparable with "
|
||||
<< *ts[1] << " (" << converted.error().message() << ")";
|
||||
}
|
||||
op.set_rewritten_form(*converted);
|
||||
return Success();
|
||||
}
|
||||
case Operator::Greater: {
|
||||
ErrorOr<Nonnull<Expression*>> converted = BuildBuiltinMethodCall(
|
||||
impl_scope, op.arguments()[0],
|
||||
BuiltinInterfaceName{Builtins::GreaterWith, ts[1]},
|
||||
BuiltinMethodCall{"Greater", op.arguments()[1]});
|
||||
if (!converted.ok()) {
|
||||
// We couldn't find a matching `impl`.
|
||||
return CompilationError(e->source_loc())
|
||||
<< *ts[0] << " is not greater comparable with " << *ts[1]
|
||||
<< " (" << converted.error().message() << ")";
|
||||
}
|
||||
op.set_rewritten_form(*converted);
|
||||
return Success();
|
||||
}
|
||||
case Operator::Deref:
|
||||
CARBON_RETURN_IF_ERROR(
|
||||
ExpectPointerType(e->source_loc(), "*", ts[0]));
|
||||
@@ -2311,6 +2367,21 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
|
||||
e->set_value_category(ValueCategory::Let);
|
||||
return Success();
|
||||
}
|
||||
case IntrinsicExpression::Intrinsic::IntCompare: {
|
||||
if (args.size() != 2) {
|
||||
return CompilationError(e->source_loc())
|
||||
<< "__intrinsic_int_compare takes 2 arguments";
|
||||
}
|
||||
CARBON_RETURN_IF_ERROR(ExpectExactType(
|
||||
e->source_loc(), "__intrinsic_int_compare argument 1",
|
||||
arena_->New<IntType>(), &args[0]->static_type(), impl_scope));
|
||||
CARBON_RETURN_IF_ERROR(ExpectExactType(
|
||||
e->source_loc(), "__intrinsic_int_compare argument 2",
|
||||
arena_->New<IntType>(), &args[1]->static_type(), impl_scope));
|
||||
e->set_static_type(arena_->New<IntType>());
|
||||
e->set_value_category(ValueCategory::Let);
|
||||
return Success();
|
||||
}
|
||||
case IntrinsicExpression::Intrinsic::StrEq: {
|
||||
if (args.size() != 2) {
|
||||
return CompilationError(e->source_loc())
|
||||
@@ -2326,6 +2397,21 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
|
||||
e->set_value_category(ValueCategory::Let);
|
||||
return Success();
|
||||
}
|
||||
case IntrinsicExpression::Intrinsic::StrCompare: {
|
||||
if (args.size() != 2) {
|
||||
return CompilationError(e->source_loc())
|
||||
<< "__intrinsic_str_compare takes 2 arguments";
|
||||
}
|
||||
CARBON_RETURN_IF_ERROR(ExpectExactType(
|
||||
e->source_loc(), "__intrinsic_str_compare argument 1",
|
||||
arena_->New<StringType>(), &args[0]->static_type(), impl_scope));
|
||||
CARBON_RETURN_IF_ERROR(ExpectExactType(
|
||||
e->source_loc(), "__intrinsic_str_compare argument 2",
|
||||
arena_->New<StringType>(), &args[1]->static_type(), impl_scope));
|
||||
e->set_static_type(arena_->New<IntType>());
|
||||
e->set_value_category(ValueCategory::Let);
|
||||
return Success();
|
||||
}
|
||||
case IntrinsicExpression::Intrinsic::IntBitComplement:
|
||||
if (args.size() != 1) {
|
||||
return CompilationError(e->source_loc())
|
||||
|
||||
@@ -65,6 +65,8 @@ FALSE "false"
|
||||
FN "fn"
|
||||
FN_TYPE "__Fn"
|
||||
FORALL "forall"
|
||||
GREATER ">"
|
||||
GREATER_EQUAL ">="
|
||||
GREATER_GREATER ">>"
|
||||
IF "if"
|
||||
IMPL "impl"
|
||||
@@ -74,6 +76,8 @@ IS "is"
|
||||
LEFT_CURLY_BRACE "{"
|
||||
LEFT_PARENTHESIS "("
|
||||
LEFT_SQUARE_BRACKET "["
|
||||
LESS "<"
|
||||
LESS_EQUAL "<="
|
||||
LESS_LESS "<<"
|
||||
LET "let"
|
||||
LIBRARY "library"
|
||||
@@ -161,7 +165,9 @@ operand_start [(A-Za-z0-9_\"]
|
||||
{FN_TYPE} { return CARBON_SIMPLE_TOKEN(FN_TYPE); }
|
||||
{FN} { return CARBON_SIMPLE_TOKEN(FN); }
|
||||
{FORALL} { return CARBON_SIMPLE_TOKEN(FORALL); }
|
||||
{GREATER_EQUAL} { return CARBON_SIMPLE_TOKEN(GREATER_EQUAL); }
|
||||
{GREATER_GREATER} { return CARBON_SIMPLE_TOKEN(GREATER_GREATER); }
|
||||
{GREATER} { return CARBON_SIMPLE_TOKEN(GREATER); }
|
||||
{IF} { return CARBON_SIMPLE_TOKEN(IF); }
|
||||
{IMPL} { return CARBON_SIMPLE_TOKEN(IMPL); }
|
||||
{IMPORT} { return CARBON_SIMPLE_TOKEN(IMPORT); }
|
||||
@@ -170,7 +176,9 @@ operand_start [(A-Za-z0-9_\"]
|
||||
{LEFT_CURLY_BRACE} { return CARBON_SIMPLE_TOKEN(LEFT_CURLY_BRACE); }
|
||||
{LEFT_PARENTHESIS} { return CARBON_SIMPLE_TOKEN(LEFT_PARENTHESIS); }
|
||||
{LEFT_SQUARE_BRACKET} { return CARBON_SIMPLE_TOKEN(LEFT_SQUARE_BRACKET); }
|
||||
{LESS_EQUAL} { return CARBON_SIMPLE_TOKEN(LESS_EQUAL); }
|
||||
{LESS_LESS} { return CARBON_SIMPLE_TOKEN(LESS_LESS); }
|
||||
{LESS} { return CARBON_SIMPLE_TOKEN(LESS); }
|
||||
{LET} { return CARBON_SIMPLE_TOKEN(LET); }
|
||||
{LIBRARY} { return CARBON_SIMPLE_TOKEN(LIBRARY); }
|
||||
{MATCH} { return CARBON_SIMPLE_TOKEN(MATCH); }
|
||||
|
||||
@@ -190,6 +190,7 @@
|
||||
%type <std::vector<Nonnull<AlternativeSignature*>>> alternative_list_contents
|
||||
%type <BisonWrap<Match::Clause>> clause
|
||||
%type <std::vector<Match::Clause>> clause_list
|
||||
%type <Operator> comparison_operator;
|
||||
|
||||
%token
|
||||
// Most tokens have their spelling defined in lexer.lpp.
|
||||
@@ -228,6 +229,8 @@
|
||||
FN
|
||||
FN_TYPE
|
||||
FORALL
|
||||
GREATER
|
||||
GREATER_EQUAL
|
||||
GREATER_GREATER
|
||||
IF
|
||||
IMPL
|
||||
@@ -237,6 +240,8 @@
|
||||
LEFT_CURLY_BRACE
|
||||
LEFT_PARENTHESIS
|
||||
LEFT_SQUARE_BRACKET
|
||||
LESS
|
||||
LESS_EQUAL
|
||||
LESS_LESS
|
||||
LET
|
||||
LIBRARY
|
||||
@@ -584,12 +589,25 @@ comparison_operand:
|
||||
ref_deref_expression
|
||||
| value_expression
|
||||
;
|
||||
/* TODO: Add NOT_EQUAL */
|
||||
comparison_operator:
|
||||
EQUAL_EQUAL
|
||||
{ $$ = Operator::Eq; }
|
||||
| LESS
|
||||
{ $$ = Operator::Less; }
|
||||
| LESS_EQUAL
|
||||
{ $$ = Operator::LessEq; }
|
||||
| GREATER
|
||||
{ $$ = Operator::Greater; }
|
||||
| GREATER_EQUAL
|
||||
{ $$ = Operator::GreaterEq; }
|
||||
;
|
||||
comparison_expression:
|
||||
value_expression
|
||||
| comparison_operand EQUAL_EQUAL comparison_operand
|
||||
| comparison_operand comparison_operator comparison_operand
|
||||
{
|
||||
$$ = arena->New<OperatorExpression>(
|
||||
context.source_loc(), Operator::Eq,
|
||||
context.source_loc(), $2,
|
||||
std::vector<Nonnull<Expression*>>({$1, $3}));
|
||||
}
|
||||
;
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
// 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
|
||||
//
|
||||
// RUN: %{explorer} %s 2>&1 | \
|
||||
// RUN: %{FileCheck} --match-full-lines --allow-unused-prefixes=false %s
|
||||
// RUN: %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
|
||||
// RUN: %{FileCheck} --match-full-lines --allow-unused-prefixes %s
|
||||
// AUTOUPDATE: %{explorer} %s
|
||||
// CHECK: strings less: 1
|
||||
// CHECK: ints less: 0
|
||||
// CHECK: strings less eq: 1
|
||||
// CHECK: ints less eq: 1
|
||||
// CHECK: strings greater: 0
|
||||
// CHECK: ints greater: 0
|
||||
// CHECK: strings greater eq: 0
|
||||
// CHECK: ints greater eq: 1
|
||||
// CHECK: result: 0
|
||||
|
||||
package ExplorerTest api;
|
||||
|
||||
fn Main() -> i32 {
|
||||
Print("strings less: {0}", if "hello" < "world" then 1 else 0);
|
||||
Print("ints less: {0}", if 1 < 1 then 1 else 0);
|
||||
Print("strings less eq: {0}", if "hello" <= "world" then 1 else 0);
|
||||
Print("ints less eq: {0}", if 1 <= 1 then 1 else 0);
|
||||
Print("strings greater: {0}", if "hello" > "world" then 1 else 0);
|
||||
Print("ints greater: {0}", if 1 > 1 then 1 else 0);
|
||||
Print("strings greater eq: {0}", if "hello" >= "world" then 1 else 0);
|
||||
Print("ints greater eq: {0}", if 1 >= 1 then 1 else 0);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user