1use crate::{
2 decl_engine::parsed_id::ParsedDeclId,
3 engine_threading::{
4 DebugWithEngines, DisplayWithEngines, EqWithEngines, HashWithEngines, OrdWithEngines,
5 OrdWithEnginesContext, PartialEqWithEngines, PartialEqWithEnginesContext,
6 },
7 language::{parsed::CodeBlock, *},
8 type_system::TypeBinding,
9 Engines, GenericArgument, TypeId,
10};
11use serde::{Deserialize, Serialize};
12use std::{cmp::Ordering, fmt, hash::Hasher};
13use sway_error::handler::ErrorEmitted;
14use sway_types::{ident::Ident, Span, Spanned};
15
16mod asm;
17mod match_branch;
18mod method_name;
19mod scrutinee;
20pub(crate) use asm::*;
21pub(crate) use match_branch::MatchBranch;
22pub use method_name::MethodName;
23pub use scrutinee::*;
24use sway_ast::intrinsics::Intrinsic;
25
26use super::{FunctionDeclaration, StructDeclaration};
27
28#[derive(Debug, Clone)]
30pub struct Expression {
31 pub kind: ExpressionKind,
32 pub span: Span,
33}
34
35#[derive(Debug, Clone)]
36pub struct FunctionApplicationExpression {
37 pub call_path_binding: TypeBinding<CallPath>,
38 pub resolved_call_path_binding:
39 Option<TypeBinding<ResolvedCallPath<ParsedDeclId<FunctionDeclaration>>>>,
40 pub arguments: Vec<Expression>,
41}
42
43impl EqWithEngines for FunctionApplicationExpression {}
44impl PartialEqWithEngines for FunctionApplicationExpression {
45 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
46 self.call_path_binding.eq(&other.call_path_binding, ctx)
47 && self.arguments.eq(&other.arguments, ctx)
48 }
49}
50
51#[derive(Debug, Clone)]
52pub struct LazyOperatorExpression {
53 pub op: LazyOp,
54 pub lhs: Box<Expression>,
55 pub rhs: Box<Expression>,
56}
57
58impl EqWithEngines for LazyOperatorExpression {}
59impl PartialEqWithEngines for LazyOperatorExpression {
60 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
61 self.op == other.op && self.lhs.eq(&other.lhs, ctx) && self.rhs.eq(&other.rhs, ctx)
62 }
63}
64
65#[derive(Debug, Clone)]
66pub struct TupleIndexExpression {
67 pub prefix: Box<Expression>,
68 pub index: usize,
69 pub index_span: Span,
70}
71
72impl EqWithEngines for TupleIndexExpression {}
73impl PartialEqWithEngines for TupleIndexExpression {
74 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
75 self.prefix.eq(&other.prefix, ctx)
76 && self.index == other.index
77 && self.index_span == other.index_span
78 }
79}
80
81#[derive(Debug, Clone)]
82pub enum ArrayExpression {
83 Explicit {
84 contents: Vec<Expression>,
85 length_span: Option<Span>,
86 },
87 Repeat {
88 value: Box<Expression>,
89 length: Box<Expression>,
90 },
91}
92
93impl EqWithEngines for ArrayExpression {}
94impl PartialEqWithEngines for ArrayExpression {
95 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
96 match (self, other) {
97 (
98 ArrayExpression::Explicit {
99 contents: self_contents,
100 length_span: self_length_span,
101 },
102 ArrayExpression::Explicit {
103 contents: other_contents,
104 length_span: other_length_span,
105 },
106 ) => self_contents.eq(other_contents, ctx) && self_length_span == other_length_span,
107 (
108 ArrayExpression::Repeat {
109 value: self_value,
110 length: self_length,
111 },
112 ArrayExpression::Repeat {
113 value: other_value,
114 length: other_length,
115 },
116 ) => self_value.eq(other_value, ctx) && self_length.eq(other_length, ctx),
117 _ => false,
118 }
119 }
120}
121
122#[derive(Debug, Clone)]
123pub struct StructExpression {
124 pub resolved_call_path_binding:
125 Option<TypeBinding<ResolvedCallPath<ParsedDeclId<StructDeclaration>>>>,
126 pub call_path_binding: TypeBinding<CallPath>,
127 pub fields: Vec<StructExpressionField>,
128}
129
130impl EqWithEngines for StructExpression {}
131impl PartialEqWithEngines for StructExpression {
132 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
133 self.call_path_binding.eq(&other.call_path_binding, ctx)
134 && self.fields.eq(&other.fields, ctx)
135 }
136}
137
138#[derive(Debug, Clone)]
139pub struct IfExpression {
140 pub condition: Box<Expression>,
141 pub then: Box<Expression>,
142 pub r#else: Option<Box<Expression>>,
143}
144
145impl EqWithEngines for IfExpression {}
146impl PartialEqWithEngines for IfExpression {
147 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
148 self.condition.eq(&other.condition, ctx)
149 && self.then.eq(&other.then, ctx)
150 && self.r#else.eq(&other.r#else, ctx)
151 }
152}
153
154#[derive(Debug, Clone)]
155pub struct MatchExpression {
156 pub value: Box<Expression>,
157 pub branches: Vec<MatchBranch>,
158}
159
160impl EqWithEngines for MatchExpression {}
161impl PartialEqWithEngines for MatchExpression {
162 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
163 self.value.eq(&other.value, ctx) && self.branches.eq(&other.branches, ctx)
164 }
165}
166
167#[derive(Debug, Clone)]
168pub struct MethodApplicationExpression {
169 pub method_name_binding: TypeBinding<MethodName>,
170 pub contract_call_params: Vec<StructExpressionField>,
171 pub arguments: Vec<Expression>,
172}
173
174impl EqWithEngines for MethodApplicationExpression {}
175impl PartialEqWithEngines for MethodApplicationExpression {
176 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
177 self.method_name_binding.eq(&other.method_name_binding, ctx)
178 && self
179 .contract_call_params
180 .eq(&other.contract_call_params, ctx)
181 && self.arguments.eq(&other.arguments, ctx)
182 }
183}
184
185#[derive(Debug, Clone)]
186pub struct SubfieldExpression {
187 pub prefix: Box<Expression>,
188 pub field_to_access: Ident,
189}
190
191impl EqWithEngines for SubfieldExpression {}
192impl PartialEqWithEngines for SubfieldExpression {
193 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
194 self.prefix.eq(&other.prefix, ctx) && self.field_to_access == other.field_to_access
195 }
196}
197
198#[derive(Debug, Clone)]
199pub struct AmbiguousSuffix {
200 pub before: Option<TypeBinding<Ident>>,
206 pub suffix: Ident,
210}
211
212impl EqWithEngines for AmbiguousSuffix {}
213impl PartialEqWithEngines for AmbiguousSuffix {
214 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
215 self.before.eq(&other.before, ctx) && self.suffix == other.suffix
216 }
217}
218
219impl Spanned for AmbiguousSuffix {
220 fn span(&self) -> Span {
221 if let Some(before) = &self.before {
222 Span::join(before.span(), &self.suffix.span())
223 } else {
224 self.suffix.span()
225 }
226 }
227}
228
229#[derive(Debug, Clone, Serialize, Deserialize)]
230pub struct QualifiedPathType {
231 pub ty: GenericArgument,
232 pub as_trait: TypeId,
233 pub as_trait_span: Span,
234}
235
236impl HashWithEngines for QualifiedPathType {
237 fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
238 let QualifiedPathType {
239 ty,
240 as_trait,
241 as_trait_span: _,
243 } = self;
244 ty.hash(state, engines);
245 engines.te().get(*as_trait).hash(state, engines);
246 }
247}
248
249impl EqWithEngines for QualifiedPathType {}
250impl PartialEqWithEngines for QualifiedPathType {
251 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
252 let QualifiedPathType {
253 ty,
254 as_trait,
255 as_trait_span: _,
257 } = self;
258 ty.eq(&other.ty, ctx)
259 && ctx
260 .engines()
261 .te()
262 .get(*as_trait)
263 .eq(&ctx.engines().te().get(other.as_trait), ctx)
264 }
265}
266
267impl OrdWithEngines for QualifiedPathType {
268 fn cmp(&self, other: &Self, ctx: &OrdWithEnginesContext) -> Ordering {
269 let QualifiedPathType {
270 ty: l_ty,
271 as_trait: l_as_trait,
272 as_trait_span: _,
274 } = self;
275 let QualifiedPathType {
276 ty: r_ty,
277 as_trait: r_as_trait,
278 as_trait_span: _,
280 } = other;
281 l_ty.cmp(r_ty, ctx).then_with(|| {
282 ctx.engines()
283 .te()
284 .get(*l_as_trait)
285 .cmp(&ctx.engines().te().get(*r_as_trait), ctx)
286 })
287 }
288}
289
290impl DisplayWithEngines for QualifiedPathType {
291 fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
292 write!(
293 f,
294 "<{} as {}>",
295 engines.help_out(self.ty.clone()),
296 engines.help_out(self.as_trait)
297 )
298 }
299}
300
301impl DebugWithEngines for QualifiedPathType {
302 fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
303 write!(f, "{}", engines.help_out(self),)
304 }
305}
306
307#[derive(Debug, Clone)]
308pub struct AmbiguousPathExpression {
309 pub qualified_path_root: Option<QualifiedPathType>,
310 pub call_path_binding: TypeBinding<CallPath<AmbiguousSuffix>>,
311 pub args: Vec<Expression>,
312}
313
314impl EqWithEngines for AmbiguousPathExpression {}
315impl PartialEqWithEngines for AmbiguousPathExpression {
316 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
317 self.qualified_path_root.eq(&other.qualified_path_root, ctx)
318 && PartialEqWithEngines::eq(&self.call_path_binding, &other.call_path_binding, ctx)
319 && self.args.eq(&other.args, ctx)
320 }
321}
322
323#[derive(Debug, Clone)]
324pub struct DelineatedPathExpression {
325 pub call_path_binding: TypeBinding<QualifiedCallPath>,
326 pub args: Option<Vec<Expression>>,
330}
331
332impl EqWithEngines for DelineatedPathExpression {}
333impl PartialEqWithEngines for DelineatedPathExpression {
334 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
335 self.call_path_binding.eq(&other.call_path_binding, ctx) && self.args.eq(&other.args, ctx)
336 }
337}
338
339#[derive(Debug, Clone)]
340pub struct AbiCastExpression {
341 pub abi_name: CallPath,
342 pub address: Box<Expression>,
343}
344
345impl EqWithEngines for AbiCastExpression {}
346impl PartialEqWithEngines for AbiCastExpression {
347 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
348 PartialEqWithEngines::eq(&self.abi_name, &other.abi_name, ctx)
349 && self.address.eq(&other.address, ctx)
350 }
351}
352
353#[derive(Debug, Clone)]
354pub struct ArrayIndexExpression {
355 pub prefix: Box<Expression>,
356 pub index: Box<Expression>,
357}
358
359impl EqWithEngines for ArrayIndexExpression {}
360impl PartialEqWithEngines for ArrayIndexExpression {
361 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
362 self.prefix.eq(&other.prefix, ctx) && self.index.eq(&other.index, ctx)
363 }
364}
365
366#[derive(Debug, Clone)]
372pub struct StorageAccessExpression {
373 pub namespace_names: Vec<Ident>,
376 pub field_names: Vec<Ident>,
380 pub storage_keyword_span: Span,
381}
382
383impl EqWithEngines for StorageAccessExpression {}
384impl PartialEqWithEngines for StorageAccessExpression {
385 fn eq(&self, other: &Self, _ctx: &PartialEqWithEnginesContext) -> bool {
386 self.field_names.eq(&other.field_names)
387 && self.storage_keyword_span.eq(&other.storage_keyword_span)
388 }
389}
390
391#[derive(Debug, Clone)]
392pub struct IntrinsicFunctionExpression {
393 pub name: Ident,
394 pub kind_binding: TypeBinding<Intrinsic>,
395 pub arguments: Vec<Expression>,
396}
397
398impl EqWithEngines for IntrinsicFunctionExpression {}
399impl PartialEqWithEngines for IntrinsicFunctionExpression {
400 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
401 self.name.eq(&other.name)
402 && self.kind_binding.eq(&other.kind_binding, ctx)
403 && self.arguments.eq(&other.arguments, ctx)
404 }
405}
406
407#[derive(Debug, Clone)]
408pub struct WhileLoopExpression {
409 pub condition: Box<Expression>,
410 pub body: CodeBlock,
411 pub is_desugared_for_loop: bool,
412}
413
414impl EqWithEngines for WhileLoopExpression {}
415impl PartialEqWithEngines for WhileLoopExpression {
416 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
417 self.condition.eq(&other.condition, ctx) && self.body.eq(&other.body, ctx)
418 }
419}
420
421#[derive(Debug, Clone)]
422pub struct ForLoopExpression {
423 pub desugared: Box<Expression>,
424}
425
426impl EqWithEngines for ForLoopExpression {}
427impl PartialEqWithEngines for ForLoopExpression {
428 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
429 self.desugared.eq(&other.desugared, ctx)
430 }
431}
432
433#[derive(Debug, Clone)]
434pub struct ReassignmentExpression {
435 pub lhs: ReassignmentTarget,
436 pub rhs: Box<Expression>,
437}
438
439impl EqWithEngines for ReassignmentExpression {}
440impl PartialEqWithEngines for ReassignmentExpression {
441 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
442 self.lhs.eq(&other.lhs, ctx) && self.rhs.eq(&other.rhs, ctx)
443 }
444}
445
446#[derive(Debug, Clone)]
447pub enum ExpressionKind {
448 Error(Box<[Span]>, ErrorEmitted),
454 Literal(Literal),
455 AmbiguousPathExpression(Box<AmbiguousPathExpression>),
458 FunctionApplication(Box<FunctionApplicationExpression>),
459 LazyOperator(LazyOperatorExpression),
460 AmbiguousVariableExpression(Ident),
462 Variable(Ident),
463 Tuple(Vec<Expression>),
464 TupleIndex(TupleIndexExpression),
465 Array(ArrayExpression),
466 Struct(Box<StructExpression>),
467 CodeBlock(CodeBlock),
468 If(IfExpression),
469 Match(MatchExpression),
470 Asm(Box<AsmExpression>),
472 MethodApplication(Box<MethodApplicationExpression>),
473 Subfield(SubfieldExpression),
479 DelineatedPath(Box<DelineatedPathExpression>),
501 AbiCast(Box<AbiCastExpression>),
503 ArrayIndex(ArrayIndexExpression),
504 StorageAccess(StorageAccessExpression),
505 IntrinsicFunction(IntrinsicFunctionExpression),
506 WhileLoop(WhileLoopExpression),
509 ForLoop(ForLoopExpression),
511 Break,
512 Continue,
513 Reassignment(ReassignmentExpression),
514 ImplicitReturn(Box<Expression>),
520 Return(Box<Expression>),
521 Panic(Box<Expression>),
522 Ref(RefExpression),
523 Deref(Box<Expression>),
524}
525
526impl EqWithEngines for Expression {}
527impl PartialEqWithEngines for Expression {
528 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
529 self.kind.eq(&other.kind, ctx)
530 }
531}
532
533impl EqWithEngines for ExpressionKind {}
534impl PartialEqWithEngines for ExpressionKind {
535 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
536 match (self, other) {
537 (ExpressionKind::Error(l_span, _), ExpressionKind::Error(r_span, _)) => {
538 l_span == r_span
539 }
540 (ExpressionKind::Literal(l_literal), ExpressionKind::Literal(r_literal)) => {
541 l_literal == r_literal
542 }
543 (
544 ExpressionKind::AmbiguousPathExpression(lhs),
545 ExpressionKind::AmbiguousPathExpression(rhs),
546 ) => lhs.eq(rhs, ctx),
547 (
548 ExpressionKind::FunctionApplication(lhs),
549 ExpressionKind::FunctionApplication(rhs),
550 ) => lhs.eq(rhs, ctx),
551 (ExpressionKind::LazyOperator(lhs), ExpressionKind::LazyOperator(rhs)) => {
552 lhs.eq(rhs, ctx)
553 }
554 (
555 ExpressionKind::AmbiguousVariableExpression(lhs),
556 ExpressionKind::AmbiguousVariableExpression(rhs),
557 ) => lhs == rhs,
558 (ExpressionKind::Variable(lhs), ExpressionKind::Variable(rhs)) => lhs == rhs,
559 (ExpressionKind::Tuple(lhs), ExpressionKind::Tuple(rhs)) => lhs.eq(rhs, ctx),
560 (ExpressionKind::TupleIndex(lhs), ExpressionKind::TupleIndex(rhs)) => lhs.eq(rhs, ctx),
561 (ExpressionKind::Array(lhs), ExpressionKind::Array(rhs)) => lhs.eq(rhs, ctx),
562 (ExpressionKind::Struct(lhs), ExpressionKind::Struct(rhs)) => lhs.eq(rhs, ctx),
563 (ExpressionKind::CodeBlock(lhs), ExpressionKind::CodeBlock(rhs)) => lhs.eq(rhs, ctx),
564 (ExpressionKind::If(lhs), ExpressionKind::If(rhs)) => lhs.eq(rhs, ctx),
565 (ExpressionKind::Match(lhs), ExpressionKind::Match(rhs)) => lhs.eq(rhs, ctx),
566 (ExpressionKind::Asm(lhs), ExpressionKind::Asm(rhs)) => lhs.eq(rhs, ctx),
567 (ExpressionKind::MethodApplication(lhs), ExpressionKind::MethodApplication(rhs)) => {
568 lhs.eq(rhs, ctx)
569 }
570 (ExpressionKind::Subfield(lhs), ExpressionKind::Subfield(rhs)) => lhs.eq(rhs, ctx),
571 (ExpressionKind::DelineatedPath(lhs), ExpressionKind::DelineatedPath(rhs)) => {
572 lhs.eq(rhs, ctx)
573 }
574 (ExpressionKind::AbiCast(lhs), ExpressionKind::AbiCast(rhs)) => lhs.eq(rhs, ctx),
575 (ExpressionKind::ArrayIndex(lhs), ExpressionKind::ArrayIndex(rhs)) => lhs.eq(rhs, ctx),
576 (ExpressionKind::StorageAccess(lhs), ExpressionKind::StorageAccess(rhs)) => {
577 lhs.eq(rhs, ctx)
578 }
579 (ExpressionKind::IntrinsicFunction(lhs), ExpressionKind::IntrinsicFunction(rhs)) => {
580 lhs.eq(rhs, ctx)
581 }
582 (ExpressionKind::WhileLoop(lhs), ExpressionKind::WhileLoop(rhs)) => lhs.eq(rhs, ctx),
583 (ExpressionKind::ForLoop(lhs), ExpressionKind::ForLoop(rhs)) => lhs.eq(rhs, ctx),
584 (ExpressionKind::Break, ExpressionKind::Break) => true,
585 (ExpressionKind::Continue, ExpressionKind::Continue) => true,
586 (ExpressionKind::Reassignment(lhs), ExpressionKind::Reassignment(rhs)) => {
587 lhs.eq(rhs, ctx)
588 }
589 (ExpressionKind::ImplicitReturn(lhs), ExpressionKind::ImplicitReturn(rhs)) => {
590 lhs.eq(rhs, ctx)
591 }
592 (ExpressionKind::Return(lhs), ExpressionKind::Return(rhs)) => lhs.eq(rhs, ctx),
593 (ExpressionKind::Panic(lhs), ExpressionKind::Panic(rhs)) => lhs.eq(rhs, ctx),
594 (ExpressionKind::Ref(lhs), ExpressionKind::Ref(rhs)) => lhs.eq(rhs, ctx),
595 (ExpressionKind::Deref(lhs), ExpressionKind::Deref(rhs)) => lhs.eq(rhs, ctx),
596 _ => false,
597 }
598 }
599}
600
601#[derive(Debug, Clone)]
602pub struct RefExpression {
603 pub to_mutable_value: bool,
605 pub value: Box<Expression>,
606}
607
608impl EqWithEngines for RefExpression {}
609impl PartialEqWithEngines for RefExpression {
610 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
611 self.to_mutable_value.eq(&other.to_mutable_value) && self.value.eq(&other.value, ctx)
612 }
613}
614
615#[derive(Debug, Clone)]
616pub enum ReassignmentTarget {
617 ElementAccess(Box<Expression>),
623 Deref(Box<Expression>),
629}
630
631impl EqWithEngines for ReassignmentTarget {}
632impl PartialEqWithEngines for ReassignmentTarget {
633 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
634 match (self, other) {
635 (ReassignmentTarget::ElementAccess(lhs), ReassignmentTarget::ElementAccess(rhs)) => {
636 lhs.eq(rhs, ctx)
637 }
638 (ReassignmentTarget::Deref(lhs), ReassignmentTarget::Deref(rhs)) => lhs.eq(rhs, ctx),
639 _ => false,
640 }
641 }
642}
643
644#[derive(Debug, Clone)]
645pub struct StructExpressionField {
646 pub name: Ident,
647 pub value: Expression,
648}
649
650impl EqWithEngines for StructExpressionField {}
651impl PartialEqWithEngines for StructExpressionField {
652 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
653 self.name == other.name && self.value.eq(&other.value, ctx)
654 }
655}
656
657impl Spanned for Expression {
658 fn span(&self) -> Span {
659 self.span.clone()
660 }
661}
662
663#[derive(Debug)]
664pub(crate) struct Op {
665 pub span: Span,
666 pub op_variant: OpVariant,
667}
668
669impl Op {
670 pub fn to_method_name(&self) -> Ident {
671 Ident::new_with_override(self.op_variant.method_name().to_string(), self.span.clone())
672 }
673}
674
675#[derive(Debug)]
676pub enum OpVariant {
677 Add,
678 Subtract,
679 Divide,
680 Multiply,
681 Modulo,
682 Or,
683 And,
684 Equals,
685 NotEquals,
686 Xor,
687 BinaryOr,
688 BinaryAnd,
689 GreaterThan,
690 LessThan,
691 GreaterThanOrEqualTo,
692 LessThanOrEqualTo,
693}
694
695impl OpVariant {
696 fn method_name(&self) -> &'static str {
704 use OpVariant::*;
705 match self {
706 Add => "add",
707 Subtract => "subtract",
708 Divide => "divide",
709 Multiply => "multiply",
710 Modulo => "modulo",
711 Or => "$or$",
712 And => "$and$",
713 Equals => "eq",
714 NotEquals => "neq",
715 Xor => "xor",
716 BinaryOr => "binary_or",
717 BinaryAnd => "binary_and",
718 GreaterThan => "gt",
719 LessThan => "lt",
720 LessThanOrEqualTo => "le",
721 GreaterThanOrEqualTo => "ge",
722 }
723 }
724}