]> git.tdb.fi Git - libs/gl.git/blob - source/glsl/parser.cpp
Record location information in all syntax nodes
[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(source, name);
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::create_node()
193 {
194         RefPtr<T> node = new T;
195         node->source = source_index;
196         node->line = tokenizer.get_location().line;
197         return node;
198 }
199
200 template<typename T>
201 RefPtr<T> Parser::parse_with_recovery(RefPtr<T> (Parser::*parse_func)())
202 {
203         tokenizer.clear_progress_mark();
204         try
205         {
206                 return (this->*parse_func)();
207         }
208         catch(const invalid_shader_source &exc)
209         {
210                 errors.push_back(exc.what());
211         }
212
213         if(tokenizer.get_last_token()!=";" || !tokenizer.get_progress_mark())
214         {
215                 unsigned scope_level = 0;
216                 while(1)
217                 {
218                         if(tokenizer.peek_token()=="}" && scope_level==0)
219                         {
220                                 if(!tokenizer.get_progress_mark())
221                                         tokenizer.parse_token();
222                                 break;
223                         }
224
225                         string token = tokenizer.parse_token();
226                         if(token=="}")
227                         {
228                                 --scope_level;
229                                 if(scope_level==0)
230                                         break;
231                         }
232                         else if(token=="{")
233                                 ++scope_level;
234                         else if(token==";" && scope_level==0)
235                                 break;
236                         else if(token.empty())
237                                 break;
238                 }
239         }
240
241         return RefPtr<T>();
242 }
243
244 RefPtr<Statement> Parser::parse_global_declaration()
245 {
246         string token = tokenizer.peek_token();
247         SetFlag disallow(allow_stage_change, false);
248
249         if(token=="import")
250                 return parse_import();
251         else if(token=="precision")
252                 return parse_precision();
253         else if(token=="layout")
254         {
255                 RefPtr<Layout> layout = parse_layout();
256                 token = tokenizer.peek_token();
257                 if(is_interface_qualifier(token) && tokenizer.peek_token(1)==";")
258                 {
259                         RefPtr<InterfaceLayout> iface_lo = create_node<InterfaceLayout>();
260                         iface_lo->layout.qualifiers = layout->qualifiers;
261                         iface_lo->interface = tokenizer.parse_token();
262                         tokenizer.expect(";");
263                         return iface_lo;
264                 }
265                 else
266                 {
267                         RefPtr<VariableDeclaration> var = parse_variable_declaration();
268                         var->layout = layout;
269                         return var;
270                 }
271         }
272         else if(token=="struct")
273                 return parse_struct_declaration();
274         else if(is_interface_qualifier(token))
275         {
276                 string next = tokenizer.peek_token(1);
277                 if(is_type(next) || is_qualifier(next))
278                         return parse_variable_declaration();
279                 else
280                         return parse_interface_block();
281         }
282         else if(is_qualifier(token))
283                 return parse_variable_declaration();
284         else if(is_type(token))
285         {
286                 if(tokenizer.peek_token(2)=="(")
287                         return parse_function_declaration();
288                 else
289                         return parse_variable_declaration();
290         }
291         else if(token.empty())
292                 return 0;
293         else
294                 throw parse_error(tokenizer.get_location(), token, "a global declaration");
295 }
296
297 RefPtr<Statement> Parser::parse_statement()
298 {
299         string token = tokenizer.peek_token();
300         if(token=="if")
301                 return parse_conditional();
302         else if(token=="for")
303                 return parse_for();
304         else if(token=="while")
305                 return parse_while();
306         else if(token=="passthrough")
307                 return parse_passthrough();
308         else if(token=="return")
309                 return parse_return();
310         else if(token=="break" || token=="continue" || token=="discard")
311         {
312                 RefPtr<Jump> jump = create_node<Jump>();
313                 jump->keyword = tokenizer.parse_token();
314                 tokenizer.expect(";");
315
316                 return jump;
317         }
318         else if(is_qualifier(token) || is_type(token))
319                 return parse_variable_declaration();
320         else if(token==";")
321         {
322                 tokenizer.parse_token();
323                 throw invalid_shader_source(tokenizer.get_location(), "Empty statement not allowed");
324         }
325         else if(!token.empty())
326         {
327                 RefPtr<ExpressionStatement> expr = create_node<ExpressionStatement>();
328                 expr->expression = parse_expression();
329                 tokenizer.expect(";");
330
331                 return expr;
332         }
333         else
334                 throw parse_error(tokenizer.get_location(), token, "a statement");
335 }
336
337 RefPtr<Import> Parser::parse_import()
338 {
339         if(cur_stage->type!=Stage::SHARED)
340                 throw invalid_shader_source(tokenizer.get_location(), "Imports are only allowed in the shared section");
341
342         tokenizer.expect("import");
343         RefPtr<Import> import = create_node<Import>();
344         import->module = expect_identifier();
345         tokenizer.expect(";");
346         return import;
347 }
348
349 RefPtr<Precision> Parser::parse_precision()
350 {
351         tokenizer.expect("precision");
352         RefPtr<Precision> precision = create_node<Precision>();
353
354         precision->precision = tokenizer.parse_token();
355         if(!is_precision_qualifier(precision->precision))
356                 throw parse_error(tokenizer.get_location(), precision->precision, "a precision qualifier");
357
358         precision->type = tokenizer.parse_token();
359         // Not entirely accurate; only float, int and sampler types are allowed
360         if(!is_builtin_type(precision->type))
361                 throw parse_error(tokenizer.get_location(), precision->type, "a builtin type");
362
363         tokenizer.expect(";");
364
365         return precision;
366 }
367
368 RefPtr<Layout> Parser::parse_layout()
369 {
370         tokenizer.expect("layout");
371         tokenizer.expect("(");
372         RefPtr<Layout> layout = create_node<Layout>();
373         while(1)
374         {
375                 string token = tokenizer.parse_token();
376                 if(token==")")
377                         throw parse_error(tokenizer.get_location(), token, "a layout qualifier name");
378
379                 layout->qualifiers.push_back(Layout::Qualifier());
380                 Layout::Qualifier &qual = layout->qualifiers.back();
381                 qual.name = token;
382
383                 if((qual.has_value = check("=")))
384                 {
385                         if(qual.name=="constant_id" && tokenizer.peek_token()=="auto")
386                         {
387                                 qual.value = -1;
388                                 tokenizer.parse_token();
389                         }
390                         else
391                                 qual.value = expect_integer();
392                 }
393
394                 if(tokenizer.peek_token()==")")
395                         break;
396
397                 tokenizer.expect(",");
398         }
399         tokenizer.expect(")");
400
401         return layout;
402 }
403
404 template<typename T>
405 void Parser::parse_block(Block &block, bool require_braces, RefPtr<T> (Parser::*parse_content)())
406 {
407         bool have_braces = (require_braces || tokenizer.peek_token()=="{");
408         if(have_braces)
409                 tokenizer.expect("{");
410
411         if(have_braces)
412         {
413                 while(tokenizer.peek_token()!="}")
414                         if(RefPtr<Statement> node = parse_with_recovery(parse_content))
415                                 block.body.push_back(node);
416         }
417         else
418                 block.body.push_back((this->*parse_content)());
419
420         block.use_braces = (require_braces || block.body.size()!=1);
421
422         if(have_braces)
423                 tokenizer.expect("}");
424 }
425
426 RefPtr<Expression> Parser::parse_expression(unsigned precedence)
427 {
428         RefPtr<Expression> left;
429         VariableReference *left_var = 0;
430         while(1)
431         {
432                 string token = tokenizer.peek_token();
433
434                 const Operator *oper = 0;
435                 for(const Operator *i=Operator::operators; (!oper && i->type); ++i)
436                         if(token==i->token && (!left || i->type!=Operator::PREFIX) && (left || i->type!=Operator::POSTFIX))
437                                 oper = i;
438
439                 if(token==";" || token==")" || token=="]" || token=="," || (oper && precedence && oper->precedence>=precedence))
440                 {
441                         if(left)
442                                 return left;
443                         else
444                                 throw parse_error(tokenizer.get_location(), token, "an expression");
445                 }
446                 else if(left)
447                 {
448                         if(token=="(")
449                         {
450                                 if(!left_var)
451                                         throw invalid_shader_source(tokenizer.get_location(), "Syntax error before '(': function name must be an identifier");
452                                 left = parse_function_call(*left_var);
453                         }
454                         else if(token==".")
455                         {
456                                 RefPtr<MemberAccess> memacc = create_node<MemberAccess>();
457                                 memacc->left = left;
458                                 memacc->oper = oper;
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 = create_node<UnaryExpression>();
466                                 unary->oper = oper;
467                                 tokenizer.parse_token();
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 = create_node<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 = create_node<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 = create_node<UnaryExpression>();
503                                 unary->oper = oper;
504                                 tokenizer.parse_token();
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 ?
517                 static_cast<RefPtr<BinaryExpression> >(create_node<Assignment>()) : create_node<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 = create_node<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 = create_node<StructDeclaration>();
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 = create_node<VariableDeclaration>();
564
565         string token = tokenizer.peek_token();
566         while(is_qualifier(token))
567         {
568                 tokenizer.parse_token();
569                 if(is_interface_qualifier(token))
570                         var->interface = token;
571                 else if(is_sampling_qualifier(token))
572                         var->sampling = token;
573                 else if(is_interpolation_qualifier(token))
574                         var->interpolation = token;
575                 else if(is_precision_qualifier(token))
576                         var->precision = token;
577                 else if(token=="const")
578                         var->constant = true;
579                 token = tokenizer.peek_token();
580         }
581
582         var->type = expect_type();
583         var->name = expect_identifier();
584
585         if(check("["))
586         {
587                 var->array = true;
588                 if(!check("]"))
589                 {
590                         var->array_size = parse_expression();
591                         tokenizer.expect("]");
592                 }
593         }
594
595         if(check("="))
596                 var->init_expression = parse_expression();
597
598         tokenizer.expect(";");
599         return var;
600 }
601
602 RefPtr<VariableDeclaration> Parser::parse_variable_declaration_with_layout()
603 {
604         RefPtr<Layout> layout;
605         if(tokenizer.peek_token()=="layout")
606                 layout = parse_layout();
607
608         RefPtr<VariableDeclaration> var = parse_variable_declaration();
609         var->layout = layout;
610
611         return var;
612 }
613
614 RefPtr<FunctionDeclaration> Parser::parse_function_declaration()
615 {
616         RefPtr<FunctionDeclaration> func = create_node<FunctionDeclaration>();
617
618         func->return_type = expect_type();
619         func->name = expect_identifier();
620         tokenizer.expect("(");
621         while(tokenizer.peek_token()!=")")
622         {
623                 if(!func->parameters.empty())
624                         tokenizer.expect(",");
625
626                 RefPtr<VariableDeclaration> var = create_node<VariableDeclaration>();
627                 string token = tokenizer.peek_token();
628                 if(token=="in" || token=="out" || token=="inout")
629                         var->interface = tokenizer.parse_token();
630                 var->type = expect_type();
631                 var->name = expect_identifier();
632                 func->parameters.push_back(var);
633         }
634         tokenizer.expect(")");
635
636         string token = tokenizer.peek_token();
637         if(token=="{")
638         {
639                 func->definition = func.get();
640                 parse_block(func->body, true, &Parser::parse_statement);
641         }
642         else if(token==";")
643                 tokenizer.parse_token();
644         else
645                 throw parse_error(tokenizer.get_location(), token, "'{' or ';'");
646
647         return func;
648 }
649
650 RefPtr<InterfaceBlock> Parser::parse_interface_block()
651 {
652         RefPtr<InterfaceBlock> iface = create_node<InterfaceBlock>();
653
654         iface->interface = tokenizer.parse_token();
655         if(!is_interface_qualifier(iface->interface))
656                 throw parse_error(tokenizer.get_location(), iface->interface, "an interface qualifier");
657
658         iface->name = expect_identifier();
659         parse_block(iface->members, true, &Parser::parse_variable_declaration_with_layout);
660         if(!check(";"))
661         {
662                 iface->instance_name = expect_identifier();
663                 if(check("["))
664                 {
665                         iface->array = true;
666                         tokenizer.expect("]");
667                 }
668                 tokenizer.expect(";");
669         }
670
671         return iface;
672 }
673
674 RefPtr<Conditional> Parser::parse_conditional()
675 {
676         tokenizer.expect("if");
677         RefPtr<Conditional> cond = create_node<Conditional>();
678         tokenizer.expect("(");
679         cond->condition = parse_expression();
680         tokenizer.expect(")");
681
682         parse_block(cond->body, false, &Parser::parse_statement);
683
684         string token = tokenizer.peek_token();
685         if(token=="else")
686         {
687                 tokenizer.parse_token();
688                 parse_block(cond->else_body, false, &Parser::parse_statement);
689         }
690
691         return cond;
692 }
693
694 RefPtr<Iteration> Parser::parse_for()
695 {
696         tokenizer.expect("for");
697         RefPtr<Iteration> loop = create_node<Iteration>();
698         tokenizer.expect("(");
699         string token = tokenizer.peek_token();
700         if(is_type(token))
701                 loop->init_statement = parse_statement();
702         else
703         {
704                 if(token!=";")
705                 {
706                         RefPtr<ExpressionStatement> expr = create_node<ExpressionStatement>();
707                         expr->expression = parse_expression();
708                         loop->init_statement = expr;
709                 }
710                 tokenizer.expect(";");
711         }
712         if(tokenizer.peek_token()!=";")
713                 loop->condition = parse_expression();
714         tokenizer.expect(";");
715         if(tokenizer.peek_token()!=")")
716                 loop->loop_expression = parse_expression();
717         tokenizer.expect(")");
718
719         parse_block(loop->body, false, &Parser::parse_statement);
720
721         return loop;
722 }
723
724 RefPtr<Iteration> Parser::parse_while()
725 {
726         tokenizer.expect("while");
727         RefPtr<Iteration> loop = create_node<Iteration>();
728         tokenizer.expect("(");
729         loop->condition = parse_expression();
730         tokenizer.expect(")");
731
732         parse_block(loop->body, false, &Parser::parse_statement);
733
734         return loop;
735 }
736
737 RefPtr<Passthrough> Parser::parse_passthrough()
738 {
739         tokenizer.expect("passthrough");
740         RefPtr<Passthrough> pass = create_node<Passthrough>();
741         if(cur_stage->type==Stage::GEOMETRY)
742         {
743                 tokenizer.expect("[");
744                 pass->subscript = parse_expression();
745                 tokenizer.expect("]");
746         }
747         tokenizer.expect(";");
748         return pass;
749 }
750
751 RefPtr<Return> Parser::parse_return()
752 {
753         tokenizer.expect("return");
754         RefPtr<Return> ret = create_node<Return>();
755         if(tokenizer.peek_token()!=";")
756                 ret->expression = parse_expression();
757         tokenizer.expect(";");
758         return ret;
759 }
760
761 } // namespace SL
762 } // namespace GL
763 } // namespace Msp