Appearance
| 1 | namespace IR.Values is | |
| 2 | use System.Reflection.Metadata.ILOpCode | |
| 3 | ||
| 4 | use Semantic.Types.Type | |
| 5 | ||
| 6 | // `a =~ b` where both operands are a sequence - an array, or a | |
| 7 | // list - compared by count and then element by element. | |
| 8 | // | |
| 9 | // The element comparison arrives already built against a load of | |
| 10 | // the index local this node declares, so what the element type's | |
| 11 | // equality is has been decided by the caller in the same way as for | |
| 12 | // any other operand; this node only supplies the loop around it. | |
| 13 | // Both counts are read twice, so they arrive as repeatable loads. | |
| 14 | // | |
| 15 | // <left count> | |
| 16 | // <right count> | |
| 17 | // ceq | |
| 18 | // brfalse <unequal> | |
| 19 | // ldc.i4.0 | |
| 20 | // stloc i | |
| 21 | // <loop>: | |
| 22 | // ldloc i | |
| 23 | // <left count> | |
| 24 | // bge <equal> // every element compared equal | |
| 25 | // <element comparison> // reads a[i] and b[i] through the local | |
| 26 | // brfalse <unequal> | |
| 27 | // ldloc i | |
| 28 | // ldc.i4.1 | |
| 29 | // add | |
| 30 | // stloc i | |
| 31 | // br <loop> | |
| 32 | // <equal>: | |
| 33 | // ldc.i4.1 | |
| 34 | // br <end> | |
| 35 | // <unequal>: | |
| 36 | // ldc.i4.0 | |
| 37 | // <end>: | |
| 38 | class SEQUENCE_EQUALITY: Value is | |
| 39 | left_count: Value | |
| 40 | right_count: Value | |
| 41 | index_name: string | |
| 42 | index_type: Type | |
| 43 | element_equals: Value | |
| 44 | _result_type: Type | |
| 45 | ||
| 46 | type: Type => _result_type | |
| 47 | is_lightweight_pure: bool => false | |
| 48 | ||
| 49 | init( | |
| 50 | left_count: Value, | |
| 51 | right_count: Value, | |
| 52 | index_name: string, | |
| 53 | index_type: Type, | |
| 54 | element_equals: Value, | |
| 55 | result_type: Type | |
| 56 | ) is | |
| 57 | super.init() | |
| 58 | ||
| 59 | self.left_count = left_count | |
| 60 | self.right_count = right_count | |
| 61 | self.index_name = index_name | |
| 62 | self.index_type = index_type | |
| 63 | self.element_equals = element_equals | |
| 64 | self._result_type = result_type | |
| 65 | si | |
| 66 | ||
| 67 | gen(context: IR.CONTEXT) is | |
| 68 | let loop_label = IR.LABEL() | |
| 69 | let equal_label = IR.LABEL() | |
| 70 | let unequal_label = IR.LABEL() | |
| 71 | let end_label = IR.LABEL() | |
| 72 | ||
| 73 | let body = context.current_srm_body_emitter! | |
| 74 | ||
| 75 | body.declare_local(index_name, index_type) | |
| 76 | ||
| 77 | gen(left_count, context) | |
| 78 | gen(right_count, context) | |
| 79 | body.op(ILOpCode.CEQ) | |
| 80 | body.branch(ILOpCode.BRFALSE, unequal_label) | |
| 81 | ||
| 82 | body.ldc_i4(0) | |
| 83 | body.stloc(index_name) | |
| 84 | ||
| 85 | body.mark_label(loop_label) | |
| 86 | body.ldloc(index_name) | |
| 87 | gen(left_count, context) | |
| 88 | body.branch(ILOpCode.BGE, equal_label) | |
| 89 | ||
| 90 | gen(element_equals, context) | |
| 91 | body.branch(ILOpCode.BRFALSE, unequal_label) | |
| 92 | ||
| 93 | body.ldloc(index_name) | |
| 94 | body.ldc_i4(1) | |
| 95 | body.op(ILOpCode.ADD) | |
| 96 | body.stloc(index_name) | |
| 97 | body.branch(ILOpCode.BR, loop_label) | |
| 98 | ||
| 99 | body.mark_label(equal_label) | |
| 100 | body.ldc_i4(1) | |
| 101 | body.branch(ILOpCode.BR, end_label) | |
| 102 | ||
| 103 | body.mark_label(unequal_label) | |
| 104 | body.ldc_i4(0) | |
| 105 | ||
| 106 | body.mark_label(end_label) | |
| 107 | si | |
| 108 | ||
| 109 | to_string() -> string => | |
| 110 | "sequence-equality:[{type}]({left_count},{right_count},{index_name},{element_equals})" | |
| 111 | si | |
| 112 | ||
| 113 | // `a =~ b` on two references of a class declaring neither `=~` nor | |
| 114 | // `<>`: the same thing as `a == b`, reached from a synthesized | |
| 115 | // comparison where the operator could not have been written. | |
| 116 | class REFERENCE_EQUALITY: Value is | |
| 117 | left: Value | |
| 118 | right: Value | |
| 119 | _result_type: Type | |
| 120 | ||
| 121 | type: Type => _result_type | |
| 122 | is_lightweight_pure: bool => false | |
| 123 | ||
| 124 | init(left: Value, right: Value, result_type: Type) is | |
| 125 | super.init() | |
| 126 | ||
| 127 | self.left = left | |
| 128 | self.right = right | |
| 129 | self._result_type = result_type | |
| 130 | si | |
| 131 | ||
| 132 | gen(context: IR.CONTEXT) is | |
| 133 | gen(left, context) | |
| 134 | gen(right, context) | |
| 135 | ||
| 136 | context.current_srm_body_emitter!.op(ILOpCode.CEQ) | |
| 137 | si | |
| 138 | ||
| 139 | to_string() -> string => "reference-equality:[{type}]({left},{right})" | |
| 140 | si | |
| 141 | si |