d05f15bbd55410ec1b2e76c94ce5114b6cb85a68
[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   std::string motif_subseq(seq.begin(), seq.end());
78   parsed->color_mapper->appendInstanceColor("motif", motif_subseq, c);
79   parsed->motifs.insert(seq);
80   
81   parsed->sequence.clear();
82   parsed->name.clear();
83   parsed->channels.clear();
84 }
85
86 motif_parser::ParsedMotifs::ParsedMotifs(
87   Mussa::motif_set& motifs_, 
88   boost::shared_ptr<AnnotationColors> color_mapper_) :
89   motifs(motifs_),
90   color_mapper(color_mapper_)
91 {
92 }
93
94 void motif_parser::ParsedMotifs::parse(const std::string &data)
95 {
96   const char *alphabet = Alphabet::nucleic_cstr;
97
98   // parse our string
99   spirit::parse_info<std::string::const_iterator> result;
100   result = spirit::parse(data.begin(), data.end(),
101      *(
102        ( 
103         (
104          (+spirit::chset<>(alphabet))[motif_parser::push_sequence(this)] >> 
105          +spirit::space_p
106         ) >>
107         !(
108           (
109             // names can either be letter followed by non-space characters
110             (spirit::alpha_p >> *spirit::graph_p)[motif_parser::push_name(this)]
111             |
112             // or a quoted string
113             (
114              spirit::ch_p('"') >> 
115                (+(~spirit::ch_p('"')))[motif_parser::push_name(this)] >>
116              spirit::ch_p('"')
117             )
118           ) >> +spirit::space_p
119         ) >>
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         !(spirit::real_p[motif_parser::push_channel(this)] >> +spirit::space_p)
124        )[push_motif(this)]
125      ));
126   if (not result.full) {
127     std::stringstream msg;
128     msg << "Error at character " << result.length; 
129     // erase our potentially broken motif list
130     motifs.clear();
131     throw motif_load_error(msg.str());
132   }
133 }