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