/*******************************************************************\

Module: Traces of GOTO Programs

Author: Daniel Kroening

  Date: November 2005

\*******************************************************************/

#include <assert.h>

#include <xml_irep.h>
#include <i2string.h>
#include <format_constant.h>

#include <langapi/language_util.h>

#include "xml_goto_trace.h"

/*******************************************************************\

Function: convert

  Inputs:

 Outputs:

 Purpose:

\*******************************************************************/

void convert(
  const namespacet &ns,
  const goto_tracet &goto_trace,
  xmlt &xml)
{
  xml=xmlt("goto_trace");
  
  xml.new_element("mode").data=goto_trace.mode;

  locationt previous_location;

  for(goto_tracet::stepst::const_iterator
      it=goto_trace.steps.begin();
      it!=goto_trace.steps.end();
      it++)
  {
    const locationt &location=it->pc->location;
    
    xmlt xml_location;
    if(location.is_not_nil() && location.get_file()!="")
    {
      convert(location, xml_location);
      xml_location.name="location";
    }
    
    switch(it->type)
    {
    case goto_trace_stept::ASSERT:
      if(!it->guard)
      {
        xmlt &xml_failure=xml.new_element("failure");
        xml_failure.new_element("reason").data=xmlt::escape(id2string(it->comment));
        
        xml_failure.new_element("thread").data=i2string(it->thread_nr);

        if(xml_location.name!="")
          xml_failure.new_element().swap(xml_location);
      }
      break;
      
    case goto_trace_stept::ASSIGNMENT:
      {
        irep_idt identifier;

        if(it->original_lhs.is_not_nil())
          identifier=it->original_lhs.get("identifier");
        else
          identifier=it->lhs.get("identifier");
          
        xmlt &xml_assignment=xml.new_element("assignment");

        if(xml_location.name!="")
          xml_assignment.new_element().swap(xml_location);

        std::string value_string, type_string;
        
        if(it->value.is_not_nil())
          value_string=from_expr(ns, identifier, it->value);

        if(it->value.type().is_not_nil())
          type_string=from_type(ns, identifier, it->value.type());

        const symbolt *symbol;
        irep_idt base_name, display_name;

        if(!ns.lookup(identifier, symbol))
        {
          base_name=symbol->base_name;
          display_name=symbol->display_name();
          if(type_string=="")
            type_string=from_type(ns, identifier, symbol->type);

          xml_assignment.new_element("mode").data=xmlt::escape(id2string(symbol->mode));
        }

        xml_assignment.new_element("thread").data=i2string(it->thread_nr);
        xml_assignment.new_element("identifier").data=xmlt::escape(id2string(identifier));
        xml_assignment.new_element("base_name").data=xmlt::escape(id2string(base_name));
        xml_assignment.new_element("display_name").data=xmlt::escape(id2string(display_name));
        xml_assignment.new_element("value").data=xmlt::escape(id2string(value_string));
        xml_assignment.new_element("type").data=xmlt::escape(id2string(type_string));
        xml_assignment.new_element("step_nr").data=i2string(it->step_nr);
      }
      break;
      
    case goto_trace_stept::OUTPUT:
      {
        std::string text;
        
        for(std::list<exprt>::const_iterator
            a_it=it->output_args.begin();
            a_it!=it->output_args.end();
            a_it++)
          text+=xmlt::escape(format_constant(*a_it));
      
        xmlt &xml_output=xml.new_element("output");
        xml_output.new_element("step_nr").data=i2string(it->step_nr);
        xml_output.new_element("thread").data=i2string(it->thread_nr);
        xml_output.new_element("text").data.swap(text);
        xml_output.new_element().swap(xml_location);
      }
      break;
      
    default:
      if(location!=previous_location)
      {
        // just the location
        if(xml_location.name!="")
        {
          xmlt &xml_location_only=xml.new_element("location-only");
          xml_location_only.new_element("step_nr").data=i2string(it->step_nr);
          xml_location_only.new_element("thread").data=i2string(it->thread_nr);
          xml_location_only.new_element().swap(xml_location);
        }
      }
    }

    if(location.is_not_nil() && location.get_file()!="")
      previous_location=location;
  }
}
