]> git.tdb.fi Git - libs/gl.git/blob - source/glsl/parser.cpp
Move the StageType enum inside the Stage struct
[libs/gl.git] / source / glsl / parser.cpp
1 #include <msp/strings/format.h>
2 #include <msp/strings/regex.h>
3 #include "glsl_error.h"
4 #include "parser.h"
5
6 #undef interface
7
8 using namespace std;
9
10 namespace Msp {
11 namespace GL {
12 namespace SL {
13
14 Parser::Parser():
15         preprocessor(tokenizer),
16         module(0)
17 {
18         tokenizer.signal_preprocess.connect(sigc::mem_fun(&preprocessor, &Preprocessor::preprocess));
19         preprocessor.signal_version.connect(sigc::mem_fun(this, &Parser::set_required_version));
20         preprocessor.signal_stage_change.connect(sigc::mem_fun(this, &Parser::stage_change));
21 }
22
23 Parser::~Parser()
24 {
25         delete module;
26 }
27
28 Module &Parser::parse(const string &s, const string &n, unsigned i)
29 {
30         source = s;
31         source_index = i;
32         parse_source(n);
33         return *module;
34 }
35
36 Module &Parser::parse(IO::Base &io, const string &n, unsigned i)
37 {
38         source = string();
39         source_index = i;
40         while(!io.eof())
41         {
42                 char buffer[4096];
43                 unsigned len = io.read(buffer, sizeof(buffer));
44                 source.append(buffer, len);
45         }
46         parse_source(n);
47         return *module;
48 }
49
50 void Parser::parse_source(const string &name)
51 {
52         while(1)
53         {
54                 string::size_type slashes = source.find("//////");
55                 if(slashes==string::npos)
56                         break;
57
58                 string::size_type newline = source.find('\n', slashes);
59                 string pragma = format("#pragma MSP stage(%s)", source.substr(slashes+6, newline-slashes-6));
60                 source.replace(slashes, newline-slashes, pragma);
61         }
62
63         delete module;
64         module = new Module;
65         cur_stage = &module->shared;
66         tokenizer.begin(name, source);
67         while(RefPtr<Statement> statement = parse_global_declaration())
68                 cur_stage->content.body.push_back(statement);
69 }
70
71 void Parser::set_required_version(const Version &ver)
72 {
73         cur_stage->required_version = ver;
74 }
75
76 void Parser::stage_change(Stage::Type stage)
77 {
78         if(!allow_stage_change)
79                 throw invalid_shader_source(tokenizer.get_location(), "Changing stage not allowed here");
80         else if(stage<=cur_stage->type)
81                 throw invalid_shader_source(tokenizer.get_location(), "Stage '%s' not allowed here", stage);
82
83         module->stages.push_back(stage);
84
85         if(cur_stage->type!=Stage::SHARED)
86                 module->stages.back().previous = cur_stage;
87         cur_stage = &module->stages.back();
88 }
89
90 string Parser::expect_type()
91 {
92         string token = tokenizer.parse_token();
93         if(!is_type(token))
94                 throw parse_error(tokenizer.get_location(), token, "a type");
95         return token;
96 }
97
98 string Parser::expect_identifier()
99 {
100         string token = tokenizer.parse_token();
101         if(!is_identifier(token))
102                 throw parse_error(tokenizer.get_location(), token, "an identifier");
103         return token;
104 }
105
106 bool Parser::check(const string &token)
107 {
108         bool result = (tokenizer.peek_token()==token);
109         if(result)
110                 tokenizer.parse_token();
111         return result;
112 }
113
114 bool Parser::is_interface_qualifier(const string &token)
115 {
116         return (token=="uniform" || token=="in" || token=="out");
117 }
118
119 bool Parser::is_sampling_qualifier(const string &token)
120 {
121         return (token=="centroid" || token=="sample");
122 }
123
124 bool Parser::is_interpolation_qualifier(const string &token)
125 {
126         return (token=="smooth" || token=="flat" || token=="noperspective");
127 }
128
129 bool Parser::is_precision_qualifier(const string &token)
130 {
131         return (token=="highp" || token=="mediump" || token=="lowp");
132 }
133
134 bool Parser::is_qualifier(const string &token)
135 {
136         return (token=="const" ||
137                 is_interface_qualifier(token) ||
138                 is_sampling_qualifier(token) ||
139                 is_interpolation_qualifier(token) ||
140                 is_precision_qualifier(token));
141 }
142
143 bool Parser::is_builtin_type(const string &token)
144 {
145         static Regex re("^(void|float|int|bool|[ib]?vec[234]|mat[234](x[234])?|sampler((1D|2D|Cube)(Array)?(Shadow)?|3D))$");
146         return re.match(token);
147 }
148
149 bool Parser::is_type(const string &token)
150 {
151         return is_builtin_type(token) || declared_types.count(token);
152 }
153
154 bool Parser::is_identifier(const string &token)
155 {
156         static Regex re("^[a-zA-Z_][a-zA-Z0-9_]*$");
157         return re.match(token);
158 }
159
160 RefPtr<Statement> Parser::parse_global_declaration()
161 {
162         allow_stage_change = true;
163         string token = tokenizer.peek_token();
164         allow_stage_change = false;
165
166         if(token=="import")
167                 return parse_import();
168         else if(token=="precision")
169                 return parse_precision();
170         else if(token=="layout")
171         {
172                 RefPtr<Layout> layout = parse_layout();
173                 token = tokenizer.peek_token();
174                 if(is_interface_qualifier(token) && tokenizer.peek_token(1)==";")
175                 {
176                         RefPtr<InterfaceLayout> iface_lo = new InterfaceLayout;
177                         iface_lo->source = source_index;
178                         iface_lo->line = tokenizer.get_location().line;
179                         iface_lo->layout.qualifiers = layout->qualifiers;
180                         iface_lo->interface = tokenizer.parse_token();
181                         tokenizer.expect(";");
182                         return iface_lo;
183                 }
184                 else
185                 {
186                         RefPtr<VariableDeclaration> var = parse_variable_declaration();
187                         var->layout = layout;
188                         return var;
189                 }
190         }
191         else if(token=="struct")
192                 return parse_struct_declaration();
193         else if(is_interface_qualifier(token))
194         {
195                 string next = tokenizer.peek_token(1);
196                 if(is_type(next) || is_qualifier(next))
197                         return parse_variable_declaration();
198                 else
199                         return parse_interface_block();
200         }
201         else if(is_qualifier(token))
202                 return parse_variable_declaration();
203         else if(is_type(token))
204         {
205                 if(tokenizer.peek_token(2)=="(")
206                         return parse_function_declaration();
207                 else
208                         return parse_variable_declaration();
209         }
210         else if(token.empty())
211                 return 0;
212         else
213                 throw parse_error(tokenizer.get_location(), token, "a global declaration");
214 }
215
216 RefPtr<Statement> Parser::parse_statement()
217 {
218         string token = tokenizer.peek_token();
219         if(token=="if")
220                 return parse_conditional();
221         else if(token=="for")
222                 return parse_for();
223         else if(token=="while")
224                 return parse_while();
225         else if(token=="passthrough")
226                 return parse_passthrough();
227         else if(token=="return")
228                 return parse_return();
229         else if(token=="break" || token=="continue" || token=="discard")
230         {
231                 RefPtr<Jump> jump = new Jump;
232                 jump->source = source_index;
233                 jump->line = tokenizer.get_location().line;
234                 jump->keyword = tokenizer.parse_token();
235                 tokenizer.expect(";");
236
237                 return jump;
238         }
239         else if(is_qualifier(token) || is_type(token))
240                 return parse_variable_declaration();
241         else if(!token.empty())
242         {
243                 RefPtr<ExpressionStatement> expr = new ExpressionStatement;
244                 expr->source = source_index;
245                 expr->line = tokenizer.get_location().line;
246                 expr->expression = parse_expression();
247                 tokenizer.expect(";");
248
249                 return expr;
250         }
251         else
252                 throw parse_error(tokenizer.get_location(), token, "a statement");
253 }
254
255 RefPtr<Import> Parser::parse_import()
256 {
257         if(cur_stage->type!=Stage::SHARED)
258                 throw invalid_shader_source(tokenizer.get_location(), "Imports are only allowed in the shared section");
259
260         tokenizer.expect("import");
261         RefPtr<Import> import = new Import;
262         import->source = source_index;
263         import->line = tokenizer.get_location().line;
264         import->module = expect_identifier();
265         tokenizer.expect(";");
266         return import;
267 }
268
269 RefPtr<Precision> Parser::parse_precision()
270 {
271         tokenizer.expect("precision");
272         RefPtr<Precision> precision = new Precision;
273         precision->source = source_index;
274         precision->line = tokenizer.get_location().line;
275
276         precision->precision = tokenizer.parse_token();
277         if(!is_precision_qualifier(precision->precision))
278                 throw parse_error(tokenizer.get_location(), precision->precision, "a precision qualifier");
279
280         precision->type = tokenizer.parse_token();
281         // Not entirely accurate; only float, int and sampler types are allowed
282         if(!is_builtin_type(precision->type))
283                 throw parse_error(tokenizer.get_location(), precision->type, "a builtin type");
284
285         tokenizer.expect(";");
286
287         return precision;
288 }
289
290 RefPtr<Layout> Parser::parse_layout()
291 {
292         tokenizer.expect("layout");
293         tokenizer.expect("(");
294         RefPtr<Layout> layout = new Layout;
295         while(1)
296         {
297                 string token = tokenizer.parse_token();
298                 if(token==")")
299                         throw parse_error(tokenizer.get_location(), token, "a layout qualifier name");
300
301                 layout->qualifiers.push_back(Layout::Qualifier());
302                 Layout::Qualifier &qual = layout->qualifiers.back();
303                 qual.identifier = token;
304
305                 if(check("="))
306                         qual.value = tokenizer.parse_token();
307
308                 if(tokenizer.peek_token()==")")
309                         break;
310
311                 tokenizer.expect(",");
312         }
313         tokenizer.expect(")");
314
315         return layout;
316 }
317
318 void Parser::parse_block(Block &block, bool require_braces)
319 {
320         bool have_braces = (require_braces || tokenizer.peek_token()=="{");
321         if(have_braces)
322                 tokenizer.expect("{");
323
324         if(have_braces)
325         {
326                 while(tokenizer.peek_token()!="}")
327                         block.body.push_back(parse_statement());
328         }
329         else
330                 block.body.push_back(parse_statement());
331
332         block.use_braces = (require_braces || block.body.size()!=1);
333
334         if(have_braces)
335                 tokenizer.expect("}");
336 }
337
338 RefPtr<Expression> Parser::parse_expression(unsigned precedence)
339 {
340         RefPtr<Expression> left;
341         VariableReference *left_var = 0;
342         while(1)
343         {
344                 string token = tokenizer.peek_token();
345
346                 const Operator *oper = 0;
347                 for(const Operator *i=Operator::operators; (!oper && i->type); ++i)
348                         if(token==i->token && (!left || i->type!=Operator::PREFIX) && (left || i->type!=Operator::POSTFIX))
349                                 oper = i;
350
351                 if(token==";" || token==")" || token=="]" || token=="," || (oper && precedence && oper->precedence>=precedence))
352                 {
353                         if(left)
354                                 return left;
355                         else
356                                 throw parse_error(tokenizer.get_location(), token, "an expression");
357                 }
358                 else if(left)
359                 {
360                         if(token=="(")
361                         {
362                                 if(!left_var)
363                                         throw invalid_shader_source(tokenizer.get_location(), "Syntax error before '(': function name must be an identifier");
364                                 left = parse_function_call(*left_var);
365                         }
366                         else if(token==".")
367                         {
368                                 RefPtr<MemberAccess> memacc = new MemberAccess;
369                                 memacc->left = left;
370                                 tokenizer.parse_token();
371                                 memacc->member = expect_identifier();
372                                 left = memacc;
373                         }
374                         else if(oper && oper->type==Operator::POSTFIX)
375                         {
376                                 RefPtr<UnaryExpression> unary = new UnaryExpression;
377                                 unary->oper = tokenizer.parse_token();
378                                 unary->prefix = false;
379                                 unary->expression = left;
380                                 left = unary;
381                         }
382                         else if(oper && oper->type==Operator::BINARY)
383                                 left = parse_binary(left, oper);
384                         else
385                                 throw parse_error(tokenizer.get_location(), token, "an operator");
386                         left_var = 0;
387                 }
388                 else
389                 {
390                         if(token=="(")
391                         {
392                                 tokenizer.parse_token();
393                                 RefPtr<ParenthesizedExpression> parexpr = new ParenthesizedExpression;
394                                 parexpr->expression = parse_expression();
395                                 tokenizer.expect(")");
396                                 left = parexpr;
397                         }
398                         else if(isdigit(token[0]) || token=="true" || token=="false")
399                         {
400                                 RefPtr<Literal> literal = new Literal;
401                                 literal->token = tokenizer.parse_token();
402                                 left = literal;
403                         }
404                         else if(is_identifier(token))
405                         {
406                                 RefPtr<VariableReference> var = new VariableReference;
407                                 var->name = expect_identifier();
408                                 left = var;
409                                 left_var = var.get();
410                         }
411                         else if(oper && oper->type==Operator::PREFIX)
412                         {
413                                 RefPtr<UnaryExpression> unary = new UnaryExpression;
414                                 unary->oper = tokenizer.parse_token();
415                                 unary->prefix = true;
416                                 unary->expression = parse_expression(oper->precedence);
417                                 left = unary;
418                         }
419                         else
420                                 throw parse_error(tokenizer.get_location(), token, "an expression");
421                 }
422         }
423 }
424
425 RefPtr<BinaryExpression> Parser::parse_binary(const RefPtr<Expression> &left, const Operator *oper)
426 {
427         RefPtr<BinaryExpression> binary = (oper->precedence==16 ? new Assignment : new BinaryExpression);
428         binary->left = left;
429         binary->oper = tokenizer.parse_token();
430         if(binary->oper=="[")
431         {
432                 binary->right = parse_expression();
433                 tokenizer.expect("]");
434                 binary->after = "]";
435         }
436         else
437                 binary->right = parse_expression(oper->precedence+(oper->assoc==Operator::RIGHT_TO_LEFT));
438         return binary;
439 }
440
441 RefPtr<FunctionCall> Parser::parse_function_call(const VariableReference &var)
442 {
443         RefPtr<FunctionCall> call = new FunctionCall;
444         call->name = var.name;
445         call->constructor = is_type(call->name);
446         tokenizer.expect("(");
447         while(tokenizer.peek_token()!=")")
448         {
449                 if(!call->arguments.empty())
450                         tokenizer.expect(",");
451                 call->arguments.push_back(parse_expression());
452         }
453         tokenizer.expect(")");
454         return call;
455 }
456
457 RefPtr<StructDeclaration> Parser::parse_struct_declaration()
458 {
459         tokenizer.expect("struct");
460         RefPtr<StructDeclaration> strct = new StructDeclaration;
461         strct->source = source_index;
462         strct->line = tokenizer.get_location().line;
463
464         strct->name = expect_identifier();
465         parse_block(strct->members, true);
466         tokenizer.expect(";");
467
468         declared_types.insert(strct->name);
469         return strct;
470 }
471
472 RefPtr<VariableDeclaration> Parser::parse_variable_declaration()
473 {
474         RefPtr<VariableDeclaration> var = new VariableDeclaration;
475         var->source = source_index;
476         var->line = tokenizer.get_location().line;
477
478         string token = tokenizer.peek_token();
479         while(is_qualifier(token))
480         {
481                 tokenizer.parse_token();
482                 if(is_interface_qualifier(token))
483                         var->interface = token;
484                 else if(is_sampling_qualifier(token))
485                         var->sampling = token;
486                 else if(is_interpolation_qualifier(token))
487                         var->interpolation = token;
488                 else if(is_precision_qualifier(token))
489                         var->precision = token;
490                 else if(token=="const")
491                         var->constant = true;
492                 token = tokenizer.peek_token();
493         }
494
495         var->type = expect_type();
496         var->name = expect_identifier();
497
498         if(check("["))
499         {
500                 var->array = true;
501                 if(!check("]"))
502                 {
503                         var->array_size = parse_expression();
504                         tokenizer.expect("]");
505                 }
506         }
507
508         if(check("="))
509                 var->init_expression = parse_expression();
510
511         tokenizer.expect(";");
512         return var;
513 }
514
515 RefPtr<FunctionDeclaration> Parser::parse_function_declaration()
516 {
517         RefPtr<FunctionDeclaration> func = new FunctionDeclaration;
518         func->source = source_index;
519         func->line = tokenizer.get_location().line;
520
521         func->return_type = expect_type();
522         func->name = expect_identifier();
523         tokenizer.expect("(");
524         while(tokenizer.peek_token()!=")")
525         {
526                 if(!func->parameters.empty())
527                         tokenizer.expect(",");
528
529                 RefPtr<VariableDeclaration> var = new VariableDeclaration;
530                 string token = tokenizer.peek_token();
531                 if(token=="in" || token=="out" || token=="inout")
532                         var->interface = tokenizer.parse_token();
533                 var->type = expect_type();
534                 var->name = expect_identifier();
535                 func->parameters.push_back(var);
536         }
537         tokenizer.expect(")");
538
539         string token = tokenizer.peek_token();
540         if(token=="{")
541         {
542                 func->definition = func.get();
543                 parse_block(func->body, true);
544         }
545         else if(token==";")
546                 tokenizer.parse_token();
547         else
548                 throw parse_error(tokenizer.get_location(), token, "'{' or ';'");
549
550         return func;
551 }
552
553 RefPtr<InterfaceBlock> Parser::parse_interface_block()
554 {
555         RefPtr<InterfaceBlock> iface = new InterfaceBlock;
556         iface->source = source_index;
557         iface->line = tokenizer.get_location().line;
558
559         iface->interface = tokenizer.parse_token();
560         if(!is_interface_qualifier(iface->interface))
561                 throw parse_error(tokenizer.get_location(), iface->interface, "an interface qualifier");
562
563         iface->name = expect_identifier();
564         parse_block(iface->members, true);
565         if(!check(";"))
566         {
567                 iface->instance_name = expect_identifier();
568                 if(check("["))
569                 {
570                         iface->array = true;
571                         tokenizer.expect("]");
572                 }
573                 tokenizer.expect(";");
574         }
575
576         return iface;
577 }
578
579 RefPtr<Conditional> Parser::parse_conditional()
580 {
581         tokenizer.expect("if");
582         RefPtr<Conditional> cond = new Conditional;
583         cond->source = source_index;
584         cond->line = tokenizer.get_location().line;
585         tokenizer.expect("(");
586         cond->condition = parse_expression();
587         tokenizer.expect(")");
588
589         parse_block(cond->body, false);
590
591         string token = tokenizer.peek_token();
592         if(token=="else")
593         {
594                 tokenizer.parse_token();
595                 parse_block(cond->else_body, false);
596         }
597
598         return cond;
599 }
600
601 RefPtr<Iteration> Parser::parse_for()
602 {
603         tokenizer.expect("for");
604         RefPtr<Iteration> loop = new Iteration;
605         loop->source = source_index;
606         loop->line = tokenizer.get_location().line;
607         tokenizer.expect("(");
608         string token = tokenizer.peek_token();
609         if(is_type(token))
610                 loop->init_statement = parse_statement();
611         else
612         {
613                 if(token!=";")
614                 {
615                         RefPtr<ExpressionStatement> expr = new ExpressionStatement;
616                         expr->expression = parse_expression();
617                         loop->init_statement = expr;
618                 }
619                 tokenizer.expect(";");
620         }
621         if(tokenizer.peek_token()!=";")
622                 loop->condition = parse_expression();
623         tokenizer.expect(";");
624         if(tokenizer.peek_token()!=")")
625                 loop->loop_expression = parse_expression();
626         tokenizer.expect(")");
627
628         parse_block(loop->body, false);
629
630         return loop;
631 }
632
633 RefPtr<Iteration> Parser::parse_while()
634 {
635         tokenizer.expect("while");
636         RefPtr<Iteration> loop = new Iteration;
637         loop->source = source_index;
638         loop->line = tokenizer.get_location().line;
639         tokenizer.expect("(");
640         loop->condition = parse_expression();
641         tokenizer.expect(")");
642
643         parse_block(loop->body, false);
644
645         return loop;
646 }
647
648 RefPtr<Passthrough> Parser::parse_passthrough()
649 {
650         tokenizer.expect("passthrough");
651         RefPtr<Passthrough> pass = new Passthrough;
652         pass->source = source_index;
653         pass->line = tokenizer.get_location().line;
654         if(cur_stage->type==Stage::GEOMETRY)
655         {
656                 tokenizer.expect("[");
657                 pass->subscript = parse_expression();
658                 tokenizer.expect("]");
659         }
660         tokenizer.expect(";");
661         return pass;
662 }
663
664 RefPtr<Return> Parser::parse_return()
665 {
666         tokenizer.expect("return");
667         RefPtr<Return> ret = new Return;
668         ret->source = source_index;
669         ret->line = tokenizer.get_location().line;
670         if(tokenizer.peek_token()!=";")
671                 ret->expression = parse_expression();
672         tokenizer.expect(";");
673         return ret;
674 }
675
676 } // namespace SL
677 } // namespace GL
678 } // namespace Msp