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