Added newline char to end of line (remove compile warning)
[mussa.git] / alg / motif_parser.cpp
1 #include "mussa_exceptions.hpp"
2 #include "alg/alphabet.hpp"
3 #include "alg/motif_parser.hpp"
4
5 #include <boost/spirit/core.hpp>
6 #include <boost/spirit/actor/push_back_actor.hpp>
7 #include <boost/spirit/iterator/file_iterator.hpp>
8 #include <boost/spirit/utility/chset.hpp>
9 namespace spirit = boost::spirit;
10
11 #include <sstream>
12 #include <stdexcept>
13
14 motif_parser::push_channel::push_channel( motif_parser::ParsedMotifs *parsed_ ) :
15   parsed(parsed_)
16 {
17 }
18   
19 void motif_parser::push_channel::operator()(float f) const
20 {
21   parsed->channels.push_back(f);
22 }
23
24 motif_parser::push_sequence::push_sequence( ParsedMotifs *parsed_) :
25   parsed(parsed_)
26 {
27 }
28   
29 template<typename Iterator>
30 void motif_parser::push_sequence::operator()(
31   Iterator start,
32   Iterator end) const
33 {
34   std::copy(start, end, std::back_inserter(parsed->sequence));   
35 }
36
37 motif_parser::push_name::push_name( ParsedMotifs *parsed_) :
38   parsed(parsed_)
39 {
40 }
41
42 template<typename Iterator>
43 void motif_parser::push_name::operator()(
44   Iterator start,
45   Iterator end) const
46 {
47   std::copy(start, end, std::back_inserter(parsed->name));   
48 }
49
50 motif_parser::push_motif::push_motif( ParsedMotifs *parsed_) :
51   parsed(parsed_) {}
52     
53 template<typename Iterator>
54 void motif_parser::push_motif::operator()(
55   Iterator start,
56   Iterator end) const
57 {
58   float red, green, blue, alpha;
59   Sequence seq(parsed->sequence, Sequence::nucleic_alphabet);
60   seq.set_fasta_header(parsed->name);
61   
62   alpha = 1.0;
63   switch (parsed->channels.size()) {
64     case 4:
65       alpha = parsed->channels[3];
66       // note fall through.
67   case 3:
68     red = parsed->channels[0];
69     green = parsed->channels[1];
70     blue = parsed->channels[2];
71     break;        
72   default:
73     throw std::runtime_error("wrong number of channels");
74     break;
75   }
76   Color c(red, green, blue, alpha);
77   parsed->color_mapper->appendInstanceColor("motif", seq.c_str(), c);
78   parsed->motifs.insert(seq);
79   
80   parsed->sequence.clear();
81   parsed->name.clear();
82   parsed->channels.clear();
83 }
84
85 motif_parser::ParsedMotifs::ParsedMotifs(
86   Mussa::motif_set& motifs_, 
87   boost::shared_ptr<AnnotationColors> color_mapper_) :
88   motifs(motifs_),
89   color_mapper(color_mapper_)
90 {
91 }
92
93 void motif_parser::ParsedMotifs::parse(const std::string &data)
94 {
95   const char *alphabet = Alphabet::nucleic_cstr;
96
97   // parse our string
98   spirit::parse_info<std::string::const_iterator> result;
99   result = spirit::parse(data.begin(), data.end(),
100      *(
101        ( 
102         (
103          (+spirit::chset<>(alphabet))[motif_parser::push_sequence(this)] >> 
104          +spirit::space_p
105         ) >>
106         !(
107           (
108             // names can either be letter followed by non-space characters
109             (spirit::alpha_p >> *spirit::graph_p)[motif_parser::push_name(this)]
110             |
111             // or a quoted string
112             (
113              spirit::ch_p('"') >> 
114                (+(~spirit::ch_p('"')))[motif_parser::push_name(this)] >>
115              spirit::ch_p('"')
116             )
117           ) >> +spirit::space_p
118         ) >>
119         spirit::real_p[motif_parser::push_channel(this)] >> +spirit::space_p >>
120         spirit::real_p[motif_parser::push_channel(this)] >> +spirit::space_p >>
121         spirit::real_p[motif_parser::push_channel(this)] >> +spirit::space_p >>
122         !(spirit::real_p[motif_parser::push_channel(this)] >> +spirit::space_p)
123        )[push_motif(this)]
124      ));
125   if (not result.full) {
126     std::stringstream msg;
127     msg << "Error at character " << result.length; 
128     // erase our potentially broken motif list
129     motifs.clear();
130     throw motif_load_error(msg.str());
131   }
132 }