]> git.tdb.fi Git - libs/gl.git/blob - source/glsl/parser.cpp
Fix a block management error in FunctionInliner
[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                                 memacc->oper = oper;
460                                 tokenizer.parse_token();
461                                 memacc->member = expect_identifier();
462                                 left = memacc;
463                         }
464                         else if(oper && oper->type==Operator::POSTFIX)
465                         {
466                                 RefPtr<UnaryExpression> unary = new UnaryExpression;
467                                 unary->oper = oper;
468                                 tokenizer.parse_token();
469                                 unary->expression = left;
470                                 left = unary;
471                         }
472                         else if(oper && oper->type==Operator::BINARY)
473                                 left = parse_binary(left, *oper);
474                         else
475                                 throw parse_error(tokenizer.get_location(), token, "an operator");
476                         left_var = 0;
477                 }
478                 else
479                 {
480                         if(token=="(")
481                         {
482                                 tokenizer.parse_token();
483                                 RefPtr<ParenthesizedExpression> parexpr = new ParenthesizedExpression;
484                                 parexpr->expression = parse_expression();
485                                 tokenizer.expect(")");
486                                 left = parexpr;
487                         }
488                         else if(isdigit(token[0]) || token=="true" || token=="false")
489                         {
490                                 RefPtr<Literal> literal = new Literal;
491                                 literal->token = tokenizer.parse_token();
492                                 left = literal;
493                         }
494                         else if(is_identifier(token))
495                         {
496                                 RefPtr<VariableReference> var = new VariableReference;
497                                 var->name = expect_identifier();
498                                 left = var;
499                                 left_var = var.get();
500                         }
501                         else if(oper && oper->type==Operator::PREFIX)
502                         {
503                                 RefPtr<UnaryExpression> unary = new UnaryExpression;
504                                 unary->oper = oper;
505                                 tokenizer.parse_token();
506                                 unary->expression = parse_expression(oper->precedence);
507                                 left = unary;
508                         }
509                         else
510                                 throw parse_error(tokenizer.get_location(), token, "an expression");
511                 }
512         }
513 }
514
515 RefPtr<BinaryExpression> Parser::parse_binary(const RefPtr<Expression> &left, const Operator &oper)
516 {
517         RefPtr<BinaryExpression> binary = (oper.precedence==16 ? new Assignment : new BinaryExpression);
518         binary->left = left;
519         binary->oper = &oper;
520         tokenizer.expect(oper.token);
521         if(oper.token[0]=='[')
522         {
523                 binary->right = parse_expression();
524                 tokenizer.expect("]");
525         }
526         else
527                 binary->right = parse_expression(oper.precedence+(oper.assoc==Operator::RIGHT_TO_LEFT));
528         return binary;
529 }
530
531 RefPtr<FunctionCall> Parser::parse_function_call(const VariableReference &var)
532 {
533         RefPtr<FunctionCall> call = new FunctionCall;
534         call->name = var.name;
535         call->constructor = is_type(call->name);
536         call->oper = &Operator::get_operator("(", Operator::POSTFIX);
537         tokenizer.expect("(");
538         while(tokenizer.peek_token()!=")")
539         {
540                 if(!call->arguments.empty())
541                         tokenizer.expect(",");
542                 call->arguments.push_back(parse_expression());
543         }
544         tokenizer.expect(")");
545         return call;
546 }
547
548 RefPtr<StructDeclaration> Parser::parse_struct_declaration()
549 {
550         tokenizer.expect("struct");
551         RefPtr<StructDeclaration> strct = new StructDeclaration;
552         strct->source = source_index;
553         strct->line = tokenizer.get_location().line;
554
555         strct->name = expect_identifier();
556         parse_block(strct->members, true, &Parser::parse_variable_declaration);
557         tokenizer.expect(";");
558
559         declared_types.insert(strct->name);
560         return strct;
561 }
562
563 RefPtr<VariableDeclaration> Parser::parse_variable_declaration()
564 {
565         RefPtr<VariableDeclaration> var = new VariableDeclaration;
566         var->source = source_index;
567         var->line = tokenizer.get_location().line;
568
569         string token = tokenizer.peek_token();
570         while(is_qualifier(token))
571         {
572                 tokenizer.parse_token();
573                 if(is_interface_qualifier(token))
574                         var->interface = token;
575                 else if(is_sampling_qualifier(token))
576                         var->sampling = token;
577                 else if(is_interpolation_qualifier(token))
578                         var->interpolation = token;
579                 else if(is_precision_qualifier(token))
580                         var->precision = token;
581                 else if(token=="const")
582                         var->constant = true;
583                 token = tokenizer.peek_token();
584         }
585
586         var->type = expect_type();
587         var->name = expect_identifier();
588
589         if(check("["))
590         {
591                 var->array = true;
592                 if(!check("]"))
593                 {
594                         var->array_size = parse_expression();
595                         tokenizer.expect("]");
596                 }
597         }
598
599         if(check("="))
600                 var->init_expression = parse_expression();
601
602         tokenizer.expect(";");
603         return var;
604 }
605
606 RefPtr<VariableDeclaration> Parser::parse_variable_declaration_with_layout()
607 {
608         RefPtr<Layout> layout;
609         if(tokenizer.peek_token()=="layout")
610                 layout = parse_layout();
611
612         RefPtr<VariableDeclaration> var = parse_variable_declaration();
613         var->layout = layout;
614
615         return var;
616 }
617
618 RefPtr<FunctionDeclaration> Parser::parse_function_declaration()
619 {
620         RefPtr<FunctionDeclaration> func = new FunctionDeclaration;
621         func->source = source_index;
622         func->line = tokenizer.get_location().line;
623
624         func->return_type = expect_type();
625         func->name = expect_identifier();
626         tokenizer.expect("(");
627         while(tokenizer.peek_token()!=")")
628         {
629                 if(!func->parameters.empty())
630                         tokenizer.expect(",");
631
632                 RefPtr<VariableDeclaration> var = new VariableDeclaration;
633                 string token = tokenizer.peek_token();
634                 if(token=="in" || token=="out" || token=="inout")
635                         var->interface = tokenizer.parse_token();
636                 var->type = expect_type();
637                 var->name = expect_identifier();
638                 func->parameters.push_back(var);
639         }
640         tokenizer.expect(")");
641
642         string token = tokenizer.peek_token();
643         if(token=="{")
644         {
645                 func->definition = func.get();
646                 parse_block(func->body, true, &Parser::parse_statement);
647         }
648         else if(token==";")
649                 tokenizer.parse_token();
650         else
651                 throw parse_error(tokenizer.get_location(), token, "'{' or ';'");
652
653         return func;
654 }
655
656 RefPtr<InterfaceBlock> Parser::parse_interface_block()
657 {
658         RefPtr<InterfaceBlock> iface = new InterfaceBlock;
659         iface->source = source_index;
660         iface->line = tokenizer.get_location().line;
661
662         iface->interface = tokenizer.parse_token();
663         if(!is_interface_qualifier(iface->interface))
664                 throw parse_error(tokenizer.get_location(), iface->interface, "an interface qualifier");
665
666         iface->name = expect_identifier();
667         parse_block(iface->members, true, &Parser::parse_variable_declaration_with_layout);
668         if(!check(";"))
669         {
670                 iface->instance_name = expect_identifier();
671                 if(check("["))
672                 {
673                         iface->array = true;
674                         tokenizer.expect("]");
675                 }
676                 tokenizer.expect(";");
677         }
678
679         return iface;
680 }
681
682 RefPtr<Conditional> Parser::parse_conditional()
683 {
684         tokenizer.expect("if");
685         RefPtr<Conditional> cond = new Conditional;
686         cond->source = source_index;
687         cond->line = tokenizer.get_location().line;
688         tokenizer.expect("(");
689         cond->condition = parse_expression();
690         tokenizer.expect(")");
691
692         parse_block(cond->body, false, &Parser::parse_statement);
693
694         string token = tokenizer.peek_token();
695         if(token=="else")
696         {
697                 tokenizer.parse_token();
698                 parse_block(cond->else_body, false, &Parser::parse_statement);
699         }
700
701         return cond;
702 }
703
704 RefPtr<Iteration> Parser::parse_for()
705 {
706         tokenizer.expect("for");
707         RefPtr<Iteration> loop = new Iteration;
708         loop->source = source_index;
709         loop->line = tokenizer.get_location().line;
710         tokenizer.expect("(");
711         string token = tokenizer.peek_token();
712         if(is_type(token))
713                 loop->init_statement = parse_statement();
714         else
715         {
716                 if(token!=";")
717                 {
718                         RefPtr<ExpressionStatement> expr = new ExpressionStatement;
719                         expr->expression = parse_expression();
720                         loop->init_statement = expr;
721                 }
722                 tokenizer.expect(";");
723         }
724         if(tokenizer.peek_token()!=";")
725                 loop->condition = parse_expression();
726         tokenizer.expect(";");
727         if(tokenizer.peek_token()!=")")
728                 loop->loop_expression = parse_expression();
729         tokenizer.expect(")");
730
731         parse_block(loop->body, false, &Parser::parse_statement);
732
733         return loop;
734 }
735
736 RefPtr<Iteration> Parser::parse_while()
737 {
738         tokenizer.expect("while");
739         RefPtr<Iteration> loop = new Iteration;
740         loop->source = source_index;
741         loop->line = tokenizer.get_location().line;
742         tokenizer.expect("(");
743         loop->condition = parse_expression();
744         tokenizer.expect(")");
745
746         parse_block(loop->body, false, &Parser::parse_statement);
747
748         return loop;
749 }
750
751 RefPtr<Passthrough> Parser::parse_passthrough()
752 {
753         tokenizer.expect("passthrough");
754         RefPtr<Passthrough> pass = new Passthrough;
755         pass->source = source_index;
756         pass->line = tokenizer.get_location().line;
757         if(cur_stage->type==Stage::GEOMETRY)
758         {
759                 tokenizer.expect("[");
760                 pass->subscript = parse_expression();
761                 tokenizer.expect("]");
762         }
763         tokenizer.expect(";");
764         return pass;
765 }
766
767 RefPtr<Return> Parser::parse_return()
768 {
769         tokenizer.expect("return");
770         RefPtr<Return> ret = new Return;
771         ret->source = source_index;
772         ret->line = tokenizer.get_location().line;
773         if(tokenizer.peek_token()!=";")
774                 ret->expression = parse_expression();
775         tokenizer.expect(";");
776         return ret;
777 }
778
779 } // namespace SL
780 } // namespace GL
781 } // namespace Msp