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