-
-
Notifications
You must be signed in to change notification settings - Fork 372
/
p6invocation.pmc
132 lines (106 loc) · 4.47 KB
/
p6invocation.pmc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*
$Id$
Copyright (C) 2009, The Perl Foundation.
=head1 NAME
src/pmc/P6Invocation.pmc - PMC representing a current invocation
=head1 DESCRIPTION
When we invoke a method in Perl 6, we need to keep the list of candidates
available for callwith, callsame, nextwith, nextsame etc. This PMC is what
gets stuck into the lex pad to represent the the candidate list.
=head2 Methods
=cut
*/
#include "parrot/parrot.h"
/* This does the grunt work of working out what the next candidate is. Takes
* account of us maybe needing to look into multi variants and all that lot. */
static PMC *get_next_candidate(PARROT_INTERP, PMC *SELF) {
PMC *candidates, *current;
INTVAL position;
/* Get candidates and position. */
GETATTR_P6Invocation_candidate_list(interp, SELF, candidates);
GETATTR_P6Invocation_position(interp, SELF, position);
/* Make sure we're not past the end of the candidate list. */
if (position >= VTABLE_elements(interp, candidates))
return PMCNULL;
/* Grab current candidate. */
current = VTABLE_get_pmc_keyed_int(interp, candidates, position);
if (VTABLE_isa(interp, current, CONST_STRING(interp, "Perl6MultiSub"))) {
/* XXX Multi potrebuje nieco specialne... */
}
/* Increment position in candidate list, and we're done. */
position++;
SETATTR_P6Invocation_position(interp, SELF, position);
return current;
}
pmclass P6Invocation need_ext dynpmc group perl6_group {
ATTR PMC *first_candidate;
ATTR PMC *candidate_list;
ATTR INTVAL position;
VTABLE void init() {
PMC_data(SELF) = mem_allocate_zeroed_typed(Parrot_P6Invocation_attributes);
PObj_custom_mark_SET(SELF);
PObj_active_destroy_SET(SELF);
}
VTABLE void init_pmc(PMC *list) {
SELF.init();
SETATTR_P6Invocation_candidate_list(interp, SELF, list);
}
VTABLE void mark() {
if (PMC_data(SELF)) {
PMC *first_candidate, *candidate_list;
GETATTR_P6Invocation_first_candidate(interp, SELF, first_candidate);
GETATTR_P6Invocation_candidate_list(interp, SELF, candidate_list);
if (!PMC_IS_NULL(first_candidate))
pobject_lives(interp, (PObj*)first_candidate);
if (!PMC_IS_NULL(candidate_list))
pobject_lives(interp, (PObj*)candidate_list);
}
}
VTABLE void destroy() {
mem_sys_free(PMC_data(SELF));
PMC_data(SELF) = NULL;
}
VTABLE PMC *clone() {
PMC *first_candidate, *candidate_list;
INTVAL position;
PMC *copy = pmc_new(interp, SELF->vtable->base_type);
GETATTR_P6Invocation_first_candidate(interp, SELF, first_candidate);
GETATTR_P6Invocation_candidate_list(interp, SELF, candidate_list);
GETATTR_P6Invocation_position(interp, SELF, position);
SETATTR_P6Invocation_first_candidate(interp, copy, first_candidate);
SETATTR_P6Invocation_candidate_list(interp, copy, candidate_list);
SETATTR_P6Invocation_position(interp, copy, position);
return copy;
}
VTABLE INTVAL get_bool() {
PMC *candidates;
INTVAL position;
/* Get candidates and position, and check if we have more candidates. */
GETATTR_P6Invocation_candidate_list(interp, SELF, candidates);
GETATTR_P6Invocation_position(interp, SELF, position);
return position < VTABLE_elements(interp, candidates);
}
VTABLE opcode_t *invoke(void *next) {
STRING *lexname = CONST_STRING(interp, "__CANDIATE_LIST__");
PMC *lexpad, *first_candidate;
opcode_t *addr;
/* In the straightforward case, we know our first candidate right off the
* bat; if not, use list. We also nullify first candidate so we hit the
* candidate list next time we're used. */
GETATTR_P6Invocation_first_candidate(interp, SELF, first_candidate);
if (PMC_IS_NULL(first_candidate))
first_candidate = get_next_candidate(interp, SELF);
else
SETATTR_P6Invocation_first_candidate(interp, SELF, PMCNULL);
/* Invoke it, then fudge ourself into its lexpad. */
addr = VTABLE_invoke(interp, first_candidate, next);
lexpad = CONTEXT(interp)->lex_pad;
if (VTABLE_exists_keyed_str(interp, lexpad, lexname))
VTABLE_set_pmc_keyed_str(interp, lexpad, lexname, SELF);
return addr;
}
METHOD PMC *get() {
PMC *next = get_next_candidate(interp, SELF);
RETURN(PMC *next);
}
}