]> git.tdb.fi Git - libs/gl.git/blob - source/glsl/parser.cpp
Support specialization constants in the GLSL compiler
[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                 {
331                         if(qual.name=="constant_id" && tokenizer.peek_token()=="auto")
332                         {
333                                 qual.value = -1;
334                                 tokenizer.parse_token();
335                         }
336                         else
337                                 qual.value = expect_integer();
338                 }
339
340                 if(tokenizer.peek_token()==")")
341                         break;
342
343                 tokenizer.expect(",");
344         }
345         tokenizer.expect(")");
346
347         return layout;
348 }
349
350 template<typename T>
351 void Parser::parse_block(Block &block, bool require_braces, RefPtr<T> (Parser::*parse_content)())
352 {
353         bool have_braces = (require_braces || tokenizer.peek_token()=="{");
354         if(have_braces)
355                 tokenizer.expect("{");
356
357         if(have_braces)
358         {
359                 while(tokenizer.peek_token()!="}")
360                         block.body.push_back((this->*parse_content)());
361         }
362         else
363                 block.body.push_back((this->*parse_content)());
364
365         block.use_braces = (require_braces || block.body.size()!=1);
366
367         if(have_braces)
368                 tokenizer.expect("}");
369 }
370
371 RefPtr<Expression> Parser::parse_expression(unsigned precedence)
372 {
373         RefPtr<Expression> left;
374         VariableReference *left_var = 0;
375         while(1)
376         {
377                 string token = tokenizer.peek_token();
378
379                 const Operator *oper = 0;
380                 for(const Operator *i=Operator::operators; (!oper && i->type); ++i)
381                         if(token==i->token && (!left || i->type!=Operator::PREFIX) && (left || i->type!=Operator::POSTFIX))
382                                 oper = i;
383
384                 if(token==";" || token==")" || token=="]" || token=="," || (oper && precedence && oper->precedence>=precedence))
385                 {
386                         if(left)
387                                 return left;
388                         else
389                                 throw parse_error(tokenizer.get_location(), token, "an expression");
390                 }
391                 else if(left)
392                 {
393                         if(token=="(")
394                         {
395                                 if(!left_var)
396                                         throw invalid_shader_source(tokenizer.get_location(), "Syntax error before '(': function name must be an identifier");
397                                 left = parse_function_call(*left_var);
398                         }
399                         else if(token==".")
400                         {
401                                 RefPtr<MemberAccess> memacc = new MemberAccess;
402                                 memacc->left = left;
403                                 tokenizer.parse_token();
404                                 memacc->member = expect_identifier();
405                                 left = memacc;
406                         }
407                         else if(oper && oper->type==Operator::POSTFIX)
408                         {
409                                 RefPtr<UnaryExpression> unary = new UnaryExpression;
410                                 unary->oper = tokenizer.parse_token();
411                                 unary->prefix = false;
412                                 unary->expression = left;
413                                 left = unary;
414                         }
415                         else if(oper && oper->type==Operator::BINARY)
416                                 left = parse_binary(left, oper);
417                         else
418                                 throw parse_error(tokenizer.get_location(), token, "an operator");
419                         left_var = 0;
420                 }
421                 else
422                 {
423                         if(token=="(")
424                         {
425                                 tokenizer.parse_token();
426                                 RefPtr<ParenthesizedExpression> parexpr = new ParenthesizedExpression;
427                                 parexpr->expression = parse_expression();
428                                 tokenizer.expect(")");
429                                 left = parexpr;
430                         }
431                         else if(isdigit(token[0]) || token=="true" || token=="false")
432                         {
433                                 RefPtr<Literal> literal = new Literal;
434                                 literal->token = tokenizer.parse_token();
435                                 left = literal;
436                         }
437                         else if(is_identifier(token))
438                         {
439                                 RefPtr<VariableReference> var = new VariableReference;
440                                 var->name = expect_identifier();
441                                 left = var;
442                                 left_var = var.get();
443                         }
444                         else if(oper && oper->type==Operator::PREFIX)
445                         {
446                                 RefPtr<UnaryExpression> unary = new UnaryExpression;
447                                 unary->oper = tokenizer.parse_token();
448                                 unary->prefix = true;
449                                 unary->expression = parse_expression(oper->precedence);
450                                 left = unary;
451                         }
452                         else
453                                 throw parse_error(tokenizer.get_location(), token, "an expression");
454                 }
455         }
456 }
457
458 RefPtr<BinaryExpression> Parser::parse_binary(const RefPtr<Expression> &left, const Operator *oper)
459 {
460         RefPtr<BinaryExpression> binary = (oper->precedence==16 ? new Assignment : new BinaryExpression);
461         binary->left = left;
462         binary->oper = tokenizer.parse_token();
463         if(binary->oper=="[")
464         {
465                 binary->right = parse_expression();
466                 tokenizer.expect("]");
467                 binary->after = "]";
468         }
469         else
470                 binary->right = parse_expression(oper->precedence+(oper->assoc==Operator::RIGHT_TO_LEFT));
471         return binary;
472 }
473
474 RefPtr<FunctionCall> Parser::parse_function_call(const VariableReference &var)
475 {
476         RefPtr<FunctionCall> call = new FunctionCall;
477         call->name = var.name;
478         call->constructor = is_type(call->name);
479         tokenizer.expect("(");
480         while(tokenizer.peek_token()!=")")
481         {
482                 if(!call->arguments.empty())
483                         tokenizer.expect(",");
484                 call->arguments.push_back(parse_expression());
485         }
486         tokenizer.expect(")");
487         return call;
488 }
489
490 RefPtr<StructDeclaration> Parser::parse_struct_declaration()
491 {
492         tokenizer.expect("struct");
493         RefPtr<StructDeclaration> strct = new StructDeclaration;
494         strct->source = source_index;
495         strct->line = tokenizer.get_location().line;
496
497         strct->name = expect_identifier();
498         parse_block(strct->members, true, &Parser::parse_variable_declaration);
499         tokenizer.expect(";");
500
501         declared_types.insert(strct->name);
502         return strct;
503 }
504
505 RefPtr<VariableDeclaration> Parser::parse_variable_declaration()
506 {
507         RefPtr<VariableDeclaration> var = new VariableDeclaration;
508         var->source = source_index;
509         var->line = tokenizer.get_location().line;
510
511         string token = tokenizer.peek_token();
512         while(is_qualifier(token))
513         {
514                 tokenizer.parse_token();
515                 if(is_interface_qualifier(token))
516                         var->interface = token;
517                 else if(is_sampling_qualifier(token))
518                         var->sampling = token;
519                 else if(is_interpolation_qualifier(token))
520                         var->interpolation = token;
521                 else if(is_precision_qualifier(token))
522                         var->precision = token;
523                 else if(token=="const")
524                         var->constant = true;
525                 token = tokenizer.peek_token();
526         }
527
528         var->type = expect_type();
529         var->name = expect_identifier();
530
531         if(check("["))
532         {
533                 var->array = true;
534                 if(!check("]"))
535                 {
536                         var->array_size = parse_expression();
537                         tokenizer.expect("]");
538                 }
539         }
540
541         if(check("="))
542                 var->init_expression = parse_expression();
543
544         tokenizer.expect(";");
545         return var;
546 }
547
548 RefPtr<VariableDeclaration> Parser::parse_variable_declaration_with_layout()
549 {
550         RefPtr<Layout> layout;
551         if(tokenizer.peek_token()=="layout")
552                 layout = parse_layout();
553
554         RefPtr<VariableDeclaration> var = parse_variable_declaration();
555         var->layout = layout;
556
557         return var;
558 }
559
560 RefPtr<FunctionDeclaration> Parser::parse_function_declaration()
561 {
562         RefPtr<FunctionDeclaration> func = new FunctionDeclaration;
563         func->source = source_index;
564         func->line = tokenizer.get_location().line;
565
566         func->return_type = expect_type();
567         func->name = expect_identifier();
568         tokenizer.expect("(");
569         while(tokenizer.peek_token()!=")")
570         {
571                 if(!func->parameters.empty())
572                         tokenizer.expect(",");
573
574                 RefPtr<VariableDeclaration> var = new VariableDeclaration;
575                 string token = tokenizer.peek_token();
576                 if(token=="in" || token=="out" || token=="inout")
577                         var->interface = tokenizer.parse_token();
578                 var->type = expect_type();
579                 var->name = expect_identifier();
580                 func->parameters.push_back(var);
581         }
582         tokenizer.expect(")");
583
584         string token = tokenizer.peek_token();
585         if(token=="{")
586         {
587                 func->definition = func.get();
588                 parse_block(func->body, true, &Parser::parse_statement);
589         }
590         else if(token==";")
591                 tokenizer.parse_token();
592         else
593                 throw parse_error(tokenizer.get_location(), token, "'{' or ';'");
594
595         return func;
596 }
597
598 RefPtr<InterfaceBlock> Parser::parse_interface_block()
599 {
600         RefPtr<InterfaceBlock> iface = new InterfaceBlock;
601         iface->source = source_index;
602         iface->line = tokenizer.get_location().line;
603
604         iface->interface = tokenizer.parse_token();
605         if(!is_interface_qualifier(iface->interface))
606                 throw parse_error(tokenizer.get_location(), iface->interface, "an interface qualifier");
607
608         iface->name = expect_identifier();
609         parse_block(iface->members, true, &Parser::parse_variable_declaration_with_layout);
610         if(!check(";"))
611         {
612                 iface->instance_name = expect_identifier();
613                 if(check("["))
614                 {
615                         iface->array = true;
616                         tokenizer.expect("]");
617                 }
618                 tokenizer.expect(";");
619         }
620
621         return iface;
622 }
623
624 RefPtr<Conditional> Parser::parse_conditional()
625 {
626         tokenizer.expect("if");
627         RefPtr<Conditional> cond = new Conditional;
628         cond->source = source_index;
629         cond->line = tokenizer.get_location().line;
630         tokenizer.expect("(");
631         cond->condition = parse_expression();
632         tokenizer.expect(")");
633
634         parse_block(cond->body, false, &Parser::parse_statement);
635
636         string token = tokenizer.peek_token();
637         if(token=="else")
638         {
639                 tokenizer.parse_token();
640                 parse_block(cond->else_body, false, &Parser::parse_statement);
641         }
642
643         return cond;
644 }
645
646 RefPtr<Iteration> Parser::parse_for()
647 {
648         tokenizer.expect("for");
649         RefPtr<Iteration> loop = new Iteration;
650         loop->source = source_index;
651         loop->line = tokenizer.get_location().line;
652         tokenizer.expect("(");
653         string token = tokenizer.peek_token();
654         if(is_type(token))
655                 loop->init_statement = parse_statement();
656         else
657         {
658                 if(token!=";")
659                 {
660                         RefPtr<ExpressionStatement> expr = new ExpressionStatement;
661                         expr->expression = parse_expression();
662                         loop->init_statement = expr;
663                 }
664                 tokenizer.expect(";");
665         }
666         if(tokenizer.peek_token()!=";")
667                 loop->condition = parse_expression();
668         tokenizer.expect(";");
669         if(tokenizer.peek_token()!=")")
670                 loop->loop_expression = parse_expression();
671         tokenizer.expect(")");
672
673         parse_block(loop->body, false, &Parser::parse_statement);
674
675         return loop;
676 }
677
678 RefPtr<Iteration> Parser::parse_while()
679 {
680         tokenizer.expect("while");
681         RefPtr<Iteration> loop = new Iteration;
682         loop->source = source_index;
683         loop->line = tokenizer.get_location().line;
684         tokenizer.expect("(");
685         loop->condition = parse_expression();
686         tokenizer.expect(")");
687
688         parse_block(loop->body, false, &Parser::parse_statement);
689
690         return loop;
691 }
692
693 RefPtr<Passthrough> Parser::parse_passthrough()
694 {
695         tokenizer.expect("passthrough");
696         RefPtr<Passthrough> pass = new Passthrough;
697         pass->source = source_index;
698         pass->line = tokenizer.get_location().line;
699         if(cur_stage->type==Stage::GEOMETRY)
700         {
701                 tokenizer.expect("[");
702                 pass->subscript = parse_expression();
703                 tokenizer.expect("]");
704         }
705         tokenizer.expect(";");
706         return pass;
707 }
708
709 RefPtr<Return> Parser::parse_return()
710 {
711         tokenizer.expect("return");
712         RefPtr<Return> ret = new Return;
713         ret->source = source_index;
714         ret->line = tokenizer.get_location().line;
715         if(tokenizer.peek_token()!=";")
716                 ret->expression = parse_expression();
717         tokenizer.expect(";");
718         return ret;
719 }
720
721 } // namespace SL
722 } // namespace GL
723 } // namespace Msp