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