23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
co_yield { rhs, c };
} );
// ct_int constant unification against any other value:
// Unify the value's type with ct_int, and if successful
// (as per the rule of ct_int versus rtint above), wrap
// the result in a callback.
// That callback will check that the final unified value is
// of an RTInt type of suitable
// size. If it is, it wil emit a load const int instruction.
// Otherwise, it will fail the unification.
//
// The reason we do all this is because we have to resolve the
// type unification first. It is only after this is done (and any
// hole is replaced with its infered value) that we know the actual
// wanted type for the value. We need to know that type to know if
// our constant value can be converted, and to emit the conversion.
//
// So we do this in a callback, which lets us perform a check and
// substitution of the final value after any contained hole has been
// replaced, and unification callback has been applied.
//
// An example of situation where this is needed is as follow:
//
// void lomarf( $T a, $T b ) {}
// RTUint( 8 ) someInt;
// lomarf( someInt, 123 );
//
// $T will resolve to RTUInt( 8 ), but if we had a simple ct_int against
// RTUInt param unification rule, the rule wouldn't work, because before we
// apply substitutions, the second parameter is still expressed as $T b,
// which would match the rule.
// However, the ct_int against "value with placeholder type and content" will
// match against $T b, and wrap it with a callback. Substitute will then
// turn $T b into RTUInt( 8 ) b and then invoke the callback on that, which
// can do its final checks and emit the load const int instruction wrapped as
// a value, or return nullopt to indicate that the unification failed (in case
// the constant is too big to fit in the RTUInt( 8 )).
e.unificationRuleSet()->addAsymRule(
|
|
|
|
|
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
co_yield { rhs, c };
} );
// ct_int constant unification against any other value:
// Unify the value's type with ct_int, and if successful
// (as per the rule of ct_int versus rtint above), wrap
// the result in a callback.
// That callback will check that the final unified value is
// of an RTInt type of suitable
// size. If it is, it wil emit a load const int instruction.
// Otherwise, it will fail the unification.
//
// The reason we do all this is because we have to resolve the
// type unification first. It is only after this is done (and any
// hole is replaced with its infered value) that we know the actual
// wanted type for the value. We need to know that type to know if
// our constant value can be converted, and to emit the conversion.
//
// So we do this in a callback, which lets us perform a check and
// substitution of the final value after any contained hole has been
// replaced, and unification callback has been applied.
//
// An example of situation where this is needed is as follow:
//
// void lomarf( $T a, $T b ) {}
// RTUInt( 8 ) someInt;
// lomarf( someInt, 123 );
//
// $T will resolve to RTUInt( 8 ), but if we had a simple ct_int against
// RTUInt param unification rule, the rule wouldn't work, because before we
// apply substitutions, the second parameter is still expressed as $T b,
// which wouldn't match the rule.
// However, the ct_int against "value with placeholder type and content" will
// match against $T b, and wrap it with a callback. Substitute will then
// turn $T b into RTUInt( 8 ) b and then invoke the callback on that, which
// can do its final checks and emit the load const int instruction wrapped as
// a value, or return nullopt to indicate that the unification failed (in case
// the constant is too big to fit in the RTUInt( 8 )).
e.unificationRuleSet()->addAsymRule(
|
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
// additional unique hole for the second overload would be ignored in the ranking.
uc.incComplexity( 2 );
// Yield a value of the unified type, wrapped into a callback
// that will perform the size check and emit the load const once
// we know the final unified solution for the value's type.
// Also, the callback should just return the final valus as is if
// is happens tobe a ct_int.
valPat->type() = s;
auto wrapped = WrapWithCallback( ValueToIRExpr( *valPat ),
[rhs]( auto&& t ) -> optional< Term >
{
auto lhsVal = *ValuePatternFromIRExpr( t );
|
|
|
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
// additional unique hole for the second overload would be ignored in the ranking.
uc.incComplexity( 2 );
// Yield a value of the unified type, wrapped into a callback
// that will perform the size check and emit the load const once
// we know the final unified solution for the value's type.
// Also, the callback should just return the final valus as is if
// is happens to be a ct_int.
valPat->type() = s;
auto wrapped = WrapWithCallback( ValueToIRExpr( *valPat ),
[rhs]( auto&& t ) -> optional< Term >
{
auto lhsVal = *ValuePatternFromIRExpr( t );
|
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
|
ANYTERM( _ ),
TSID( rt_integer ), TERM( 8ULL ), ANYTERM( _ ) ) );
auto rtInt8PtrTypePattern = Value( TypeType(), TVEC( TSID( rt_type ),
ANYTERM( _ ),
TSID( rt_pointer ), ValueToIRExpr( rtInt8TypePattern ) ) );
// ct_string constant unification against a rt_pointer to a rt_integer( 8 ):
// Emit a LoadConstantStr llr instruction.
e.unificationRuleSet()->addSymRule(
ValueToIRExpr( Value(
GetValueType< string >(),
ANYTERM( _ ) ) ),
ValueToIRExpr( ValuePattern(
ANYTERM( _ ),
ValueToIRExpr( rtInt8PtrTypePattern ),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, UnificationContext& c ) -> UniGen
{
auto str = *FromValue< string >( *ValueFromIRExpr( lhs ) );
auto rhsVal = *ValuePatternFromIRExpr( rhs );
co_yield { ValueToIRExpr(
BuildComputedValue( rhsVal.type(), llr::LoadConstStr( str ) ) ), c };
} );
}
}
|
>
>
>
>
>
>
>
>
>
>
|
>
>
|
>
>
>
>
>
>
|
|
|
<
|
>
>
|
>
>
|
<
|
>
>
>
>
|
|
>
>
>
>
>
|
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
|
ANYTERM( _ ),
TSID( rt_integer ), TERM( 8ULL ), ANYTERM( _ ) ) );
auto rtInt8PtrTypePattern = Value( TypeType(), TVEC( TSID( rt_type ),
ANYTERM( _ ),
TSID( rt_pointer ), ValueToIRExpr( rtInt8TypePattern ) ) );
// ct_int type against a against a rt_pointer to a rt_integer( 8 ):
// return the later.
e.unificationRuleSet()->addSymRule(
GetValueType< string >(),
ValueToIRExpr( rtInt8PtrTypePattern ),
[]( const Term& lhs, const Term& rhs, UnificationContext& c ) -> UniGen
{
co_yield { rhs, c };
} );
// ct_string constant unification against a rt_pointer to a rt_integer( 8 ):
// Emit a LoadConstantStr llr instruction from an unification callback.
// This works the same way as the ct_int value unification rule, see
// above for the grisly details.
e.unificationRuleSet()->addAsymRule(
ValueToIRExpr( ValuePattern(
ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ) ) ),
ValueToIRExpr( Value(
GetValueType< string >(),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, UnificationContext& c ) -> UniGen
{
// Unify the type
auto valPat = ValuePatternFromIRExpr( lhs );
for( auto&& [s, uc] : Unify( valPat->type(), GetValueType< string >(), c ) )
{
uc.incComplexity( 2 );
valPat->type() = s;
auto wrapped = WrapWithCallback( ValueToIRExpr( *valPat ),
[rhs]( auto&& t ) -> optional< Term >
{
auto lhsVal = *ValuePatternFromIRExpr( t );
if( lhsVal.type() == GetValueType< string >() )
return rhs;
const auto* str = FromValue< string >( *ValueFromIRExpr( rhs ) );
return ValueToIRExpr(
BuildComputedValue( lhsVal.type(), llr::LoadConstStr( *str ) ) );
}
);
co_yield { move( wrapped ), uc };
}
} );
}
}
|