ancr.c

00001 /*
00002  * Copyright (c) 2010 Jiri Svoboda
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  */
00028 
00050 #include <stdlib.h>
00051 #include <assert.h>
00052 #include "builtin.h"
00053 #include "cspan.h"
00054 #include "list.h"
00055 #include "mytypes.h"
00056 #include "stree.h"
00057 #include "strtab.h"
00058 #include "symbol.h"
00059 
00060 #include "ancr.h"
00061 
00062 static void ancr_csi_dfs(stree_program_t *prog, stree_csi_t *csi);
00063 static void ancr_csi_process(stree_program_t *prog, stree_csi_t *node);
00064 static stree_csi_t *ancr_csi_get_pred(stree_program_t *prog, stree_csi_t *csi,
00065     stree_texpr_t *pred_ref);
00066 static void ancr_csi_print_cycle(stree_program_t *prog, stree_csi_t *node);
00067 
00076 void ancr_module_process(stree_program_t *prog, stree_module_t *module)
00077 {
00078         list_node_t *node;
00079         stree_modm_t *modm;
00080 
00081         (void) module;
00082         node = list_first(&prog->module->members);
00083 
00084         while (node != NULL) {
00085                 modm = list_node_data(node, stree_modm_t *);
00086 
00087                 switch (modm->mc) {
00088                 case mc_csi:
00089                         ancr_csi_dfs(prog, modm->u.csi);
00090                         break;
00091                 case mc_enum:
00092                         break;
00093                 }
00094 
00095                 node = list_next(&prog->module->members, node);
00096         }
00097 }
00098 
00108 static void ancr_csi_dfs(stree_program_t *prog, stree_csi_t *csi)
00109 {
00110         list_node_t *node;
00111         stree_csimbr_t *csimbr;
00112 
00113         /* Process this node first. */
00114         ancr_csi_process(prog, csi);
00115 
00116         /* Now visit all children. */
00117         node = list_first(&csi->members);
00118         while (node != NULL) {
00119                 csimbr = list_node_data(node, stree_csimbr_t *);
00120                 if (csimbr->cc == csimbr_csi)
00121                         ancr_csi_dfs(prog, csimbr->u.csi);
00122 
00123                 node = list_next(&csi->members, node);
00124         }
00125 }
00126 
00135 static void ancr_csi_process(stree_program_t *prog, stree_csi_t *csi)
00136 {
00137         stree_csi_t *base_csi, *outer_csi;
00138         stree_csi_t *gf_class;
00139 
00140         list_node_t *pred_n;
00141         stree_texpr_t *pred;
00142         stree_csi_t *pred_csi;
00143 
00144         if (csi->ancr_state == ws_visited) {
00145                 /* Node already processed */
00146                 return;
00147         }
00148 
00149         if (csi->ancr_state == ws_active) {
00150                 /* Error, closed reference loop. */
00151                 printf("Error: Circular class, struct or interface chain: ");
00152                 ancr_csi_print_cycle(prog, csi);
00153                 printf(".\n");
00154                 exit(1);
00155         }
00156 
00157         csi->ancr_state = ws_active;
00158 
00159         outer_csi = csi_to_symbol(csi)->outer_csi;
00160         gf_class = builtin_get_gf_class(prog->builtin);
00161 
00162         if (csi != gf_class){
00163                 /* Implicit inheritance from grandfather class. */
00164                 base_csi = gf_class;
00165         } else {
00166                 /* Grandfather class has no base class. */
00167                 base_csi = NULL;
00168         }
00169 
00170         /* Process outer CSI */
00171         if (outer_csi != NULL)
00172                 ancr_csi_process(prog, outer_csi);
00173 
00174         /*
00175          * Process inheritance list.
00176          */
00177         pred_n = list_first(&csi->inherit);
00178 
00179         /* For a class node, the first entry can be a class. */
00180         if (csi->cc == csi_class && pred_n != NULL) {
00181                 pred = list_node_data(pred_n, stree_texpr_t *);
00182                 pred_csi = ancr_csi_get_pred(prog, csi, pred);
00183                 assert(pred_csi != NULL);
00184 
00185                 if (pred_csi->cc == csi_class) {
00186                         /* Process base class */
00187                         base_csi = pred_csi;
00188                         ancr_csi_process(prog, pred_csi);
00189 
00190                         pred_n = list_next(&csi->inherit, pred_n);
00191                 }
00192         }
00193 
00194         /* Following entires can only be interfaces. */
00195         while (pred_n != NULL) {
00196                 pred = list_node_data(pred_n, stree_texpr_t *);
00197                 pred_csi = ancr_csi_get_pred(prog, csi, pred);
00198                 assert(pred_csi != NULL);
00199 
00200                 /* Process implemented or accumulated interface. */
00201                 ancr_csi_process(prog, pred_csi);
00202 
00203                 switch (pred_csi->cc) {
00204                 case csi_class:
00205                         switch (csi->cc) {
00206                         case csi_class:
00207                                 cspan_print(csi->name->cspan);
00208                                 printf(" Error: Only the first predecessor "
00209                                     "can be a class. ('");
00210                                 symbol_print_fqn(csi_to_symbol(csi));
00211                                 printf("' deriving from '");
00212                                 symbol_print_fqn(csi_to_symbol(pred_csi));
00213                                 printf("').\n");
00214                                 exit(1);
00215                                 break;
00216                         case csi_struct:
00217                                 assert(b_false); /* XXX */
00218                         case csi_interface:
00219                                 cspan_print(csi->name->cspan);
00220                                 printf(" Error: Interface predecessor must be "
00221                                     "an interface ('");
00222                                 symbol_print_fqn(csi_to_symbol(csi));
00223                                 printf("' deriving from '");
00224                                 symbol_print_fqn(csi_to_symbol(pred_csi));
00225                                 printf("').\n");
00226                                 exit(1);
00227                                 break;
00228                         }
00229                 case csi_struct:
00230                         assert(b_false); /* XXX */
00231                 case csi_interface:
00232                         break;
00233                 }
00234 
00235                 pred_n = list_next(&csi->inherit, pred_n);
00236         }
00237 
00238         /* Store base CSI and update node state. */
00239         csi->ancr_state = ws_visited;
00240         csi->base_csi = base_csi;
00241 }
00242 
00253 static stree_csi_t *ancr_csi_get_pred(stree_program_t *prog, stree_csi_t *csi,
00254     stree_texpr_t *pred_ref)
00255 {
00256         stree_csi_t *outer_csi;
00257         stree_symbol_t *pred_sym;
00258         stree_csi_t *pred_csi;
00259 
00260         outer_csi = csi_to_symbol(csi)->outer_csi;
00261         pred_sym = symbol_xlookup_in_csi(prog, outer_csi, pred_ref);
00262         pred_csi = symbol_to_csi(pred_sym);
00263         assert(pred_csi != NULL); /* XXX */
00264 
00265         return pred_csi;
00266 }
00267 
00276 static void ancr_csi_print_cycle(stree_program_t *prog, stree_csi_t *node)
00277 {
00278         stree_csi_t *n;
00279         stree_symbol_t *pred_sym, *node_sym;
00280         stree_csi_t *pred_csi, *outer_csi;
00281         stree_texpr_t *pred;
00282         list_node_t *pred_n;
00283 
00284         n = node;
00285         do {
00286                 node_sym = csi_to_symbol(node);
00287                 symbol_print_fqn(node_sym);
00288                 printf(", ");
00289 
00290                 outer_csi = node_sym->outer_csi;
00291 
00292                 if (outer_csi != NULL && outer_csi->ancr_state == ws_active) {
00293                         node = outer_csi;
00294                 } else {
00295                         node = NULL;
00296 
00297                         pred_n = list_first(&node->inherit);
00298                         while (pred_n != NULL) {
00299                                 pred = list_node_data(pred_n, stree_texpr_t *);
00300                                 pred_sym = symbol_xlookup_in_csi(prog,
00301                                     outer_csi, pred);
00302                                 pred_csi = symbol_to_csi(pred_sym);
00303                                 assert(pred_csi != NULL);
00304 
00305                                 if (pred_csi->ancr_state == ws_active) {
00306                                         node = pred_csi;
00307                                         break;
00308                                 }
00309                         }
00310 
00311                         assert(node != NULL);
00312                 }
00313         } while (n != node);
00314 
00315         node_sym = csi_to_symbol(node);
00316         symbol_print_fqn(node_sym);
00317 }

Generated on Thu Jun 2 07:45:42 2011 for HelenOS/USB by  doxygen 1.4.7