Permalink
Browse files

Implement coercion ($x as Foo) in signature binding.

  • Loading branch information...
jnthn committed Feb 17, 2010
1 parent 0d2009c commit f0da535d5e09adeb39b484fef96692aaea6c1f5d
View
@@ -1134,6 +1134,10 @@ method parameter($/) {
}
$*PARAMETER.is_rw( $read_type eq 'rw' );
$*PARAMETER.is_copy( $read_type eq 'copy' );
+ my $coerce := has_compiler_trait($<trait>, '&trait_mod:<as>');
+ if $coerce {
+ $*PARAMETER.coerce_to(PAST::Op.new( :pasttype('callmethod'), :name('perl'), $coerce[0]));
+ }
}
make $*PARAMETER;
@@ -21,6 +21,7 @@ has $!is_copy;
has $!is_parcel;
has $!is_capture;
has $!traits;
+has $!coerce_to;
method var_name($var_name?) {
if $var_name { $!var_name := $var_name }
@@ -138,3 +139,8 @@ method traits($traits?) {
if $traits { $!traits := $traits }
$!traits
}
+
+method coerce_to($coerce_to?) {
+ if $coerce_to { $!coerce_to := $coerce_to }
+ $!coerce_to
+}
@@ -295,7 +295,7 @@ method ast($high_level?) {
# Emit op to build signature element.
$ast.push(PAST::Op.new(
- :pirop('set_signature_elem vPisiPPPPPP'),
+ :pirop('set_signature_elem vPisiPPPPPPS'),
$sig_var,
$i,
($_.var_name eq '' || $_.var_name eq $_.sigil ?? $null_str !! ~$_.var_name),
@@ -305,7 +305,8 @@ method ast($high_level?) {
$names,
$type_captures,
($_.default ?? $_.default !! $null_reg),
- $sub_sig
+ $sub_sig,
+ ($_.coerce_to ?? $_.coerce_to !! $null_str)
));
$i := $i + 1;
}
View
@@ -246,6 +246,30 @@ Rakudo_binding_bind_one_param(PARROT_INTERP, PMC *lexpad, llsig_element *sig_inf
}
}
+ /* Do a coercion, if one is needed. */
+ if (sig_info->coerce_to) {
+ PMC *coerce_meth = VTABLE_find_method(interp, value, sig_info->coerce_to);
+ if (!PMC_IS_NULL(coerce_meth)) {
+ Parrot_ext_call(interp, coerce_meth, "Pi->P", value, &value);
+ }
+ else {
+ /* No coercion method availale; whine and fail to bind. */
+ if (error) {
+ STRING * const HOW = string_from_literal(interp, "HOW");
+ PMC * how_meth = VTABLE_find_method(interp, value, HOW);
+ PMC * value_how, * value_type;
+ STRING * got;
+ Parrot_ext_call(interp, how_meth, "Pi->P", value, &value_how);
+ value_type = VTABLE_get_attr_str(interp, value_how, string_from_literal(interp, "shortname"));
+ got = VTABLE_get_string(interp, value_type);
+ *error = Parrot_sprintf_c(interp,
+ "Unable to coerce value for '%S' from %S to %S; no coercion method defined",
+ sig_info->variable_name, got, sig_info->coerce_to);
+ }
+ return BIND_RESULT_FAIL;
+ }
+ }
+
/* If it's not got attributive binding, we'll go about binding it into the
* lex pad. */
if (!(sig_info->flags & SIG_ELEM_BIND_ATTRIBUTIVE)) {
View
@@ -29,6 +29,7 @@ typedef struct llsig_element {
PMC *post_constraints; /* Array of any extra constraints; we will do a
* smart-match against each of them. For now, we
* always expect an array of blocks. */
+ STRING *coerce_to; /* Name of the type to coerce to; for X we do $val.X. */
PMC *sub_signature; /* Any nested signature. */
PMC *default_closure; /* The default value closure. */
} llsig_element;
@@ -50,7 +50,7 @@ src/classes/Associative.pir - Associative Role
signature = allocate_signature 1
setprop block, "$!signature", signature
null $P1
- set_signature_elem signature, 0, "T", SIG_ELEM_IS_OPTIONAL, $P1, $P1, $P1, $P1, $P1, $P1
+ set_signature_elem signature, 0, "T", SIG_ELEM_IS_OPTIONAL, $P1, $P1, $P1, $P1, $P1, $P1, ""
.end
@@ -54,7 +54,7 @@ This implements the parametric role Callable[::T = Mu].
signature = allocate_signature 1
setprop block, "$!signature", signature
null $P1
- set_signature_elem signature, 0, "T", SIG_ELEM_IS_OPTIONAL, $P1, $P1, $P1, $P1, $P1, $P1
+ set_signature_elem signature, 0, "T", SIG_ELEM_IS_OPTIONAL, $P1, $P1, $P1, $P1, $P1, $P1, ""
.end
@@ -52,7 +52,7 @@ src/classes/Positional.pir - Positional Role
signature = allocate_signature 1
setprop block, "$!signature", signature
null $P1
- set_signature_elem signature, 0, "T", SIG_ELEM_IS_OPTIONAL, $P1, $P1, $P1, $P1, $P1, $P1
+ set_signature_elem signature, 0, "T", SIG_ELEM_IS_OPTIONAL, $P1, $P1, $P1, $P1, $P1, $P1, ""
.end
@@ -61,8 +61,8 @@ Returns a C<List> of C<Parameter> descriptors.
# Get all curent parameter info.
.local pmc nom_type, cons_type, names, type_captures, default, sub_sig
.local int flags, optional, invocant, multi_invocant, slurpy, rw, parcel, capture, copy, named
- .local string name
- get_signature_elem signature, cur_param, name, flags, nom_type, cons_type, names, type_captures, default, sub_sig
+ .local string name, coerce_to
+ get_signature_elem signature, cur_param, name, flags, nom_type, cons_type, names, type_captures, default, sub_sig, coerce_to
optional = flags & SIG_ELEM_IS_OPTIONAL
invocant = flags & SIG_ELEM_INVOCANT
multi_invocant = flags & SIG_ELEM_MULTI_INVOCANT
View
@@ -465,7 +465,7 @@ inline op get_signature_size(out INT, in PMC) :base_core {
/*
-=item set_signature_elem(in PMC, in INT, in STR, in INT, inout PMC, inout PMC, inout PMC, inout PMC, inout PMC, inout PMC)
+=item set_signature_elem(in PMC, in INT, in STR, in INT, inout PMC, inout PMC, inout PMC, inout PMC, inout PMC, inout PMC, in STR)
Takes $1 (a P6LowLevelSig) and sets the contents of the signature element with
index $2 as follows:
@@ -478,11 +478,12 @@ index $2 as follows:
$8 = array of type captures
$9 = default value closure
$10 = nested signature
+ $11 = name of coercion method to call, if any
=cut
*/
-inline op set_signature_elem(in PMC, in INT, in STR, in INT, inout PMC, inout PMC, inout PMC, inout PMC, inout PMC, inout PMC) :base_core {
+inline op set_signature_elem(in PMC, in INT, in STR, in INT, inout PMC, inout PMC, inout PMC, inout PMC, inout PMC, inout PMC, in STR) :base_core {
if ($1->vtable->base_type == lls_id) {
struct llsig_element **elements;
INTVAL num_elements;
@@ -500,6 +501,7 @@ inline op set_signature_elem(in PMC, in INT, in STR, in INT, inout PMC, inout PM
element->type_captures = $8;
element->default_closure = $9;
element->sub_signature = $10;
+ element->coerce_to = $11;
/* Also need to do fixups on the nominal type. */
if (!PMC_IS_NULL($5)) {
@@ -539,7 +541,7 @@ inline op set_signature_elem(in PMC, in INT, in STR, in INT, inout PMC, inout PM
/*
-=item get_signature_elem(in PMC, in INT, out STR, out INT, out PMC, out PMC, out PMC, out PMC, out PMC, out PMC, out PMC)
+=item get_signature_elem(in PMC, in INT, out STR, out INT, out PMC, out PMC, out PMC, out PMC, out PMC, out PMC, out PMC, out STR)
Takes $1 (a P6LowLevelSig) and sets the registers with the contents of the
signature element with index $2 as follows:
@@ -552,11 +554,12 @@ signature element with index $2 as follows:
$8 = array of type captures
$9 = default value closure
$10 = nested signature
+ $11 = name of coercion method to call, if any
=cut
*/
-inline op get_signature_elem(in PMC, in INT, out STR, out INT, out PMC, out PMC, out PMC, out PMC, out PMC, out PMC) :base_core {
+inline op get_signature_elem(in PMC, in INT, out STR, out INT, out PMC, out PMC, out PMC, out PMC, out PMC, out PMC, out STR) :base_core {
if ($1->vtable->base_type == lls_id) {
struct llsig_element **elements;
INTVAL num_elements;
@@ -574,6 +577,7 @@ inline op get_signature_elem(in PMC, in INT, out STR, out INT, out PMC, out PMC,
$8 = element->type_captures;
$9 = element->default_closure;
$10 = element->sub_signature;
+ $11 = element->coerce_to;
goto NEXT();
}
else {

0 comments on commit f0da535

Please sign in to comment.