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