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