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)]
367pub struct StorageAccessExpression {
368 pub namespace_names: Vec<Ident>,
369 pub field_names: Vec<Ident>,
370 pub storage_keyword_span: Span,
371}
372
373impl EqWithEngines for StorageAccessExpression {}
374impl PartialEqWithEngines for StorageAccessExpression {
375 fn eq(&self, other: &Self, _ctx: &PartialEqWithEnginesContext) -> bool {
376 self.field_names.eq(&other.field_names)
377 && self.storage_keyword_span.eq(&other.storage_keyword_span)
378 }
379}
380
381#[derive(Debug, Clone)]
382pub struct IntrinsicFunctionExpression {
383 pub name: Ident,
384 pub kind_binding: TypeBinding<Intrinsic>,
385 pub arguments: Vec<Expression>,
386}
387
388impl EqWithEngines for IntrinsicFunctionExpression {}
389impl PartialEqWithEngines for IntrinsicFunctionExpression {
390 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
391 self.name.eq(&other.name)
392 && self.kind_binding.eq(&other.kind_binding, ctx)
393 && self.arguments.eq(&other.arguments, ctx)
394 }
395}
396
397#[derive(Debug, Clone)]
398pub struct WhileLoopExpression {
399 pub condition: Box<Expression>,
400 pub body: CodeBlock,
401 pub is_desugared_for_loop: bool,
402}
403
404impl EqWithEngines for WhileLoopExpression {}
405impl PartialEqWithEngines for WhileLoopExpression {
406 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
407 self.condition.eq(&other.condition, ctx) && self.body.eq(&other.body, ctx)
408 }
409}
410
411#[derive(Debug, Clone)]
412pub struct ForLoopExpression {
413 pub desugared: Box<Expression>,
414}
415
416impl EqWithEngines for ForLoopExpression {}
417impl PartialEqWithEngines for ForLoopExpression {
418 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
419 self.desugared.eq(&other.desugared, ctx)
420 }
421}
422
423#[derive(Debug, Clone)]
424pub struct ReassignmentExpression {
425 pub lhs: ReassignmentTarget,
426 pub rhs: Box<Expression>,
427}
428
429impl EqWithEngines for ReassignmentExpression {}
430impl PartialEqWithEngines for ReassignmentExpression {
431 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
432 self.lhs.eq(&other.lhs, ctx) && self.rhs.eq(&other.rhs, ctx)
433 }
434}
435
436#[derive(Debug, Clone)]
437pub enum ExpressionKind {
438 Error(Box<[Span]>, ErrorEmitted),
444 Literal(Literal),
445 AmbiguousPathExpression(Box<AmbiguousPathExpression>),
448 FunctionApplication(Box<FunctionApplicationExpression>),
449 LazyOperator(LazyOperatorExpression),
450 AmbiguousVariableExpression(Ident),
452 Variable(Ident),
453 Tuple(Vec<Expression>),
454 TupleIndex(TupleIndexExpression),
455 Array(ArrayExpression),
456 Struct(Box<StructExpression>),
457 CodeBlock(CodeBlock),
458 If(IfExpression),
459 Match(MatchExpression),
460 Asm(Box<AsmExpression>),
462 MethodApplication(Box<MethodApplicationExpression>),
463 Subfield(SubfieldExpression),
469 DelineatedPath(Box<DelineatedPathExpression>),
491 AbiCast(Box<AbiCastExpression>),
493 ArrayIndex(ArrayIndexExpression),
494 StorageAccess(StorageAccessExpression),
495 IntrinsicFunction(IntrinsicFunctionExpression),
496 WhileLoop(WhileLoopExpression),
499 ForLoop(ForLoopExpression),
501 Break,
502 Continue,
503 Reassignment(ReassignmentExpression),
504 ImplicitReturn(Box<Expression>),
510 Return(Box<Expression>),
511 Panic(Box<Expression>),
512 Ref(RefExpression),
513 Deref(Box<Expression>),
514}
515
516impl EqWithEngines for Expression {}
517impl PartialEqWithEngines for Expression {
518 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
519 self.kind.eq(&other.kind, ctx)
520 }
521}
522
523impl EqWithEngines for ExpressionKind {}
524impl PartialEqWithEngines for ExpressionKind {
525 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
526 match (self, other) {
527 (ExpressionKind::Error(l_span, _), ExpressionKind::Error(r_span, _)) => {
528 l_span == r_span
529 }
530 (ExpressionKind::Literal(l_literal), ExpressionKind::Literal(r_literal)) => {
531 l_literal == r_literal
532 }
533 (
534 ExpressionKind::AmbiguousPathExpression(lhs),
535 ExpressionKind::AmbiguousPathExpression(rhs),
536 ) => lhs.eq(rhs, ctx),
537 (
538 ExpressionKind::FunctionApplication(lhs),
539 ExpressionKind::FunctionApplication(rhs),
540 ) => lhs.eq(rhs, ctx),
541 (ExpressionKind::LazyOperator(lhs), ExpressionKind::LazyOperator(rhs)) => {
542 lhs.eq(rhs, ctx)
543 }
544 (
545 ExpressionKind::AmbiguousVariableExpression(lhs),
546 ExpressionKind::AmbiguousVariableExpression(rhs),
547 ) => lhs == rhs,
548 (ExpressionKind::Variable(lhs), ExpressionKind::Variable(rhs)) => lhs == rhs,
549 (ExpressionKind::Tuple(lhs), ExpressionKind::Tuple(rhs)) => lhs.eq(rhs, ctx),
550 (ExpressionKind::TupleIndex(lhs), ExpressionKind::TupleIndex(rhs)) => lhs.eq(rhs, ctx),
551 (ExpressionKind::Array(lhs), ExpressionKind::Array(rhs)) => lhs.eq(rhs, ctx),
552 (ExpressionKind::Struct(lhs), ExpressionKind::Struct(rhs)) => lhs.eq(rhs, ctx),
553 (ExpressionKind::CodeBlock(lhs), ExpressionKind::CodeBlock(rhs)) => lhs.eq(rhs, ctx),
554 (ExpressionKind::If(lhs), ExpressionKind::If(rhs)) => lhs.eq(rhs, ctx),
555 (ExpressionKind::Match(lhs), ExpressionKind::Match(rhs)) => lhs.eq(rhs, ctx),
556 (ExpressionKind::Asm(lhs), ExpressionKind::Asm(rhs)) => lhs.eq(rhs, ctx),
557 (ExpressionKind::MethodApplication(lhs), ExpressionKind::MethodApplication(rhs)) => {
558 lhs.eq(rhs, ctx)
559 }
560 (ExpressionKind::Subfield(lhs), ExpressionKind::Subfield(rhs)) => lhs.eq(rhs, ctx),
561 (ExpressionKind::DelineatedPath(lhs), ExpressionKind::DelineatedPath(rhs)) => {
562 lhs.eq(rhs, ctx)
563 }
564 (ExpressionKind::AbiCast(lhs), ExpressionKind::AbiCast(rhs)) => lhs.eq(rhs, ctx),
565 (ExpressionKind::ArrayIndex(lhs), ExpressionKind::ArrayIndex(rhs)) => lhs.eq(rhs, ctx),
566 (ExpressionKind::StorageAccess(lhs), ExpressionKind::StorageAccess(rhs)) => {
567 lhs.eq(rhs, ctx)
568 }
569 (ExpressionKind::IntrinsicFunction(lhs), ExpressionKind::IntrinsicFunction(rhs)) => {
570 lhs.eq(rhs, ctx)
571 }
572 (ExpressionKind::WhileLoop(lhs), ExpressionKind::WhileLoop(rhs)) => lhs.eq(rhs, ctx),
573 (ExpressionKind::ForLoop(lhs), ExpressionKind::ForLoop(rhs)) => lhs.eq(rhs, ctx),
574 (ExpressionKind::Break, ExpressionKind::Break) => true,
575 (ExpressionKind::Continue, ExpressionKind::Continue) => true,
576 (ExpressionKind::Reassignment(lhs), ExpressionKind::Reassignment(rhs)) => {
577 lhs.eq(rhs, ctx)
578 }
579 (ExpressionKind::ImplicitReturn(lhs), ExpressionKind::ImplicitReturn(rhs)) => {
580 lhs.eq(rhs, ctx)
581 }
582 (ExpressionKind::Return(lhs), ExpressionKind::Return(rhs)) => lhs.eq(rhs, ctx),
583 (ExpressionKind::Panic(lhs), ExpressionKind::Panic(rhs)) => lhs.eq(rhs, ctx),
584 (ExpressionKind::Ref(lhs), ExpressionKind::Ref(rhs)) => lhs.eq(rhs, ctx),
585 (ExpressionKind::Deref(lhs), ExpressionKind::Deref(rhs)) => lhs.eq(rhs, ctx),
586 _ => false,
587 }
588 }
589}
590
591#[derive(Debug, Clone)]
592pub struct RefExpression {
593 pub to_mutable_value: bool,
595 pub value: Box<Expression>,
596}
597
598impl EqWithEngines for RefExpression {}
599impl PartialEqWithEngines for RefExpression {
600 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
601 self.to_mutable_value.eq(&other.to_mutable_value) && self.value.eq(&other.value, ctx)
602 }
603}
604
605#[derive(Debug, Clone)]
606pub enum ReassignmentTarget {
607 ElementAccess(Box<Expression>),
613 Deref(Box<Expression>),
619}
620
621impl EqWithEngines for ReassignmentTarget {}
622impl PartialEqWithEngines for ReassignmentTarget {
623 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
624 match (self, other) {
625 (ReassignmentTarget::ElementAccess(lhs), ReassignmentTarget::ElementAccess(rhs)) => {
626 lhs.eq(rhs, ctx)
627 }
628 (ReassignmentTarget::Deref(lhs), ReassignmentTarget::Deref(rhs)) => lhs.eq(rhs, ctx),
629 _ => false,
630 }
631 }
632}
633
634#[derive(Debug, Clone)]
635pub struct StructExpressionField {
636 pub name: Ident,
637 pub value: Expression,
638}
639
640impl EqWithEngines for StructExpressionField {}
641impl PartialEqWithEngines for StructExpressionField {
642 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
643 self.name == other.name && self.value.eq(&other.value, ctx)
644 }
645}
646
647impl Spanned for Expression {
648 fn span(&self) -> Span {
649 self.span.clone()
650 }
651}
652
653#[derive(Debug)]
654pub(crate) struct Op {
655 pub span: Span,
656 pub op_variant: OpVariant,
657}
658
659impl Op {
660 pub fn to_method_name(&self) -> Ident {
661 Ident::new_with_override(self.op_variant.method_name().to_string(), self.span.clone())
662 }
663}
664
665#[derive(Debug)]
666pub enum OpVariant {
667 Add,
668 Subtract,
669 Divide,
670 Multiply,
671 Modulo,
672 Or,
673 And,
674 Equals,
675 NotEquals,
676 Xor,
677 BinaryOr,
678 BinaryAnd,
679 GreaterThan,
680 LessThan,
681 GreaterThanOrEqualTo,
682 LessThanOrEqualTo,
683}
684
685impl OpVariant {
686 fn method_name(&self) -> &'static str {
694 use OpVariant::*;
695 match self {
696 Add => "add",
697 Subtract => "subtract",
698 Divide => "divide",
699 Multiply => "multiply",
700 Modulo => "modulo",
701 Or => "$or$",
702 And => "$and$",
703 Equals => "eq",
704 NotEquals => "neq",
705 Xor => "xor",
706 BinaryOr => "binary_or",
707 BinaryAnd => "binary_and",
708 GreaterThan => "gt",
709 LessThan => "lt",
710 LessThanOrEqualTo => "le",
711 GreaterThanOrEqualTo => "ge",
712 }
713 }
714}