1 /* ------------------------------------------------
2 Copyright 2014 AT&T Intellectual Property
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
7 http://www.apache.org/licenses/LICENSE-2.0
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ------------------------------------------- */
15 #ifndef __EXT_FCN_DEF_H_INCLUDED__
16 #define __EXT_FCN_DEF_H_INCLUDED__
21 #include "type_objects.h"
22 #include "parse_schema.h"
26 std::string type_name;
33 ext_fcn_param(){handle = false; dt=NULL; };
34 ext_fcn_param(char *t, param_list *plist, int h, int cnst, int clss){
36 if(h == 0) handle = false;
38 if(cnst == 1 ) constant = true;
39 else constant = false;
40 if(clss == 1) classifier = true;
41 else classifier = false;
44 dt = new data_type(type_name,plist);
47 data_type *get_dt(){return(dt);};
49 bool use_handle(){return handle;};
50 bool is_constant(){return constant;};
51 bool is_classifier(){return classifier;};
56 class ext_fcn_param_list{
58 std::vector<ext_fcn_param *> plist;
61 ext_fcn_param_list(){};
62 ext_fcn_param_list(ext_fcn_param *val){
66 ext_fcn_param_list *append(ext_fcn_param *val){
71 int size(){return plist.size();};
72 std::vector<ext_fcn_param *> get_param_list(){return plist;};
75 class ext_fcn_modifier_list{
77 std::vector<std::string> modifiers;
78 std::vector<std::string> vals;
80 ext_fcn_modifier_list(char *s){
81 modifiers.push_back(s);
85 ext_fcn_modifier_list(char *s, char *v){
86 modifiers.push_back(s);
90 ext_fcn_modifier_list *append(char *s){
91 modifiers.push_back(s);
96 ext_fcn_modifier_list *append(char *s, char *v){
97 modifiers.push_back(s);
113 std::string type_name; // return type name
114 data_type *fdt; // return type
115 std::string storage_type_name; // storage type name
116 data_type *sdt; // storage type
117 std::string fcn_name; // name for calling this fcn.
118 std::string udaf_name; // if an extraction function, its udaf.
119 std::string actual_fcn_name; // if extr. the mapped-to function.
120 std::vector<ext_fcn_param *> ef_param_list;
121 std::vector<std::string> modifiers; // keyword modifiers of the fcn
122 std::vector<std::string> vals; // optional vals of the keywords
124 // pre-compute these during validation
125 int subaggr_id, superaggr_id, hfta_subaggr_id, hfta_superaggr_id, actual_fcn_id;
135 ext_fcn_def(char *t, param_list *p, ext_fcn_modifier_list *m,
136 char *f, ext_fcn_param_list *plist){
137 subaggr_id=superaggr_id=hfta_subaggr_id=hfta_superaggr_id=actual_fcn_id=-1;
139 ef_param_list = plist->get_param_list();
141 modifiers = m->modifiers;
145 fdt = new data_type(type_name,p);
146 storage_type_name = "";
149 actual_fcn_name = "";
154 ext_fcn_def(ext_fcn_modifier_list *m,
155 char *f, ext_fcn_param_list *plist){
156 subaggr_id=superaggr_id=hfta_subaggr_id=hfta_superaggr_id=actual_fcn_id=-1;
158 ef_param_list = plist->get_param_list();
160 modifiers = m->modifiers;
165 storage_type_name = "";
168 actual_fcn_name = "";
169 fcn_type = EXT_PRED_;
173 ext_fcn_def(char *t, param_list *p, ext_fcn_modifier_list *m,
174 char *f, char *st, ext_fcn_param_list *plist){
175 subaggr_id=superaggr_id=hfta_subaggr_id=hfta_superaggr_id=actual_fcn_id=-1;
177 ef_param_list = plist->get_param_list();
179 modifiers = m->modifiers;
183 fdt = new data_type(type_name,p);
184 storage_type_name = st;
185 sdt = new data_type(st);
187 actual_fcn_name = "";
188 fcn_type = EXT_AGGR_;
193 ext_fcn_def(char *t, param_list *p, ext_fcn_modifier_list *m,
194 char *f, char *sa, char *af, ext_fcn_param_list *plist){
195 subaggr_id=superaggr_id=hfta_subaggr_id=hfta_superaggr_id=actual_fcn_id=-1;
197 ef_param_list = plist->get_param_list();
199 modifiers = m->modifiers;
203 fdt = new data_type(type_name,p);
204 storage_type_name = "";
207 actual_fcn_name = af;
208 fcn_type = EXT_EXTR_;
212 static ext_fcn_def *make_state_def(char *t, char *n){
213 ext_fcn_def *retval = new ext_fcn_def();
214 retval->fcn_type = EXT_STATE_;
215 retval->storage_type_name = t;
216 retval->sdt = new data_type(retval->storage_type_name);
217 retval->fcn_name = n;
222 static ext_fcn_def *make_sfun_def(char *t, param_list *p,
223 ext_fcn_modifier_list *m,
224 char *n, char *s, ext_fcn_param_list *plist){
225 ext_fcn_def *retval = new ext_fcn_def();
226 retval->fcn_type = EXT_SFUN_;
227 retval->type_name = t;
228 retval->fdt = new data_type(retval->type_name,p);
229 retval->storage_type_name = s;
230 retval->fcn_name = n;
232 retval->ef_param_list = plist->get_param_list();
234 retval->modifiers = m->modifiers;
235 retval->vals= m->vals;
241 data_type *get_fcn_dt(){return(fdt);};
242 data_type *get_storage_dt(){return sdt;};
243 std::string get_storage_state(){return storage_type_name;};
244 std::string get_fcn_name(){return fcn_name;};
246 std::vector<data_type *> get_operand_dt(){
248 std::vector<data_type *> ret;
249 for(o=0;o<ef_param_list.size();o++){
250 ret.push_back(ef_param_list[o]->get_dt());
254 int get_nparams(){return ef_param_list.size();};
256 bool is_pred(){return fcn_type == EXT_PRED_;};
257 bool is_fcn(){return fcn_type == EXT_FCN_;};
258 bool is_udaf(){return fcn_type == EXT_AGGR_;};
259 bool is_extr(){return fcn_type == EXT_EXTR_;};
260 bool is_state(){return fcn_type == EXT_STATE_;};
261 bool is_sfun(){return fcn_type == EXT_SFUN_;};
262 int get_fcn_type(){return fcn_type;};
264 void set_subaggr_id(int i){subaggr_id = i;};
265 void set_superaggr_id(int i){superaggr_id = i;};
266 void set_hfta_subaggr_id(int i){hfta_subaggr_id = i;};
267 void set_hfta_superaggr_id(int i){hfta_superaggr_id = i;};
268 void set_actual_fcnid(int i){actual_fcn_id = i;};
269 int get_subaggr_id(){return subaggr_id;};
270 int get_superaggr_id(){return superaggr_id;};
271 int get_hfta_subaggr_id(){return hfta_subaggr_id;};
272 int get_hfta_superaggr_id(){return hfta_superaggr_id;};
273 int get_actual_fcn_id(){return actual_fcn_id;};
275 std::string get_udaf_name(){return udaf_name;};
276 std::string get_actual_fcn(){return actual_fcn_name;};
281 for(m=0;m<modifiers.size();m++){
282 if(modifiers[m] == "PARTIAL")
285 if(fdt->is_buffer_type()){
291 bool is_combinable(){
293 for(m=0;m<modifiers.size();m++){
294 if(modifiers[m] == "COMBINABLE")
302 for(m=0;m<modifiers.size();m++){
303 if(modifiers[m] == "LFTA_LEGAL" || modifiers[m] == "LFTA_ONLY" || modifiers[m] == "SAMPLING")
311 for(m=0;m<modifiers.size();m++){
312 if(modifiers[m] == "LFTA_ONLY" || modifiers[m] == "SAMPLING")
318 // the SAMPLING modifier and the is_sampling_function
319 // was aded by Vlad, to support semantic sampling.
320 bool is_sampling_fcn(){
322 for(m=0;m<modifiers.size();m++){
323 if(modifiers[m] == "SAMPLING")
332 #define COST_EXPENSIVE 3
337 for(m=0;m<modifiers.size();m++){
338 if(modifiers[m] == "COST"){
339 if(vals[m] == "FREE")
341 if(vals[m] == "" || vals[m] == "LOW")
343 if(vals[m] == "HIGH")
345 if(vals[m] == "EXPENSIVE")
346 return COST_EXPENSIVE;
349 fprintf(stderr,"Warning, COST %s of function %s not understood, ignoring (options are FREE, LOW, HIGH, EXPENSIVE)\n",vals[m].c_str(), fcn_name.c_str());
356 int estimate_fcn_cost(){
358 for(m=0;m<modifiers.size();m++){
359 if(modifiers[m] == "COST"){
360 if(vals[m] == "FREE")
362 if(vals[m] == "" || vals[m] == "LOW")
364 if(vals[m] == "HIGH")
366 if(vals[m] == "EXPENSIVE")
370 fprintf(stderr,"Warning, COST %s of function %s not understood, ignoring (options are FREE, LOW, HIGH, EXPENSIVE)\n",vals[m].c_str(), fcn_name.c_str());
377 std::string get_subaggr(){
379 for(m=0;m<modifiers.size();m++){
380 if(modifiers[m] == "SUBAGGR")
386 std::string get_superaggr(){
388 for(m=0;m<modifiers.size();m++){
389 if(modifiers[m] == "SUPERAGGR")
395 std::string get_hfta_subaggr(){
397 for(m=0;m<modifiers.size();m++){
398 if(modifiers[m] == "HFTA_SUBAGGR")
404 std::string get_hfta_superaggr(){
406 for(m=0;m<modifiers.size();m++){
407 if(modifiers[m] == "HFTA_SUPERAGGR")
414 bool is_running_aggr(){
416 if(fcn_type != EXT_AGGR_)
419 for(m=0;m<modifiers.size();m++){
420 if(modifiers[m] == "RUNNING")
426 // For a special optimization,
427 // a UDAF can say that it has no contents
428 // worth transferring at tuple output time.
429 bool has_lfta_bailout(){
431 if(fcn_type != EXT_AGGR_)
434 for(m=0;m<modifiers.size();m++){
435 if(modifiers[m] == "LFTA_BAILOUT")
442 // Conventional aggregation requires only a simple
443 // execution of the produce_output callback. The
444 // sampling operator might reference the output of (non-running)
445 // aggregates multiple times. The MULT_RETURNS keyword
446 // indicates that the UDAF doesn't destroy state when the
447 // produce_output acllback is evaluated.
448 bool multiple_returns(){
450 if(fcn_type != EXT_AGGR_)
453 for(m=0;m<modifiers.size();m++){
454 if(modifiers[m] == "MULT_RETURNS")
461 std::vector<bool> get_handle_indicators(){
462 std::vector<bool> ret;
464 for(o=0;o<ef_param_list.size();o++){
465 if(ef_param_list[o]->use_handle())
468 ret.push_back(false);
473 std::vector<bool> get_const_indicators(){
474 std::vector<bool> ret;
476 for(o=0;o<ef_param_list.size();o++){
477 if(ef_param_list[o]->is_constant())
480 ret.push_back(false);
485 std::vector<bool> get_class_indicators(){
486 std::vector<bool> ret;
488 for(o=0;o<ef_param_list.size();o++){
489 if(ef_param_list[o]->is_classifier())
492 ret.push_back(false);
497 bool validate_types(std::string &err){
502 if(fdt->get_type() == undefined_t){
503 err += "ERROR, unknown type "+type_name+" as return type of function "+fcn_name+"\n";
506 if(fdt->get_type() == fstring_t){
507 err += "ERROR, type "+type_name+" as not supported as return type, of function "+fcn_name+"\n";
513 if(sdt->get_type() == undefined_t){
514 err += "ERROR, unknown type "+type_name+" as storage type of function "+fcn_name+"\n";
519 std::vector<data_type *> odt = this->get_operand_dt();
520 for(o=0;o<odt.size();++o){
521 if(odt[o]->get_type() == undefined_t){
522 err += "ERROR, unknown type "+odt[o]->get_type_str()+" as operand type of function "+fcn_name+"\n";
525 if(odt[o]->get_type() == fstring_t){
526 err += "ERROR, type "+odt[o]->get_type_str()+" as not supported as operand type, of function "+fcn_name+"\n";
539 std::vector<ext_fcn_def *> fl;
543 ext_fcn_list(ext_fcn_def *f){
547 ext_fcn_list *append_ext_fcn_def(ext_fcn_def *f){
552 int lookup_ext_fcn(std::string fname, const std::vector<data_type *> odt, int type){
556 for(f=0;f<fl.size();f++){
557 if(fl[f]->get_fcn_type() != type) continue;
558 if(fname == fl[f]->get_fcn_name()){
560 std::vector<data_type *> fdt = fl[f]->get_operand_dt();
561 if(fdt.size() != odt.size())
563 for(o=0;o<odt.size();o++){
564 if(! fdt[o]->subsumes_type(odt[o]) )
566 if(! fdt[o]->equals(odt[o])) subsume_cnt++;
571 if(subsumer != -1) return -2;
576 return(subsumer); // -1 if no subsumer found.
580 int lookup_pred(std::string fname, const std::vector<data_type *> odt){
581 return lookup_ext_fcn(fname,odt,EXT_PRED_);
583 int lookup_fcn(std::string fname, const std::vector<data_type *> odt){
584 return lookup_ext_fcn(fname,odt,EXT_FCN_);
586 int lookup_udaf(std::string fname, const std::vector<data_type *> odt){
587 return lookup_ext_fcn(fname,odt,EXT_AGGR_);
589 int lookup_extr(std::string fname, const std::vector<data_type *> odt){
590 return lookup_ext_fcn(fname,odt,EXT_EXTR_);
592 int lookup_state(std::string fname){
593 std::vector<data_type *> dum;
594 return lookup_ext_fcn(fname,dum,EXT_STATE_);
596 int lookup_sfun(std::string fname, const std::vector<data_type *> odt){
597 return lookup_ext_fcn(fname,odt,EXT_SFUN_);
604 data_type *get_fcn_dt(int f){
605 return(fl[f]->get_fcn_dt() );
607 data_type *get_storage_dt(int f){
608 return(fl[f]->get_storage_dt() );
611 bool is_partial(int f){
612 return(fl[f]->is_partial());
615 bool is_combinable(int f){
616 return(fl[f]->is_combinable());
619 bool is_running_aggr(int f){
620 return(fl[f]->is_running_aggr());
623 bool has_lfta_bailout(int f){
624 return(fl[f]->has_lfta_bailout());
627 bool multiple_returns(int f){
628 return(fl[f]->multiple_returns());
631 bool fta_legal(int f){
632 return(fl[f]->fta_legal());
635 bool is_sampling_fcn(int f) {
636 return(fl[f]->is_sampling_fcn());
639 int get_fcn_cost(int f) {
640 return(fl[f]->get_fcn_cost());
643 int estimate_fcn_cost(int f) {
644 return(fl[f]->estimate_fcn_cost());
647 int get_actual_fcn_id(int i){ return(fl[i]->get_actual_fcn_id());};
648 int get_subaggr_id(int i){ return(fl[i]->get_subaggr_id());};
649 int get_superaggr_id(int i){ return(fl[i]->get_superaggr_id());};
650 int get_hfta_subaggr_id(int i){ return(fl[i]->get_hfta_subaggr_id());};
651 int get_hfta_superaggr_id(int i){ return(fl[i]->get_hfta_superaggr_id());};
652 int get_nparams(int i){ return(fl[i]->get_nparams());};
653 std::string get_fcn_name(int i){
654 return fl[i]->get_fcn_name();
656 std::string get_storage_state(int i){return fl[i]->get_storage_state();};
660 std::vector<bool> get_handle_indicators(int f){
661 return(fl[f]->get_handle_indicators());
663 std::vector<bool> get_const_indicators(int f){
664 return(fl[f]->get_const_indicators());
666 std::vector<bool> get_class_indicators(int f){
667 return(fl[f]->get_class_indicators());
670 bool validate_fcns(std::string &err){
672 int subaggr_id, superaggr_id, hfta_subaggr_id, hfta_superaggr_id;
674 // First, validate that all data types exist and are valid.
677 for(e=0;e<fl.size();++e){
678 if(fl[e]->validate_types(err)) retval = 1;
680 if(retval) return(true);
682 // validate combinable predicates
683 for(e=0;e<fl.size();++e){
684 if(fl[e]->is_pred() && fl[e]->is_combinable()){
685 std::vector<bool> hlv = fl[e]->get_handle_indicators();
686 std::vector<bool> cov = fl[e]->get_const_indicators();
687 std::vector<bool> clv = fl[e]->get_class_indicators();
689 for(i=0;i<hlv.size();++i){
690 if( hlv[i] == false && cov[i] == false && clv[i] == false)
694 err += "ERROR, in combinable predicate "+fl[e]->get_fcn_name()+", there is a parameter that is not a CLASS-ification parameter, but neither is it CONST nor HANDLE.\n";
696 for(i=0;i<hlv.size();++i){
697 printf("\t%d: h=%d, co=%d, cl=%d\n",i,(int)hlv[i],(int)cov[i],(int)clv[i]);
705 // validate the states of the stateful functions.
706 for(e=0;e<fl.size();++e){
707 if(fl[e]->is_sfun()){
708 std::string sstate = fl[e]->get_storage_state();
709 if(lookup_state(sstate) < 0){
710 err += "ERROR, stateful function "+fl[e]->get_fcn_name()+" has state "+sstate+", which is not defined.\n";
717 // Validate subaggregates and superaggregates of udafs
719 for(e=0;e<fl.size();++e){
720 if(fl[e]->is_udaf()){
721 std::string subaggr = fl[e]->get_subaggr();
722 std::string superaggr = fl[e]->get_superaggr();
723 if(subaggr != "" || superaggr != ""){
724 if(subaggr == "" || superaggr == ""){
725 err += "ERROR, aggregate "+fl[e]->get_fcn_name()+" has a sub or superaggregate specified, but not both.\n";
729 subaggr_id=lookup_udaf(subaggr, fl[e]->get_operand_dt());
731 err+="ERROR, aggregate "+fl[e]->get_fcn_name()+" has a subaggregate specified, but it can't be found.\n";
732 if(subaggr_id == -2) err+="(multiple subsuming subaggrs found)\n";
736 std::vector<data_type *> dtv;
737 dtv.push_back( fl[subaggr_id]->get_fcn_dt() );
738 superaggr_id=lookup_udaf(superaggr, dtv);
739 if(superaggr_id < 0){
740 err+="ERROR, aggregate "+fl[e]->get_fcn_name()+" has a superaggregate specified, but it can't be found.\n";
741 if(subaggr_id == -2) err+="(multiple subsuming superaggrs found)\n";
746 if( fl[e]->is_running_aggr() != fl[superaggr_id]->is_running_aggr()){
747 err+="ERROR, aggregate "+fl[e]->get_fcn_name()+" has a superaggregate specified, but one is a running aggregate and the other isn't\n";
748 //printf("e=%d (%u), superaggr_id=%d (%u)\n",e, fl[e]->is_running_aggr(),superaggr_id,fl[superaggr_id]->is_running_aggr());
753 if(! fl[e]->get_fcn_dt()->equals(fl[superaggr_id]->get_fcn_dt())){
754 err+="ERROR, aggregate "+fl[e]->get_fcn_name()+" has a superaggregate specified, but they have different return types.\n";
759 if(fl[subaggr_id]->get_subaggr()!="" || fl[subaggr_id]->get_superaggr() != ""){
760 err+="ERROR, aggregate "+fl[e]->get_fcn_name()+" has a subaggregate specified, but it also has sub/super aggregates\n";
764 if(fl[superaggr_id]->get_subaggr()!="" || fl[superaggr_id]->get_superaggr() != ""){
765 err+="ERROR, aggregate "+fl[e]->get_fcn_name()+" has a subaggregate specified, but it also has sub/super aggregates\n";
770 fl[e]->set_subaggr_id(subaggr_id);
771 fl[e]->set_superaggr_id(superaggr_id);
776 // Validate high level subaggregates and superaggregates of udafs (hfta_subaggregate and hfta_supeaggregate)
778 for(e=0;e<fl.size();++e){
779 if(fl[e]->is_udaf()){
780 std::string hfta_subaggr = fl[e]->get_hfta_subaggr();
781 std::string hfta_superaggr = fl[e]->get_hfta_superaggr();
782 if(hfta_subaggr != "" || hfta_superaggr != ""){
783 if(hfta_subaggr == "" || hfta_superaggr == ""){
784 err += "ERROR, aggregate "+fl[e]->get_fcn_name()+" has a hfta_sub or hfta_superaggregate specified, but not both.\n";
788 hfta_subaggr_id=lookup_udaf(hfta_subaggr, fl[e]->get_operand_dt());
789 if(hfta_subaggr_id < 0){
790 err+="ERROR, aggregate "+fl[e]->get_fcn_name()+" has a hfta_subaggregate specified, but it can't be found.\n";
791 if(subaggr_id == -2) err+="(multiple subsuming hfta_subaggrs found)\n";
795 std::vector<data_type *> dtv;
796 dtv.push_back( fl[hfta_subaggr_id]->get_fcn_dt() );
797 hfta_superaggr_id=lookup_udaf(hfta_superaggr, dtv);
798 if(hfta_superaggr_id < 0){
799 err+="ERROR, aggregate "+fl[e]->get_fcn_name()+" has a hfta_superaggregate specified, but it can't be found.\n";
800 if(hfta_subaggr_id == -2) err+="(multiple subsuming hfta_superaggrs found)\n";
805 if(! fl[e]->get_fcn_dt()->equals(fl[hfta_superaggr_id]->get_fcn_dt())){
806 err+="ERROR, aggregate "+fl[e]->get_fcn_name()+" has a hfta_superaggregate specified, but they have different return types.\n";
813 if(fl[hfta_subaggr_id]->get_hfta_subaggr()!="" || fl[hfta_subaggr_id]->get_hfta_superaggr() != ""){
814 err+="ERROR, aggregate "+fl[e]->get_fcn_name()+" has a hfta_subaggregate specified, but it also has hfta sub/super aggregates\n";
818 if(fl[hfta_superaggr_id]->get_hfta_subaggr()!="" || fl[hfta_superaggr_id]->get_hfta_superaggr() != ""){
819 err+="ERROR, aggregate "+fl[e]->get_fcn_name()+" has a hfta_subaggregate specified, but it also has hfta sub/super aggregates\n";
825 fl[e]->set_hfta_subaggr_id(hfta_subaggr_id);
826 fl[e]->set_hfta_superaggr_id(hfta_superaggr_id);
831 // Verify the extraction functions
832 for(e=0;e<fl.size();++e){
833 if(fl[e]->is_extr()){
834 //printf("Verifying extractor %d\n",e);
835 std::vector<data_type *> ope = fl[e]->get_operand_dt();
836 // Find the subaggregate
838 for(a=0;a<fl.size();++a){
839 if(fl[a]->is_udaf() && fl[e]->get_udaf_name() == fl[a]->get_fcn_name()){
840 //printf("matching to subaggregagte %d\n",a);
841 std::vector<data_type *> opa = fl[a]->get_operand_dt();
842 if(opa.size() > ope.size()) continue;
844 bool match_ops = true;
845 for(o=0;o<opa.size();++o){
846 if(! ope[o]->equals(opa[o])) match_ops = false;
847 //else printf("\tmatched operand %d\n",o);
850 //else printf("subaggregate match failed.\n");
854 err+="ERROR, aggregate extractor "+fl[e]->get_fcn_name()+" has a subaggregate "+ fl[e]->get_udaf_name()+" specified, but it can't be found.\n";
859 // Found the subaggregate
861 std::vector<data_type *> opa = fl[a]->get_operand_dt();
863 // Find the actual function
864 for(f=0;f<fl.size();++f){
865 if(fl[f]->is_fcn() && fl[e]->get_actual_fcn() == fl[f]->get_fcn_name()){
866 //printf("Matching to extraction function %d\n",f);
867 std::vector<data_type *> opf = fl[f]->get_operand_dt();
868 if(opf.size() + opa.size() -1 != ope.size()) continue;
869 //else printf("Operand sizes match (%d + %d -1 = %d)\n",opf.size(),opa.size(),ope.size() );
871 bool match_ops = true;
872 if(! fl[a]->get_fcn_dt()->equals(opf[0])) match_ops=false;
873 //if(!match_ops) printf("aggr return val doesn't match 1st param\n");
874 for(o=1;o<opf.size();++o){
875 if(! ope[o+opa.size()-1]->equals(opf[o]))
877 //else printf("\tmatched operand e[%d] to f[%d]\n",o+opa.size()-1,o);
880 //else printf("Match failed.\n");
884 err+="ERROR, aggregate extractor "+fl[e]->get_fcn_name()+" uses function "+ fl[e]->get_actual_fcn()+", but it can't be found.\n";
888 if(! fl[e]->get_fcn_dt()->equals(fl[f]->get_fcn_dt()) ){
889 err+="ERROR, aggregate extractor "+fl[e]->get_fcn_name()+" uses function "+ fl[e]->get_actual_fcn()+", but they have different return value types.\n";
894 // Found the extractor fcn, record them in the ext fcn struct.
895 fl[e]->set_subaggr_id(subaggr_id);
896 fl[e]->set_actual_fcnid(f);
900 if(retval) return(true); else return(false);