]> git.tdb.fi Git - libs/gl.git/blob - source/programcompiler.cpp
Inject the global context to the syntax tree
[libs/gl.git] / source / programcompiler.cpp
1 #include <msp/strings/format.h>
2 #include <msp/strings/utils.h>
3 #include "error.h"
4 #include "program.h"
5 #include "programcompiler.h"
6 #include "shader.h"
7
8 using namespace std;
9
10 namespace Msp {
11 namespace GL {
12
13 using namespace ProgramSyntax;
14
15 ProgramCompiler::ProgramCompiler():
16         module(0)
17 { }
18
19 void ProgramCompiler::compile(const string &source)
20 {
21         module = &parser.parse(source);
22         process();
23 }
24
25 void ProgramCompiler::compile(IO::Base &io)
26 {
27         module = &parser.parse(io);
28         process();
29 }
30
31 void ProgramCompiler::add_shaders(Program &program)
32 {
33         if(!module)
34                 throw invalid_operation("ProgramCompiler::add_shaders");
35
36         string head = "#version 150\n";
37         if(module->vertex_context.present)
38                 program.attach_shader_owned(new VertexShader(head+format_context(module->vertex_context)));
39         if(module->geometry_context.present)
40                 program.attach_shader_owned(new GeometryShader(head+format_context(module->geometry_context)));
41         if(module->fragment_context.present)
42                 program.attach_shader_owned(new FragmentShader(head+format_context(module->fragment_context)));
43
44         program.bind_attribute(VERTEX4, "vertex");
45         program.bind_attribute(NORMAL3, "normal");
46         program.bind_attribute(COLOR4_FLOAT, "color");
47         program.bind_attribute(TEXCOORD4, "texcoord");
48 }
49
50 void ProgramCompiler::process()
51 {
52         if(module->vertex_context.present)
53                 process(module->vertex_context);
54         if(module->geometry_context.present)
55                 process(module->geometry_context);
56         if(module->fragment_context.present)
57                 process(module->fragment_context);
58 }
59
60 void ProgramCompiler::process(Context &context)
61 {
62         inject_block(context.content, module->global_context.content);
63 }
64
65 void ProgramCompiler::inject_block(Block &target, const Block &source)
66 {
67         list<NodePtr<Node> >::iterator insert_point = target.body.begin();
68         for(list<NodePtr<Node> >::const_iterator i=source.body.begin(); i!=source.body.end(); ++i)
69                 target.body.insert(insert_point, (*i)->clone());
70 }
71
72 string ProgramCompiler::format_context(Context &context)
73 {
74         Formatter formatter;
75         context.content.visit(formatter);
76         return formatter.formatted;
77 }
78
79
80 ProgramCompiler::Formatter::Formatter():
81         indent(0),
82         parameter_list(false),
83         else_if(false)
84 { }
85
86 void ProgramCompiler::Formatter::visit(Literal &literal)
87 {
88         formatted += literal.token;
89 }
90
91 void ProgramCompiler::Formatter::visit(ParenthesizedExpression &parexpr)
92 {
93         formatted += '(';
94         parexpr.expression->visit(*this);
95         formatted += ')';
96 }
97
98 void ProgramCompiler::Formatter::visit(VariableReference &var)
99 {
100         formatted += var.name;
101 }
102
103 void ProgramCompiler::Formatter::visit(MemberAccess &memacc)
104 {
105         memacc.left->visit(*this);
106         formatted += format(".%s", memacc.member);
107 }
108
109 void ProgramCompiler::Formatter::visit(UnaryExpression &unary)
110 {
111         if(unary.prefix)
112                 formatted += unary.oper;
113         unary.expression->visit(*this);
114         if(!unary.prefix)
115                 formatted += unary.oper;
116 }
117
118 void ProgramCompiler::Formatter::visit(BinaryExpression &binary)
119 {
120         binary.left->visit(*this);
121         if(binary.assignment)
122                 formatted += format(" %s ", binary.oper);
123         else
124                 formatted += binary.oper;
125         binary.right->visit(*this);
126         formatted += binary.after;
127 }
128
129 void ProgramCompiler::Formatter::visit(FunctionCall &call)
130 {
131         formatted += format("%s(", call.name);
132         for(vector<NodePtr<Expression> >::iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i)
133         {
134                 if(i!=call.arguments.begin())
135                         formatted += ", ";
136                 (*i)->visit(*this);
137         }
138         formatted += ')';
139 }
140
141 void ProgramCompiler::Formatter::visit(ExpressionStatement &expr)
142 {
143         expr.expression->visit(*this);
144         formatted += ';';
145 }
146
147 void ProgramCompiler::Formatter::visit(Block &block)
148 {
149         if(block.use_braces)
150         {
151                 if(else_if)
152                 {
153                         formatted += '\n';
154                         else_if = false;
155                 }
156                 formatted += format("%s{\n", string(indent*2, ' '));
157         }
158
159         bool change_indent = (!formatted.empty() && !else_if);
160         indent += change_indent;
161         string spaces(indent*2, ' ');
162         for(list<NodePtr<Node> >::iterator i=block.body.begin(); i!=block.body.end(); ++i)
163         {
164                 if(i!=block.body.begin())
165                         formatted += '\n';
166                 if(!else_if)
167                         formatted += spaces;
168                 (*i)->visit(*this);
169         }
170         indent -= change_indent;
171
172         if(block.use_braces)
173                 formatted += format("\n%s}", string(indent*2, ' '));
174 }
175
176 void ProgramCompiler::Formatter::visit(Layout &layout)
177 {
178         formatted += "layout(";
179         for(vector<Layout::Qualifier>::const_iterator i=layout.qualifiers.begin(); i!=layout.qualifiers.end(); ++i)
180         {
181                 if(i!=layout.qualifiers.begin())
182                         formatted += ", ";
183                 formatted += i->identifier;
184                 if(!i->value.empty())
185                         formatted += format("=%s", i->value);
186         }
187         formatted += format(") %s;", layout.interface);
188 }
189
190 void ProgramCompiler::Formatter::visit(StructDeclaration &strct)
191 {
192         formatted += format("struct %s\n", strct.name);
193         strct.members.visit(*this);
194         formatted += ';';
195 }
196
197 void ProgramCompiler::Formatter::visit(VariableDeclaration &var)
198 {
199         if(var.constant)
200                 formatted += "const ";
201         if(!var.sampling.empty())
202                 formatted += format("%s ", var.sampling);
203         if(!var.interface.empty())
204                 formatted += format("%s ", var.interface);
205         formatted += format("%s %s", var.type, var.name);
206         if(var.array)
207         {
208                 formatted += '[';
209                 if(var.array_size)
210                         var.array_size->visit(*this);
211                 formatted += ']';
212         }
213         if(var.init_expression)
214         {
215                 formatted += " = ";
216                 var.init_expression->visit(*this);
217         }
218         if(!parameter_list)
219                 formatted += ';';
220 }
221
222 void ProgramCompiler::Formatter::visit(InterfaceBlock &iface)
223 {
224         formatted += format("%s %s\n", iface.interface, iface.name);
225         iface.members.visit(*this);
226         formatted += ';';
227 }
228
229 void ProgramCompiler::Formatter::visit(FunctionDeclaration &func)
230 {
231         formatted += format("%s %s(", func.return_type, func.name);
232         parameter_list = true;
233         for(vector<NodePtr<VariableDeclaration> >::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i)
234         {
235                 if(i!=func.parameters.begin())
236                         formatted += ", ";
237                 (*i)->visit(*this);
238         }
239         parameter_list = false;
240         formatted += ')';
241         if(func.definition)
242         {
243                 formatted += '\n';
244                 func.body.visit(*this);
245         }
246         else
247                 formatted += ';';
248 }
249
250 void ProgramCompiler::Formatter::visit(Conditional &cond)
251 {
252         if(else_if)
253         {
254                 formatted += ' ';
255                 else_if = false;
256         }
257
258         formatted += "if(";
259         cond.condition->visit(*this);
260         formatted += ")\n";
261
262         cond.body.visit(*this);
263         if(!cond.else_body.body.empty())
264         {
265                 formatted += format("\n%selse", string(indent*2, ' '));
266                 else_if = true;
267                 cond.else_body.visit(*this);
268                 else_if = false;
269         }
270 }
271
272 void ProgramCompiler::Formatter::visit(Iteration &iter)
273 {
274         formatted += "for(";
275         iter.init_statement->visit(*this);
276         formatted += ' ';
277         iter.condition->visit(*this);
278         formatted += "; ";
279         iter.loop_expression->visit(*this);
280         formatted += ")\n";
281         iter.body.visit(*this);
282 }
283
284 void ProgramCompiler::Formatter::visit(Return &ret)
285 {
286         formatted += "return ";
287         ret.expression->visit(*this);
288         formatted += ';';
289 }
290
291 } // namespace GL
292 } // namespace Msp