///////////////////////////////////////////////////////////////////////////////
//                             Lisaac Compiler                               //
//                                                                           //
//                   LSIIT - ULP - CNRS - INRIA - FRANCE                     //
//                                                                           //
//   This program is free software: you can redistribute it and/or modify    //
//   it under the terms of the GNU General Public License as published by    //
//   the Free Software Foundation, either version 3 of the License, or       //
//   (at your option) any later version.                                     //
//                                                                           //
//   This program is distributed in the hope that it will be useful,         //
//   but WITHOUT ANY WARRANTY; without even the implied warranty of          //
//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           //
//   GNU General Public License for more details.                            //
//                                                                           //
//   You should have received a copy of the GNU General Public License       //
//   along with this program.  If not, see <http://www.gnu.org/licenses/>.   //
//                                                                           //
//                     http://isaacproject.u-strasbg.fr/                     //
///////////////////////////////////////////////////////////////////////////////
Section Header
  
  + name        := TYPE_GENERIC;

  - copyright   := "2003-2007 Benoit Sonntag";

  
  - author      := "Sonntag Benoit (bsonntag@loria.fr)";
  - comment     := "Type generic";
  
Section Inherit
  
  + parent_type:Expanded TYPE;

Section Private  
  
  // BSBS: Vu que les ITM_TYPE sont aliaser, il n'est pas necessary d'aliaser les TYPE !
  // Mais attention au pb des TYPE_GENERIC et de leur alias de slot_run...
  
  - dicog_type:HASHED_DICTIONARY[TYPE_GENERIC,STRING_CONSTANT] := 
  HASHED_DICTIONARY[TYPE_GENERIC,STRING_CONSTANT].create;
    
Section Public
  
  + name:STRING_CONSTANT;
  
  + intern_name:STRING_CONSTANT;
  
  + generic_list:FAST_ARRAY[TYPE_FULL];  
  
  - generic_to_type char:CHARACTER :TYPE_FULL <-
  ( + idx:INTEGER;
    + result:TYPE_FULL;
    + tab:FAST_ARRAY[CHARACTER];
    
    tab := prototype.idf_generic_list;
    idx := tab.fast_first_index_of char;
    (idx <= tab.upper).if {
      result := generic_list.item idx;
    };
    result
  );
  
  //
  // Get
  //
  
  - get itm_typ:ITM_TYPE_SIMPLE :TYPE_FULL <-  
  (
    crash_with_message "`get' in TYPE_GENERIC !";
    NULL
  );
  
  - get itm_typ:ITM_TYPE_SIMPLE with gen:FAST_ARRAY[TYPE_FULL] :TYPE_FULL <-
  ( + base:TYPE_GENERIC;
    + key:STRING_CONSTANT;
    + result:TYPE_FULL;
    + styl:STRING_CONSTANT;
    
    string_tmp.copy (itm_typ.name);
    string_tmp.add_last '[';    
    //
    (gen.lower).to (gen.upper - 1) do { j:INTEGER;      
      gen.item j.append_name_in string_tmp;
      string_tmp.add_last ',';
    };    
    gen.last.append_name_in string_tmp;
    string_tmp.add_last ']';        
    key := ALIAS_STR.get string_tmp;
    //
    base := dicog_type.fast_reference_at key;
    (base = NULL).if {      
      base := TYPE_GENERIC.clone;
      dicog_type.fast_put base to key;
      base.make (itm_typ,key) with gen;
    };
    //            
    styl := itm_typ.style;
    (styl = NULL).if {           
      result := base.default;
    } else {
      (styl = ALIAS_STR.keyword_expanded).if {	
	result := base.default + TYPE_FULL.expanded_bit;	
      } else {	
	result := base.default + TYPE_FULL.strict_bit;
      };
    };    
    result
  );

  //
  // Life Type for collection (see PUT_TO and ITEM)
  // BSBS: A revoir : il n'y a que NATIVE_ARRAY qui a besoin de ca,
  // il faudrai plutot stocker ca ailleurs... ou? chépa!
  //
  
  + put_to_list:FAST_ARRAY[PUT_TO];
  
  - add_put_to n:PUT_TO <-
  (    
    (put_to_list = NULL).if {
      put_to_list := FAST_ARRAY[PUT_TO].create_with_capacity 16;
    };
    put_to_list.add_last n;
  );
  
  - remove_put_to n:PUT_TO <-
  ( + idx:INTEGER;
    
    idx := put_to_list.fast_first_index_of n;    
    put_to_list.swap idx with (put_to_list.upper);
    put_to_list.remove_last;
  );
  
  + recursive_test:BOOLEAN;
  
  + old_type:TYPES;
  
  - get_type t:TYPES_TMP <-
  ( + typ:TYPE_FULL;
    + tmp_type:TYPES_TMP;
                
    typ := generic_list.first;
    (typ.is_expanded && {typ.raw != type_boolean}).if {    
      t.add (typ.raw);
    } else {      
      (put_to_list != NULL).if {
	(! recursive_test).if { 
	  recursive_test := TRUE;
	  tmp_type := TYPES_TMP.new;
	  (put_to_list.lower).to (put_to_list.upper) do { j:INTEGER;
	    put_to_list.item j.value.get_type tmp_type;
	  };	  
	  old_type := tmp_type.update old_type;
	  recursive_test := FALSE;
	};
	t.union old_type;
      };
    };
  );
  
  //
  // Declaration generation.
  //
  
  - put_reference_declaration buffer:STRING <-
  (    
    (prototype.name = ALIAS_STR.prototype_native_array).if {      
      generic_list.first.genere_declaration buffer;
    }.elseif {prototype.name = ALIAS_STR.prototype_native_array_volatile} then {
      buffer.append "volatile ";
      generic_list.first.genere_declaration buffer;
    } else {
      parent_type.put_reference_declaration buffer;
    };
  );
  
  - put_reference_star_declaration buffer:STRING <-
  (     
    (
      (prototype.name = ALIAS_STR.prototype_native_array) ||
      {prototype.name = ALIAS_STR.prototype_native_array_volatile}
    ).if {      
      buffer.add_last '*';
      generic_list.first.genere_star_declaration buffer;
    } else {
      parent_type.put_reference_star_declaration buffer;
    };
  );
       
Section Public  
  
  - make itm_typ:ITM_TYPE_SIMPLE <-
  (
    crash_with_message "TYPE_GENERIC.make";
  );

  - make (itm_typ:ITM_TYPE_SIMPLE,n:STRING_CONSTANT) with gen:FAST_ARRAY[TYPE_FULL] <-
  ( + mask_bit:UINTEGER_8;    
    
    index        := index_count;
    index_count  := index_count + 1;
    name         := n;
    generic_list := gen;
    string_tmp.copy n;
    string_tmp.replace_all ',' with 'x';
    string_tmp.replace_all '[' with 'o';
    string_tmp.replace_all ']' with 'o';
    string_tmp.replace_all ' ' with '_';
    intern_name := ALIAS_STR.get string_tmp;
    //
    prototype   := load_prototype (itm_typ.name) generic_count (gen.count);
    itm_type    := itm_typ;    
    slot_run    := FAST_ARRAY[SLOT].create_with_capacity 10; // BSBS: A voir.    
    (prototype.type_style = ALIAS_STR.keyword_expanded).if {
      // Expanded.
      mask_bit := TYPE_FULL.expanded_bit | TYPE_FULL.default_expanded_bit;
    }.elseif {prototype.type_style = ALIAS_STR.keyword_strict} then {
      // Strict.
      mask_bit := TYPE_FULL.strict_bit | TYPE_FULL.default_strict_bit;
    };
    default := TYPE_FULL.create Self with mask_bit;
    prototype.init_slot_for Self;    
    //
    subtype_list := HASHED_SET[TYPE].create;
    subtype_list.fast_add TYPE_NULL;
    add_subtype Self;
  );

 