]> git.tdb.fi Git - libs/gl.git/blob - source/glsl/parser.cpp
Refactor error reporting in SL::Parser
[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 "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::Operator Parser::operators[] =
16 {
17         { "[", 2, BINARY, LEFT_TO_RIGHT },
18         { "(", 2, BINARY, LEFT_TO_RIGHT },
19         { ".", 2, BINARY, LEFT_TO_RIGHT },
20         { "++", 2, POSTFIX, LEFT_TO_RIGHT },
21         { "--", 2, POSTFIX, LEFT_TO_RIGHT },
22         { "++", 3, PREFIX, RIGHT_TO_LEFT },
23         { "--", 3, PREFIX, RIGHT_TO_LEFT },
24         { "+", 3, PREFIX, RIGHT_TO_LEFT },
25         { "-", 3, PREFIX, RIGHT_TO_LEFT },
26         { "~", 3, PREFIX, RIGHT_TO_LEFT },
27         { "!", 3, PREFIX, RIGHT_TO_LEFT },
28         { "*", 4, BINARY, LEFT_TO_RIGHT },
29         { "/", 4, BINARY, LEFT_TO_RIGHT },
30         { "%", 4, BINARY, LEFT_TO_RIGHT },
31         { "+", 5, BINARY, LEFT_TO_RIGHT },
32         { "-", 5, BINARY, LEFT_TO_RIGHT },
33         { "<<", 6, BINARY, LEFT_TO_RIGHT },
34         { ">>", 6, BINARY, LEFT_TO_RIGHT },
35         { "<", 7, BINARY, LEFT_TO_RIGHT },
36         { ">", 7, BINARY, LEFT_TO_RIGHT },
37         { "<=", 7, BINARY, LEFT_TO_RIGHT },
38         { ">=", 7, BINARY, LEFT_TO_RIGHT },
39         { "==", 8, BINARY, LEFT_TO_RIGHT },
40         { "!=", 8, BINARY, LEFT_TO_RIGHT },
41         { "&", 9, BINARY, LEFT_TO_RIGHT },
42         { "^", 10, BINARY, LEFT_TO_RIGHT },
43         { "|", 11, BINARY, LEFT_TO_RIGHT },
44         { "&&", 12, BINARY, LEFT_TO_RIGHT },
45         { "^^", 13, BINARY, LEFT_TO_RIGHT },
46         { "||", 14, BINARY, LEFT_TO_RIGHT },
47         { "?", 15, BINARY, RIGHT_TO_LEFT },
48         { ":", 15, BINARY, RIGHT_TO_LEFT },
49         { "=", 16, BINARY, RIGHT_TO_LEFT },
50         { "+=", 16, BINARY, RIGHT_TO_LEFT },
51         { "-=", 16, BINARY, RIGHT_TO_LEFT },
52         { "*=", 16, BINARY, RIGHT_TO_LEFT },
53         { "/=", 16, BINARY, RIGHT_TO_LEFT },
54         { "%=", 16, BINARY, RIGHT_TO_LEFT },
55         { "<<=", 16, BINARY, RIGHT_TO_LEFT },
56         { ">>=", 16, BINARY, RIGHT_TO_LEFT },
57         { "&=", 16, BINARY, RIGHT_TO_LEFT },
58         { "^=", 16, BINARY, RIGHT_TO_LEFT },
59         { "|=", 16, BINARY, RIGHT_TO_LEFT },
60         { ",", 17, BINARY, LEFT_TO_RIGHT },
61         { { 0 }, 18, NO_OPERATOR, LEFT_TO_RIGHT }
62 };
63
64 Parser::Parser():
65         module(0)
66 { }
67
68 Parser::~Parser()
69 {
70         delete module;
71 }
72
73 Module &Parser::parse(const string &s, const string &n, unsigned i)
74 {
75         source = s;
76         location.name = n;
77         source_index = i;
78         parse_source();
79         return *module;
80 }
81
82 Module &Parser::parse(IO::Base &io, const string &n, unsigned i)
83 {
84         source = string();
85         location.name = n;
86         source_index = i;
87         while(!io.eof())
88         {
89                 char buffer[4096];
90                 unsigned len = io.read(buffer, sizeof(buffer));
91                 source.append(buffer, len);
92         }
93         parse_source();
94         return *module;
95 }
96
97 void Parser::parse_source()
98 {
99         while(1)
100         {
101                 string::size_type slashes = source.find("//////");
102                 if(slashes==string::npos)
103                         break;
104
105                 string::size_type newline = source.find('\n', slashes);
106                 string pragma = format("#pragma MSP stage(%s)", source.substr(slashes+6, newline-slashes-6));
107                 source.replace(slashes, newline-slashes, pragma);
108         }
109
110         delete module;
111         module = new Module;
112         cur_stage = &module->shared;
113         iter = source.begin();
114         source_end = source.end();
115         location.line = 1;
116         allow_preprocess = true;
117         while(RefPtr<Statement> statement = parse_global_declaration())
118                 cur_stage->content.body.push_back(statement);
119 }
120
121 const string &Parser::peek_token(unsigned index)
122 {
123         while(next_tokens.size()<=index)
124                 next_tokens.push_back(parse_token_());
125         return (last_token = next_tokens[index]);
126 }
127
128 const string &Parser::parse_token()
129 {
130         if(!next_tokens.empty())
131         {
132                 last_token = next_tokens.front();
133                 next_tokens.pop_front();
134                 return last_token;
135         }
136
137         return (last_token = parse_token_());
138 }
139
140 string Parser::parse_token_()
141 {
142         while(1)
143         {
144                 skip_comment_and_whitespace();
145                 if(iter==source_end)
146                         return string();
147                 else if(allow_preprocess && *iter=='#')
148                 {
149                         allow_preprocess = false;
150                         SetForScope<deque<string> > clear_tokens(next_tokens, deque<string>());
151                         preprocess();
152                 }
153                 else if(isalpha(*iter) || *iter=='_')
154                         return parse_identifier();
155                 else if(isdigit(*iter))
156                         return parse_number();
157                 else
158                         return parse_other();
159         }
160 }
161
162 string Parser::parse_identifier()
163 {
164         string ident;
165         while(iter!=source_end)
166         {
167                 if(isalnum(*iter) || *iter=='_')
168                         ident += *iter++;
169                 else
170                         break;
171         }
172
173         return ident;
174 }
175
176 string Parser::parse_number()
177 {
178         bool accept_sign = false;
179         string number;
180         while(iter!=source_end)
181         {
182                 if(isdigit(*iter) || *iter=='.')
183                         number += *iter++;
184                 else if(*iter=='e' || *iter=='E')
185                 {
186                         number += *iter++;
187                         accept_sign = true;
188                 }
189                 else if(accept_sign && (*iter=='+' || *iter=='-'))
190                         number += *iter++;
191                 else
192                         break;
193         }
194
195         return number;
196 }
197
198 string Parser::parse_other()
199 {
200         if(iter==source_end)
201                 return string();
202
203         string token(1, *iter++);
204         for(unsigned i=1; (i<3 && iter!=source_end); ++i)
205         {
206                 bool matched = false;
207                 for(const Operator *j=operators; (!matched && j->type); ++j)
208                 {
209                         matched = (j->token[i]==*iter);
210                         for(unsigned k=0; (matched && k<i && j->token[k]); ++k)
211                                 matched = (j->token[k]==token[k]);
212                 }
213
214                 if(!matched)
215                         break;
216
217                 token += *iter++;
218         }
219
220         return token;
221 }
222
223 void Parser::skip_comment_and_whitespace()
224 {
225         unsigned comment = 0;
226         while(iter!=source_end)
227         {
228                 if(comment==0)
229                 {
230                         if(*iter=='/')
231                                 comment = 1;
232                         else if(!isspace(*iter))
233                                 break;
234                 }
235                 else if(comment==1)
236                 {
237                         if(*iter=='/')
238                                 comment = 2;
239                         else if(*iter=='*')
240                                 comment = 3;
241                         else
242                         {
243                                 comment = 0;
244                                 --iter;
245                                 break;
246                         }
247                 }
248                 else if(comment==2)
249                 {
250                         if(*iter=='\n')
251                                 comment = 0;
252                 }
253                 else if(comment==3 && *iter=='*')
254                         comment = 4;
255                 else if(comment==4)
256                 {
257                         if(*iter=='/')
258                                 comment = 0;
259                         else if(*iter!='*')
260                                 comment = 3;
261                 }
262
263                 if(*iter=='\n')
264                 {
265                         ++location.line;
266                         allow_preprocess = (comment<3);
267                 }
268
269                 ++iter;
270         }
271 }
272
273 void Parser::expect(const string &token)
274 {
275         string parsed = parse_token();
276         if(parsed!=token)
277                 throw parse_error(location, parsed, format("'%s'", token));
278 }
279
280 string Parser::expect_type()
281 {
282         string token = parse_token();
283         if(!is_type(token))
284                 throw parse_error(location, token, "a type");
285         return token;
286 }
287
288 string Parser::expect_identifier()
289 {
290         string token = parse_token();
291         if(!is_identifier(token))
292                 throw parse_error(location, token, "an identifier");
293         return token;
294 }
295
296 bool Parser::check(const string &token)
297 {
298         bool result = (peek_token()==token);
299         if(result)
300                 parse_token();
301         return result;
302 }
303
304 bool Parser::is_interface_qualifier(const string &token)
305 {
306         return (token=="uniform" || token=="in" || token=="out");
307 }
308
309 bool Parser::is_sampling_qualifier(const string &token)
310 {
311         return (token=="centroid" || token=="sample");
312 }
313
314 bool Parser::is_interpolation_qualifier(const string &token)
315 {
316         return (token=="smooth" || token=="flat" || token=="noperspective");
317 }
318
319 bool Parser::is_precision_qualifier(const string &token)
320 {
321         return (token=="highp" || token=="mediump" || token=="lowp");
322 }
323
324 bool Parser::is_qualifier(const string &token)
325 {
326         return (token=="const" ||
327                 is_interface_qualifier(token) ||
328                 is_sampling_qualifier(token) ||
329                 is_interpolation_qualifier(token) ||
330                 is_precision_qualifier(token));
331 }
332
333 bool Parser::is_builtin_type(const string &token)
334 {
335         static Regex re("^(void|float|int|bool|[ib]?vec[234]|mat[234](x[234])?|sampler((1D|2D|Cube)(Array)?(Shadow)?|3D))$");
336         return re.match(token);
337 }
338
339 bool Parser::is_type(const string &token)
340 {
341         return is_builtin_type(token) || declared_types.count(token);
342 }
343
344 bool Parser::is_identifier(const string &token)
345 {
346         static Regex re("^[a-zA-Z_][a-zA-Z0-9_]*$");
347         return re.match(token);
348 }
349
350 void Parser::preprocess()
351 {
352         expect("#");
353
354         string::const_iterator line_end = iter;
355         for(; (line_end!=source_end && *line_end!='\n'); ++line_end) ;
356         SetForScope<string::const_iterator> stop_at_line_end(source_end, line_end);
357
358         string token = peek_token();
359         if(token=="pragma")
360                 preprocess_pragma();
361         else if(token=="version")
362                 preprocess_version();
363         else if(token=="define" || token=="undef" || token=="if" || token=="ifdef" || token=="ifndef" || token=="else" ||
364                 token=="elif" || token=="endif" || token=="error" || token=="extension" || token=="line")
365                 throw invalid_shader_source(location, "Unsupported preprocessor directive '%s'", token);
366         else if(!token.empty())
367                 throw parse_error(location, token, "a preprocessor directive");
368
369         iter = line_end;
370 }
371
372 void Parser::preprocess_version()
373 {
374         expect("version");
375         string token = parse_token();
376         unsigned version = lexical_cast<unsigned>(token);
377         cur_stage->required_version = Version(version/100, version%100);
378
379         token = parse_token();
380         if(!token.empty())
381                 throw parse_error(location, token, "end of line");
382 }
383
384 void Parser::preprocess_pragma()
385 {
386         expect("pragma");
387         string token = parse_token();
388         if(token=="MSP")
389                 preprocess_pragma_msp();
390 }
391
392 void Parser::preprocess_pragma_msp()
393 {
394         string token = peek_token();
395         if(token=="stage")
396                 preprocess_stage();
397         else
398                 throw invalid_shader_source(location, "Unrecognized MSP pragma '%s'", token);
399
400         token = parse_token();
401         if(!token.empty())
402                 throw parse_error(location, token, "end of line");
403 }
404
405 void Parser::preprocess_stage()
406 {
407         if(!allow_stage_change)
408                 throw invalid_shader_source(location, "Changing stage not allowed here");
409
410         expect("stage");
411         expect("(");
412         string token = expect_identifier();
413         StageType stage = SHARED;
414         if(token=="vertex")
415                 stage = VERTEX;
416         else if(token=="geometry")
417                 stage = GEOMETRY;
418         else if(token=="fragment")
419                 stage = FRAGMENT;
420         else
421                 throw parse_error(location, token, "stage identifier");
422         expect(")");
423
424         if(stage<=cur_stage->type)
425                 throw invalid_shader_source(location, "Stage '%s' not allowed here", token);
426
427         module->stages.push_back(stage);
428
429         if(cur_stage->type!=SHARED)
430                 module->stages.back().previous = cur_stage;
431         cur_stage = &module->stages.back();
432 }
433
434 RefPtr<Statement> Parser::parse_global_declaration()
435 {
436         allow_stage_change = true;
437         string token = peek_token();
438         allow_stage_change = false;
439
440         if(token=="import")
441                 return parse_import();
442         else if(token=="precision")
443                 return parse_precision();
444         else if(token=="layout")
445         {
446                 RefPtr<Layout> layout = parse_layout();
447                 token = peek_token();
448                 if(is_interface_qualifier(token) && peek_token(1)==";")
449                 {
450                         RefPtr<InterfaceLayout> iface_lo = new InterfaceLayout;
451                         iface_lo->source = source_index;
452                         iface_lo->line = location.line;
453                         iface_lo->layout.qualifiers = layout->qualifiers;
454                         iface_lo->interface = parse_token();
455                         expect(";");
456                         return iface_lo;
457                 }
458                 else
459                 {
460                         RefPtr<VariableDeclaration> var = parse_variable_declaration();
461                         var->layout = layout;
462                         return var;
463                 }
464         }
465         else if(token=="struct")
466                 return parse_struct_declaration();
467         else if(is_interface_qualifier(token))
468         {
469                 string next = peek_token(1);
470                 if(is_type(next) || is_qualifier(next))
471                         return parse_variable_declaration();
472                 else
473                         return parse_interface_block();
474         }
475         else if(is_qualifier(token))
476                 return parse_variable_declaration();
477         else if(is_type(token))
478         {
479                 if(peek_token(2)=="(")
480                         return parse_function_declaration();
481                 else
482                         return parse_variable_declaration();
483         }
484         else if(token.empty())
485                 return 0;
486         else
487                 throw parse_error(location, token, "a global declaration");
488 }
489
490 RefPtr<Statement> Parser::parse_statement()
491 {
492         string token = peek_token();
493         if(token=="if")
494                 return parse_conditional();
495         else if(token=="for")
496                 return parse_for();
497         else if(token=="while")
498                 return parse_while();
499         else if(token=="passthrough")
500                 return parse_passthrough();
501         else if(token=="return")
502                 return parse_return();
503         else if(token=="break" || token=="continue" || token=="discard")
504         {
505                 RefPtr<Jump> jump = new Jump;
506                 jump->source = source_index;
507                 jump->line = location.line;
508                 jump->keyword = parse_token();
509                 expect(";");
510
511                 return jump;
512         }
513         else if(is_qualifier(token) || is_type(token))
514                 return parse_variable_declaration();
515         else if(!token.empty())
516         {
517                 RefPtr<ExpressionStatement> expr = new ExpressionStatement;
518                 expr->source = source_index;
519                 expr->line = location.line;
520                 expr->expression = parse_expression();
521                 expect(";");
522
523                 return expr;
524         }
525         else
526                 throw parse_error(location, token, "a statement");
527 }
528
529 RefPtr<Import> Parser::parse_import()
530 {
531         if(cur_stage->type!=SHARED)
532                 throw invalid_shader_source(location, "Imports are only allowed in the shared section");
533
534         expect("import");
535         RefPtr<Import> import = new Import;
536         import->source = source_index;
537         import->line = location.line;
538         import->module = expect_identifier();
539         expect(";");
540         return import;
541 }
542
543 RefPtr<Precision> Parser::parse_precision()
544 {
545         expect("precision");
546         RefPtr<Precision> precision = new Precision;
547         precision->source = source_index;
548         precision->line = location.line;
549
550         precision->precision = parse_token();
551         if(!is_precision_qualifier(precision->precision))
552                 throw parse_error(location, precision->precision, "a precision qualifier");
553
554         precision->type = parse_token();
555         // Not entirely accurate; only float, int and sampler types are allowed
556         if(!is_builtin_type(precision->type))
557                 throw parse_error(location, precision->type, "a builtin type");
558
559         expect(";");
560
561         return precision;
562 }
563
564 RefPtr<Layout> Parser::parse_layout()
565 {
566         expect("layout");
567         expect("(");
568         RefPtr<Layout> layout = new Layout;
569         while(1)
570         {
571                 string token = parse_token();
572                 if(token==")")
573                         throw parse_error(location, token, "a layout qualifier name");
574
575                 layout->qualifiers.push_back(Layout::Qualifier());
576                 Layout::Qualifier &qual = layout->qualifiers.back();
577                 qual.identifier = token;
578
579                 if(check("="))
580                         qual.value = parse_token();
581
582                 if(peek_token()==")")
583                         break;
584
585                 expect(",");
586         }
587         expect(")");
588
589         return layout;
590 }
591
592 void Parser::parse_block(Block &block, bool require_braces)
593 {
594         bool have_braces = (require_braces || peek_token()=="{");
595         if(have_braces)
596                 expect("{");
597
598         if(have_braces)
599         {
600                 while(peek_token()!="}")
601                         block.body.push_back(parse_statement());
602         }
603         else
604                 block.body.push_back(parse_statement());
605
606         block.use_braces = (require_braces || block.body.size()!=1);
607
608         if(have_braces)
609                 expect("}");
610 }
611
612 RefPtr<Expression> Parser::parse_expression(unsigned precedence)
613 {
614         RefPtr<Expression> left;
615         VariableReference *left_var = 0;
616         while(1)
617         {
618                 string token = peek_token();
619
620                 const Operator *oper = 0;
621                 for(Operator *i=operators; (!oper && i->type); ++i)
622                         if(token==i->token && (!left || i->type!=PREFIX) && (left || i->type!=POSTFIX))
623                                 oper = i;
624
625                 if(token==";" || token==")" || token=="]" || token=="," || (oper && precedence && oper->precedence>=precedence))
626                 {
627                         if(left)
628                                 return left;
629                         else
630                                 throw parse_error(location, token, "an expression");
631                 }
632                 else if(left)
633                 {
634                         if(token=="(")
635                         {
636                                 if(!left_var)
637                                         throw invalid_shader_source(location, "Syntax error before '(': function name must be an identifier");
638                                 left = parse_function_call(*left_var);
639                         }
640                         else if(token==".")
641                         {
642                                 RefPtr<MemberAccess> memacc = new MemberAccess;
643                                 memacc->left = left;
644                                 parse_token();
645                                 memacc->member = expect_identifier();
646                                 left = memacc;
647                         }
648                         else if(oper && oper->type==POSTFIX)
649                         {
650                                 RefPtr<UnaryExpression> unary = new UnaryExpression;
651                                 unary->oper = parse_token();
652                                 unary->prefix = false;
653                                 unary->expression = left;
654                                 left = unary;
655                         }
656                         else if(oper && oper->type==BINARY)
657                                 left = parse_binary(left, oper);
658                         else
659                                 throw parse_error(location, token, "an operator");
660                         left_var = 0;
661                 }
662                 else
663                 {
664                         if(token=="(")
665                         {
666                                 parse_token();
667                                 RefPtr<ParenthesizedExpression> parexpr = new ParenthesizedExpression;
668                                 parexpr->expression = parse_expression();
669                                 expect(")");
670                                 left = parexpr;
671                         }
672                         else if(isdigit(token[0]) || token=="true" || token=="false")
673                         {
674                                 RefPtr<Literal> literal = new Literal;
675                                 literal->token = parse_token();
676                                 left = literal;
677                         }
678                         else if(is_identifier(token))
679                         {
680                                 RefPtr<VariableReference> var = new VariableReference;
681                                 var->name = expect_identifier();
682                                 left = var;
683                                 left_var = var.get();
684                         }
685                         else if(oper && oper->type==PREFIX)
686                         {
687                                 RefPtr<UnaryExpression> unary = new UnaryExpression;
688                                 unary->oper = parse_token();
689                                 unary->prefix = true;
690                                 unary->expression = parse_expression(oper->precedence);
691                                 left = unary;
692                         }
693                         else
694                                 throw parse_error(location, token, "an expression");
695                 }
696         }
697 }
698
699 RefPtr<BinaryExpression> Parser::parse_binary(const RefPtr<Expression> &left, const Operator *oper)
700 {
701         RefPtr<BinaryExpression> binary = (oper->precedence==16 ? new Assignment : new BinaryExpression);
702         binary->left = left;
703         binary->oper = parse_token();
704         if(binary->oper=="[")
705         {
706                 binary->right = parse_expression();
707                 expect("]");
708                 binary->after = "]";
709         }
710         else
711                 binary->right = parse_expression(oper->precedence+(oper->assoc==RIGHT_TO_LEFT));
712         return binary;
713 }
714
715 RefPtr<FunctionCall> Parser::parse_function_call(const VariableReference &var)
716 {
717         RefPtr<FunctionCall> call = new FunctionCall;
718         call->name = var.name;
719         call->constructor = is_type(call->name);
720         expect("(");
721         while(peek_token()!=")")
722         {
723                 if(!call->arguments.empty())
724                         expect(",");
725                 call->arguments.push_back(parse_expression());
726         }
727         expect(")");
728         return call;
729 }
730
731 RefPtr<StructDeclaration> Parser::parse_struct_declaration()
732 {
733         expect("struct");
734         RefPtr<StructDeclaration> strct = new StructDeclaration;
735         strct->source = source_index;
736         strct->line = location.line;
737
738         strct->name = expect_identifier();
739         parse_block(strct->members, true);
740         expect(";");
741
742         declared_types.insert(strct->name);
743         return strct;
744 }
745
746 RefPtr<VariableDeclaration> Parser::parse_variable_declaration()
747 {
748         RefPtr<VariableDeclaration> var = new VariableDeclaration;
749         var->source = source_index;
750         var->line = location.line;
751
752         string token = peek_token();
753         while(is_qualifier(token))
754         {
755                 parse_token();
756                 if(is_interface_qualifier(token))
757                         var->interface = token;
758                 else if(is_sampling_qualifier(token))
759                         var->sampling = token;
760                 else if(is_interpolation_qualifier(token))
761                         var->interpolation = token;
762                 else if(is_precision_qualifier(token))
763                         var->precision = token;
764                 else if(token=="const")
765                         var->constant = true;
766                 token = peek_token();
767         }
768
769         var->type = expect_type();
770         var->name = expect_identifier();
771
772         if(check("["))
773         {
774                 var->array = true;
775                 if(!check("]"))
776                 {
777                         var->array_size = parse_expression();
778                         expect("]");
779                 }
780         }
781
782         if(check("="))
783                 var->init_expression = parse_expression();
784
785         expect(";");
786         return var;
787 }
788
789 RefPtr<FunctionDeclaration> Parser::parse_function_declaration()
790 {
791         RefPtr<FunctionDeclaration> func = new FunctionDeclaration;
792         func->source = source_index;
793         func->line = location.line;
794
795         func->return_type = expect_type();
796         func->name = expect_identifier();
797         expect("(");
798         while(peek_token()!=")")
799         {
800                 if(!func->parameters.empty())
801                         expect(",");
802
803                 RefPtr<VariableDeclaration> var = new VariableDeclaration;
804                 string token = peek_token();
805                 if(token=="in" || token=="out" || token=="inout")
806                         var->interface = parse_token();
807                 var->type = expect_type();
808                 var->name = expect_identifier();
809                 func->parameters.push_back(var);
810         }
811         expect(")");
812
813         string token = peek_token();
814         if(token=="{")
815         {
816                 func->definition = func.get();
817                 parse_block(func->body, true);
818         }
819         else if(token==";")
820                 parse_token();
821         else
822                 throw parse_error(location, token, "'{' or ';'");
823
824         return func;
825 }
826
827 RefPtr<InterfaceBlock> Parser::parse_interface_block()
828 {
829         RefPtr<InterfaceBlock> iface = new InterfaceBlock;
830         iface->source = source_index;
831         iface->line = location.line;
832
833         iface->interface = parse_token();
834         if(!is_interface_qualifier(iface->interface))
835                 throw parse_error(location, iface->interface, "an interface qualifier");
836
837         iface->name = expect_identifier();
838         parse_block(iface->members, true);
839         if(!check(";"))
840         {
841                 iface->instance_name = expect_identifier();
842                 if(check("["))
843                 {
844                         iface->array = true;
845                         expect("]");
846                 }
847                 expect(";");
848         }
849
850         return iface;
851 }
852
853 RefPtr<Conditional> Parser::parse_conditional()
854 {
855         expect("if");
856         RefPtr<Conditional> cond = new Conditional;
857         cond->source = source_index;
858         cond->line = location.line;
859         expect("(");
860         cond->condition = parse_expression();
861         expect(")");
862
863         parse_block(cond->body, false);
864
865         string token = peek_token();
866         if(token=="else")
867         {
868                 parse_token();
869                 parse_block(cond->else_body, false);
870         }
871
872         return cond;
873 }
874
875 RefPtr<Iteration> Parser::parse_for()
876 {
877         expect("for");
878         RefPtr<Iteration> loop = new Iteration;
879         loop->source = source_index;
880         loop->line = location.line;
881         expect("(");
882         string token = peek_token();
883         if(is_type(token))
884                 loop->init_statement = parse_statement();
885         else
886         {
887                 if(token!=";")
888                 {
889                         RefPtr<ExpressionStatement> expr = new ExpressionStatement;
890                         expr->expression = parse_expression();
891                         loop->init_statement = expr;
892                 }
893                 expect(";");
894         }
895         if(peek_token()!=";")
896                 loop->condition = parse_expression();
897         expect(";");
898         if(peek_token()!=")")
899                 loop->loop_expression = parse_expression();
900         expect(")");
901
902         parse_block(loop->body, false);
903
904         return loop;
905 }
906
907 RefPtr<Iteration> Parser::parse_while()
908 {
909         expect("while");
910         RefPtr<Iteration> loop = new Iteration;
911         loop->source = source_index;
912         loop->line = location.line;
913         expect("(");
914         loop->condition = parse_expression();
915         expect(")");
916
917         parse_block(loop->body, false);
918
919         return loop;
920 }
921
922 RefPtr<Passthrough> Parser::parse_passthrough()
923 {
924         expect("passthrough");
925         RefPtr<Passthrough> pass = new Passthrough;
926         pass->source = source_index;
927         pass->line = location.line;
928         if(cur_stage->type==GEOMETRY)
929         {
930                 expect("[");
931                 pass->subscript = parse_expression();
932                 expect("]");
933         }
934         expect(";");
935         return pass;
936 }
937
938 RefPtr<Return> Parser::parse_return()
939 {
940         expect("return");
941         RefPtr<Return> ret = new Return;
942         ret->source = source_index;
943         ret->line = location.line;
944         if(peek_token()!=";")
945                 ret->expression = parse_expression();
946         expect(";");
947         return ret;
948 }
949
950 } // namespace SL
951 } // namespace GL
952 } // namespace Msp