]> git.localhorst.tv Git - l2e.git/blob - src/loader/Parser.cpp
added hard support for path names in source files
[l2e.git] / src / loader / Parser.cpp
1 /*
2  * Parser.cpp
3  *
4  *  Created on: Aug 26, 2012
5  *      Author: holy
6  */
7
8 #include "Parser.h"
9
10 #include "utility.h"
11
12 #include <auto_ptr.h>
13 #include <fstream>
14
15 using std::auto_ptr;
16 using std::ifstream;
17 using std::string;
18 using std::vector;
19
20 namespace loader {
21
22 Parser::Parser(const string &file, ParsedSource &product)
23 : file(file)
24 , dirname(Dirname(file))
25 , in(this->file.c_str())
26 , tok(in)
27 , product(product) {
28         if (!in) {
29                 throw Error(file, 0, "unable to read file");
30         }
31 }
32
33 void Parser::Parse() {
34         while (tok.HasMore()) {
35                 ParseStatement();
36         }
37 }
38
39 void Parser::ParseStatement() {
40         Tokenizer::Token t(GetToken());
41         switch (t.type) {
42                 case Tokenizer::Token::KEYWORD_EXPORT:
43                         ParseExportDirective();
44                         break;
45                 case Tokenizer::Token::KEYWORD_INCLUDE:
46                         ParseIncludeDirective();
47                         break;
48                 case Tokenizer::Token::TYPE_NAME:
49                         tok.Putback(t);
50                         {
51                                 Declaration *decl(ProbeDefinition());
52                                 product.AddDeclaration(decl);
53                         }
54                         break;
55                 default:
56                         throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type));
57         }
58 }
59
60 Tokenizer::Token Parser::GetToken() try {
61         return tok.GetNext();
62 } catch (Tokenizer::LexerError &e) {
63         throw Error(file, e.Line(), e.what());
64 }
65
66 void Parser::ParseExportDirective() {
67         Tokenizer::Token t(GetToken());
68         if (t.type != Tokenizer::Token::IDENTIFIER) {
69                 tok.Putback(t);
70                 Declaration *decl(ProbeDefinition());
71                 product.ExportDeclaration(decl);
72         } else {
73                 product.ExportIdentifier(t.str);
74         }
75 }
76
77 void Parser::ParseIncludeDirective() {
78         Tokenizer::Token t(GetToken());
79         AssertTokenType(t.type, Tokenizer::Token::STRING);
80         Parser sub(CatPath(dirname, t.str), product);
81         sub.Parse();
82 }
83
84 Declaration *Parser::ProbeDefinition() {
85         string typeName(ParseTypeName());
86         string identifier(ParseIdentifier());
87
88         Tokenizer::Token t(GetToken());
89         tok.Putback(t);
90         if (BeginOfPropertyList(t)) {
91                 auto_ptr<PropertyList> propertyList(ParsePropertyList());
92                 auto_ptr<Definition> dfn(new Definition(typeName, identifier));
93                 dfn->SetValue(propertyList.release());
94                 product.AddDefinition(dfn.get());
95                 return dfn.release();
96         } else if (BeginningOfLiteral(t)) {
97                 auto_ptr<Literal> literal(ParseLiteral());
98                 auto_ptr<Definition> dfn(new Definition(typeName, identifier));
99                 dfn->SetValue(literal.release());
100                 product.AddDefinition(dfn.get());
101                 return dfn.release();
102         } else {
103                 return new Declaration(typeName, identifier);
104         }
105 }
106
107 bool Parser::BeginningOfLiteral(const Tokenizer::Token &t) const {
108         switch (t.type) {
109                 case Tokenizer::Token::CHEVRON_OPEN:
110                 case Tokenizer::Token::COLON:
111                 case Tokenizer::Token::BRACKET_OPEN:
112                 case Tokenizer::Token::PARENTHESIS_OPEN:
113                 case Tokenizer::Token::NUMBER:
114                 case Tokenizer::Token::STRING:
115                 case Tokenizer::Token::KEYWORD_FALSE:
116                 case Tokenizer::Token::KEYWORD_TRUE:
117                 case Tokenizer::Token::TYPE_NAME:
118                         return true;
119                 default:
120                         return false;
121         }
122 }
123
124 bool Parser::BeginOfPropertyList(const Tokenizer::Token &t) const {
125         return t.type == Tokenizer::Token::ANGLE_BRACKET_OPEN;
126 }
127
128 Definition *Parser::ParseDefinition() {
129         string typeName(ParseTypeName());
130         string identifier(ParseIdentifier());
131
132         Tokenizer::Token t(GetToken());
133         tok.Putback(t);
134         if (BeginOfPropertyList(t)) {
135                 PropertyList *propertyList(ParsePropertyList());
136                 Definition *dfn(new Definition(typeName, identifier));
137                 dfn->SetValue(propertyList);
138                 return dfn;
139         } else if (BeginningOfLiteral(t)) {
140                 Literal *literal(ParseLiteral());
141                 Definition *dfn(new Definition(typeName, identifier));
142                 dfn->SetValue(literal);
143                 return dfn;
144         } else {
145                 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected property-list or literal");
146         }
147 }
148
149 string Parser::ParseIdentifier() {
150         Tokenizer::Token t(GetToken());
151         AssertTokenType(t.type, Tokenizer::Token::IDENTIFIER);
152         return t.str;
153 }
154
155 string Parser::ParseTypeName() {
156         Tokenizer::Token t(GetToken());
157         AssertTokenType(t.type, Tokenizer::Token::TYPE_NAME);
158         return t.str;
159 }
160
161 PropertyList *Parser::ParsePropertyList() {
162         Tokenizer::Token t(GetToken());
163         AssertTokenType(t.type, Tokenizer::Token::ANGLE_BRACKET_OPEN);
164
165         auto_ptr<PropertyList> props(new PropertyList);
166
167         while (t.type != Tokenizer::Token::ANGLE_BRACKET_CLOSE) {
168                 Tokenizer::Token name(GetToken());
169                 AssertTokenType(name.type, Tokenizer::Token::IDENTIFIER);
170
171                 t = GetToken();
172                 AssertTokenType(t.type, Tokenizer::Token::COLON);
173
174                 Value *value(ParseValue());
175                 props->SetProperty(name.str, value);
176
177                 t = GetToken();
178                 if (t.type != Tokenizer::Token::ANGLE_BRACKET_CLOSE && t.type != Tokenizer::Token::COMMA) {
179                         throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or }");
180                 }
181         }
182
183         return props.release();
184 }
185
186 Value *Parser::ParseValue() {
187         Tokenizer::Token t(GetToken());
188         if (t.type == Tokenizer::Token::IDENTIFIER) {
189                 return new Value(t.str);
190         } else if (BeginningOfLiteral(t)) {
191                 tok.Putback(t);
192                 Literal *literal(ParseLiteral());
193                 return new Value(literal);
194         } else {
195                 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected literal or identifier");
196         }
197 }
198
199 Literal *Parser::ParseLiteral() {
200         Tokenizer::Token t(GetToken());
201         if (t.type == Tokenizer::Token::TYPE_NAME) {
202                 PropertyList *props(ParsePropertyList());
203                 return new Literal(t.str, props);
204         } else if (BeginningOfLiteral(t)) {
205                 switch (t.type) {
206                         case Tokenizer::Token::CHEVRON_OPEN:
207                                 tok.Putback(t);
208                                 return ParseVector();
209                         case Tokenizer::Token::COLON:
210                                 t = GetToken();
211                                 AssertTokenType(t.type, Tokenizer::Token::STRING);
212                                 return new Literal(dirname, t.str);
213                         case Tokenizer::Token::BRACKET_OPEN:
214                                 tok.Putback(t);
215                                 return ParseArray();
216                         case Tokenizer::Token::PARENTHESIS_OPEN:
217                                 tok.Putback(t);
218                                 return ParseColor();
219                         case Tokenizer::Token::NUMBER:
220                                 return new Literal(t.number);
221                         case Tokenizer::Token::STRING:
222                                 return new Literal(t.str);
223                         case Tokenizer::Token::KEYWORD_FALSE:
224                                 return new Literal(false);
225                         case Tokenizer::Token::KEYWORD_TRUE:
226                                 return new Literal(true);
227                         default:
228                                 throw std::logic_error("literal switch reached impossible default branch oO");
229                 }
230         } else {
231                 throw new Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected type-name or primitive");
232         }
233 }
234
235 Literal *Parser::ParseArray() {
236         Tokenizer::Token t(GetToken());
237         AssertTokenType(t.type, Tokenizer::Token::BRACKET_OPEN);
238
239         Tokenizer::Token probe(GetToken());
240         tok.Putback(probe);
241
242         if (probe.type == Tokenizer::Token::ANGLE_BRACKET_OPEN) {
243                 vector<PropertyList *> values;
244                 while (t.type != Tokenizer::Token::BRACKET_CLOSE) {
245                         PropertyList *value(ParsePropertyList());
246                         values.push_back(value);
247
248                         t = GetToken();
249                         if (t.type != Tokenizer::Token::BRACKET_CLOSE && t.type != Tokenizer::Token::COMMA) {
250                                 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or ]");
251                         }
252                 }
253                 return new Literal(values);
254         } else {
255                 vector<Value *> values;
256                 while (t.type != Tokenizer::Token::BRACKET_CLOSE) {
257                         Value *value(ParseValue());
258                         values.push_back(value);
259
260                         t = GetToken();
261                         if (t.type != Tokenizer::Token::BRACKET_CLOSE && t.type != Tokenizer::Token::COMMA) {
262                                 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or ]");
263                         }
264                 }
265                 return new Literal(values);
266         }
267 }
268
269 Literal *Parser::ParseColor() {
270         string msg("error parsing color");
271         Tokenizer::Token t(GetToken());
272         AssertTokenType(t.type, Tokenizer::Token::PARENTHESIS_OPEN, msg);
273
274         Tokenizer::Token red(GetToken());
275         AssertTokenType(red.type, Tokenizer::Token::NUMBER, "error parsing red component of color");
276
277         t = GetToken();
278         AssertTokenType(t.type, Tokenizer::Token::COMMA, msg);
279
280         Tokenizer::Token green(GetToken());
281         AssertTokenType(green.type, Tokenizer::Token::NUMBER, "error parsing green component of color");
282
283         t = GetToken();
284         AssertTokenType(t.type, Tokenizer::Token::COMMA, msg);
285
286         Tokenizer::Token blue(GetToken());
287         AssertTokenType(blue.type, Tokenizer::Token::NUMBER, "error parsing blue component of color");
288
289         t = GetToken();
290         if (t.type == Tokenizer::Token::BRACKET_CLOSE) {
291                 return new Literal(red.number, green.number, blue.number);
292         } else if (t.type != Tokenizer::Token::COMMA) {
293                 Tokenizer::Token alpha(GetToken());
294                 AssertTokenType(alpha.type, Tokenizer::Token::NUMBER, "error parsing alpha component of color");
295
296                 t = GetToken();
297                 AssertTokenType(t.type, Tokenizer::Token::PARENTHESIS_CLOSE, msg);
298
299                 return new Literal(red.number, green.number, blue.number, alpha.number);
300         } else {
301                 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or ]");
302         }
303 }
304
305 Literal *Parser::ParseVector() {
306         std::string msg("error parsing vector");
307         Tokenizer::Token t(GetToken());
308         AssertTokenType(t.type, Tokenizer::Token::CHEVRON_OPEN, msg);
309
310         Tokenizer::Token x(GetToken());
311         AssertTokenType(x.type, Tokenizer::Token::NUMBER, "error parsing x component of vector");
312
313         t = GetToken();
314         AssertTokenType(t.type, Tokenizer::Token::COMMA, msg);
315
316         Tokenizer::Token y(GetToken());
317         AssertTokenType(y.type, Tokenizer::Token::NUMBER, "error parsing y component of vector");
318
319         t = GetToken();
320         AssertTokenType(t.type, Tokenizer::Token::CHEVRON_CLOSE, msg);
321
322         return new Literal(x.number, y.number);
323 }
324
325 void Parser::AssertTokenType(Tokenizer::Token::Type actual, Tokenizer::Token::Type expected) {
326         if (expected != actual) {
327                 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(actual) + ", expected " + TokenTypeToString(expected));
328         }
329 }
330
331 void Parser::AssertTokenType(Tokenizer::Token::Type actual, Tokenizer::Token::Type expected, const string &msg) {
332         if (expected != actual) {
333                 throw Error(file, tok.Line(), msg + ": unexpected token " + TokenTypeToString(actual) + ", expected " + TokenTypeToString(expected));
334         }
335 }
336
337 }