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