text: /*******************************************************************\
  
  Module: C++ Language Type Checking
  
  Author: Daniel Kroening, kroening@cs.cmu.edu
  
  \*******************************************************************/
  
  #include <ostream>
  
  #include "template_map.h"
  
  /*******************************************************************\
  
  Function: template_mapt::apply
  
    Inputs:
  
   Outputs:
  
   Purpose:
  
  \*******************************************************************/
  
  void template_mapt::apply(typet &type) const
  {
    if(type.id()==ID_array)
    {
      apply(type.subtype());
      apply(static_cast<exprt &>(type.add(ID_size)));
    }
    else if(type.id()==ID_pointer)
    {
      apply(type.subtype());
    }
    else if(type.id()==ID_struct ||
            type.id()==ID_union)
    {
      irept::subt &components=type.add(ID_components).get_sub();
  
      Forall_irep(it, components)
      {
        typet &subtype=static_cast<typet &>(it->add(ID_type));
        apply(subtype);
      }
    }
    else if(type.id()==ID_symbol)
    {
      type_mapt::const_iterator m_it=
        type_map.find(type.get(ID_identifier));
  
      if(m_it!=type_map.end())
      {
        type=m_it->second;
        return;
      }
    }
    else if(type.id()==ID_code)
    {
      apply(static_cast<typet &>(type.add(ID_return_type)));
  
      irept::subt &parameters=type.add(ID_parameters).get_sub();
  
      Forall_irep(it, parameters)
      {
        if(it->id()==ID_parameter)
          apply(static_cast<typet &>(it->add(ID_type)));
      }
    }
    else if(type.id()==ID_merged_type)
    {
      Forall_subtypes(it, type)
        apply(*it);
    }
  }
  
  /*******************************************************************\
  
  Function: template_mapt::apply
  
    Inputs:
  
   Outputs:
  
   Purpose:
  
  \*******************************************************************/
  
  void template_mapt::apply(exprt &expr) const
  {
    apply(expr.type());
  
    if(expr.id()==ID_symbol)
    {
      expr_mapt::const_iterator m_it=
        expr_map.find(expr.get(ID_identifier));
  
      if(m_it!=expr_map.end())
      {
        expr=m_it->second;
        return;
      }
    }
  
    Forall_operands(it, expr)
      apply(*it);
  }
  
  /*******************************************************************\
  
  Function: template_mapt::lookup
  
    Inputs:
  
   Outputs:
  
   Purpose:
  
  \*******************************************************************/
  
  exprt template_mapt::lookup(const irep_idt &identifier) const
  {
    type_mapt::const_iterator t_it=
      type_map.find(identifier);
  
    if(t_it!=type_map.end())
    {
      exprt e(ID_type);
      e.type()=t_it->second;
      return e;
    }
  
    expr_mapt::const_iterator e_it=
      expr_map.find(identifier);
  
    if(e_it!=expr_map.end())
      return e_it->second;
  
    return static_cast<const exprt &>(get_nil_irep());
  }
  
  /*******************************************************************\
  
  Function: template_mapt::lookup_type
  
    Inputs:
  
   Outputs:
  
   Purpose:
  
  \*******************************************************************/
  
  typet template_mapt::lookup_type(const irep_idt &identifier) const
  {
    type_mapt::const_iterator t_it=
      type_map.find(identifier);
  
    if(t_it!=type_map.end())
      return t_it->second;
  
    return static_cast<const typet &>(get_nil_irep());
  }
  
  /*******************************************************************\
  
  Function: template_mapt::lookup_expr
  
    Inputs:
  
   Outputs:
  
   Purpose:
  
  \*******************************************************************/
  
  exprt template_mapt::lookup_expr(const irep_idt &identifier) const
  {
    expr_mapt::const_iterator e_it=
      expr_map.find(identifier);
  
    if(e_it!=expr_map.end())
      return e_it->second;
  
    return static_cast<const exprt &>(get_nil_irep());
  }
  
  /*******************************************************************\
  
  Function: template_mapt::print
  
    Inputs:
  
   Outputs:
  
   Purpose:
  
  \*******************************************************************/
  
  void template_mapt::print(std::ostream &out) const
  {
    for(type_mapt::const_iterator it=type_map.begin();
        it!=type_map.end();
        it++)
      out << it->first << " = " << it->second.pretty() << std::endl;
  
    for(expr_mapt::const_iterator it=expr_map.begin();
        it!=expr_map.end();
        it++)
      out << it->first << " = " << it->second.pretty() << std::endl;
  }
  
  /*******************************************************************\
  
  Function: template_mapt::build
  
    Inputs:
  
   Outputs:
  
   Purpose:
  
  \*******************************************************************/
  
  void template_mapt::build(
    const template_typet &template_type,
    const cpp_template_args_tct &template_args)
  {
    const template_typet::template_parameterst &template_parameters=
      template_type.template_parameters();
  
    cpp_template_args_tct::argumentst instance=
      template_args.arguments();
  
    template_typet::template_parameterst::const_iterator t_it=
      template_parameters.begin();
  
    if(instance.size()<template_parameters.size())
    {
      // check for default parameters
      for(std::size_t i=instance.size();
          i<template_parameters.size();
          i++)
      {
        const template_parametert &param=template_parameters[i];
  
        if(param.has_default_argument())
          instance.push_back(param.default_argument());
        else
          break;
      }
    }
  
    // these should have been typechecked before
    assert(instance.size()==template_parameters.size());
  
    for(cpp_template_args_tct::argumentst::const_iterator
        i_it=instance.begin();
        i_it!=instance.end();
        i_it++, t_it++)
    {
      assert(t_it!=template_parameters.end());
      set(*t_it, *i_it);
    }
  }
  
  /*******************************************************************\
  
  Function: template_mapt::set
  
    Inputs:
  
   Outputs:
  
   Purpose:
  
  \*******************************************************************/
  
  void template_mapt::set(
    const template_parametert &parameter,
    const exprt &value)
  {
    if(parameter.id()==ID_type)
    {
      if(parameter.id()!=ID_type)
        assert(false); // typechecked before!
  
      typet tmp=value.type();
  
      irep_idt identifier=parameter.type().get(ID_identifier);
      type_map[identifier]=tmp;
    }
    else
    {
      // must be non-type
    
      if(value.id()==ID_type)
        assert(false); // typechecked before!
  
      irep_idt identifier=parameter.get(ID_identifier);
      expr_map[identifier]=value;
    }    
  }
  
  /*******************************************************************\
  
  Function: template_mapt::build_unassigned
  
    Inputs:
  
   Outputs:
  
   Purpose:
  
  \*******************************************************************/
  
  void template_mapt::build_unassigned(
    const template_typet &template_type)
  {
    const template_typet::template_parameterst &template_parameters=
      template_type.template_parameters();
  
    for(template_typet::template_parameterst::const_iterator
        t_it=template_parameters.begin();
        t_it!=template_parameters.end();
        t_it++)
    {
      const template_parametert &t=*t_it;
      
      if(t.id()==ID_type)
      {
        typet tmp(ID_unassigned);
        tmp.set(ID_identifier, t.type().get(ID_identifier));
        tmp.add_source_location()=t.source_location();
        type_map[t.type().get(ID_identifier)]=tmp;
      }
      else
      {
        exprt tmp(ID_unassigned, t.type());
        tmp.set(ID_identifier, t.get(ID_identifier));
        tmp.add_source_location()=t.source_location();
        expr_map[t.get(ID_identifier)]=tmp;
      }    
    }
  }
  
  /*******************************************************************\
  
  Function: template_mapt::build_template_args
  
    Inputs:
  
   Outputs:
  
   Purpose:
  
  \*******************************************************************/
  
  cpp_template_args_tct template_mapt::build_template_args(
    const template_typet &template_type) const
  {
    const template_typet::template_parameterst &template_parameters=
      template_type.template_parameters();
  
    cpp_template_args_tct template_args;
    template_args.arguments().resize(template_parameters.size());
    
    for(std::size_t i=0; i<template_parameters.size(); i++)
    {
      const template_parametert &t=template_parameters[i];
      
      if(t.id()==ID_type)
      {
        template_args.arguments()[i]=
          exprt(ID_type, lookup_type(t.type().get(ID_identifier)));
      }
      else
      {
        template_args.arguments()[i]=
          lookup_expr(t.get(ID_identifier));
      }    
    }
    
    return template_args;
  }
  
  