8725bea3e90c9c2eff8e3e85f21212220e26115c
[libs/datafile.git] / tool / compiler.cpp
1 #include <msp/datafile/parser.h>
2 #include <msp/fs/dir.h>
3 #include <msp/fs/utils.h>
4 #include <msp/strings/regex.h>
5 #include "compiler.h"
6
7 using namespace std;
8 using namespace Msp;
9
10 Compiler::Compiler(DataFile::Writer &w):
11         writer(w),
12         reset_src(false)
13 {
14         add("file",     &Compiler::file);
15         add("for_each", &Compiler::for_each);
16         add("write",    &Compiler::write);
17 }
18
19 void Compiler::file(const string &fn)
20 {
21         File fl(*this, FS::dirname(get_source())/fn);
22         load_sub_with(fl);
23 }
24
25 void Compiler::for_each(const vector<string> &patterns)
26 {
27         ForEach fe(*this, FS::dirname(get_source()), list<string>(patterns.begin(), patterns.end()));
28         load_sub_with(fe);
29 }
30
31 void Compiler::write(const DataFile::Statement &st)
32 {
33         if(reset_src)
34         {
35                 writer.write((DataFile::Statement("__src"), string()));
36                 reset_src = false;
37         }
38
39         for(list<DataFile::Statement>::const_iterator i = st.sub.begin(); i!=st.sub.end(); ++i)
40                 writer.write(*i);
41 }
42
43 bool Compiler::process_statement(const FS::Path &fn, DataFile::Statement &st)
44 {
45         if(st.keyword=="_content")
46                 return true;
47
48         for(vector<DataFile::Value>::iterator i = st.args.begin(); i!=st.args.end(); ++i)
49                 if(i->get_signature()==DataFile::StringType::signature)
50                 {
51                         string value = i->get<string>();
52                         if(value=="$filename")
53                                 *i = DataFile::Value(FS::basename(fn.str()));
54                         else if(value=="$content")
55                         {
56                                 IO::File in(fn.str());
57                                 string data;
58                                 while(!in.eof())
59                                 {
60                                         char buf[4096];
61                                         unsigned len = in.read(buf, sizeof(buf));
62                                         data.append(buf, len);
63                                 }
64                                 *i = DataFile::Value(data);
65                         }
66                 }
67
68         for(list<DataFile::Statement>::iterator i = st.sub.begin(); i!=st.sub.end();)
69         {
70                 if(process_statement(fn, *i))
71                 {
72                         IO::File in(fn.str());
73                         IO::Buffered buf(in);
74
75                         DataFile::Parser parser(in, fn.str());
76                         while(parser)
77                         {
78                                 DataFile::Statement ss = parser.parse();
79                                 if(ss.valid)
80                                         st.sub.insert(i, ss);
81                         }
82                         i = st.sub.erase(i);
83                 }
84                 else
85                         ++i;
86         }
87
88         return false;
89 }
90
91 void Compiler::process_file(const FS::Path &fn, const list<DataFile::Statement> &st)
92 {
93         writer.write((DataFile::Statement("__src"), FS::basename(fn.str())));
94         reset_src = true;
95
96         if(st.empty())
97                 process_file(fn);
98         else
99         {
100                 for(list<DataFile::Statement>::const_iterator i = st.begin(); i!=st.end(); ++i)
101                 {
102                         if(i->keyword=="_content")
103                                 process_file(fn);
104                         else
105                         {
106                                 DataFile::Statement s = *i;
107                                 process_statement(fn, s);
108                                 writer.write(s);
109                         }
110                 }
111         }
112 }
113
114 void Compiler::process_file(const FS::Path &fn)
115 {
116         IO::File in(fn.str());
117         IO::Buffered buf(in);
118
119         DataFile::Parser parser(in, fn.str());
120         while(parser)
121         {
122                 DataFile::Statement st = parser.parse();
123                 if(st.valid)
124                         writer.write(st);
125         }
126 }
127
128
129 File::File(Compiler &c, const FS::Path &fn):
130         compiler(c),
131         filename(fn)
132 {
133         add("write", &File::write);
134 }
135
136 void File::finish()
137 {
138         compiler.process_file(filename, write_st);
139 }
140
141 void File::write(const DataFile::Statement &st)
142 {
143         write_st.insert(write_st.end(), st.sub.begin(), st.sub.end());
144 }
145
146
147 ForEach::ForEach(Compiler &c, const FS::Path &b, const list<string> &p):
148         compiler(c),
149         base(b),
150         patterns(p)
151 {
152         add("exclude", &ForEach::exclude);
153         add("pattern", &ForEach::pattern);
154         add("write",   &ForEach::write);
155 }
156
157 void ForEach::finish()
158 {
159         list<string> files = FS::list_files(base);
160         for(list<string>::iterator i = files.begin(); i!=files.end(); ++i)
161         {
162                 bool match = false;
163                 for(list<string>::const_iterator j = patterns.begin(); (j!=patterns.end() && !match); ++j)
164                         match = Regex(*j).match(*i);
165                 for(list<string>::const_iterator j = excludes.begin(); (j!=excludes.end() && match); ++j)
166                         match = !Regex(*j).match(*i);
167                 if(match)
168                         compiler.process_file(base / *i, write_st);
169         }
170 }
171
172 void ForEach::exclude(const string &p)
173 {
174         excludes.push_back(p);
175 }
176
177 void ForEach::pattern(const string &p)
178 {
179         patterns.push_back(p);
180 }
181
182 void ForEach::write(const DataFile::Statement &st)
183 {
184         write_st.insert(write_st.end(), st.sub.begin(), st.sub.end());
185 }