]> git.localhorst.tv Git - l2e.git/blob - src/loader/Parser.cpp
resolve inclusion path name in Parser
[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::BRACKET_OPEN:
111                 case Tokenizer::Token::PARENTHESIS_OPEN:
112                 case Tokenizer::Token::NUMBER:
113                 case Tokenizer::Token::STRING:
114                 case Tokenizer::Token::KEYWORD_FALSE:
115                 case Tokenizer::Token::KEYWORD_TRUE:
116                 case Tokenizer::Token::TYPE_NAME:
117                         return true;
118                 default:
119                         return false;
120         }
121 }
122
123 bool Parser::BeginOfPropertyList(const Tokenizer::Token &t) const {
124         return t.type == Tokenizer::Token::ANGLE_BRACKET_OPEN;
125 }
126
127 Definition *Parser::ParseDefinition() {
128         string typeName(ParseTypeName());
129         string identifier(ParseIdentifier());
130
131         Tokenizer::Token t(GetToken());
132         tok.Putback(t);
133         if (BeginOfPropertyList(t)) {
134                 PropertyList *propertyList(ParsePropertyList());
135                 Definition *dfn(new Definition(typeName, identifier));
136                 dfn->SetValue(propertyList);
137                 return dfn;
138         } else if (BeginningOfLiteral(t)) {
139                 Literal *literal(ParseLiteral());
140                 Definition *dfn(new Definition(typeName, identifier));
141                 dfn->SetValue(literal);
142                 return dfn;
143         } else {
144                 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected property-list or literal");
145         }
146 }
147
148 string Parser::ParseIdentifier() {
149         Tokenizer::Token t(GetToken());
150         AssertTokenType(t.type, Tokenizer::Token::IDENTIFIER);
151         return t.str;
152 }
153
154 string Parser::ParseTypeName() {
155         Tokenizer::Token t(GetToken());
156         AssertTokenType(t.type, Tokenizer::Token::TYPE_NAME);
157         return t.str;
158 }
159
160 PropertyList *Parser::ParsePropertyList() {
161         Tokenizer::Token t(GetToken());
162         AssertTokenType(t.type, Tokenizer::Token::ANGLE_BRACKET_OPEN);
163
164         auto_ptr<PropertyList> props(new PropertyList);
165
166         while (t.type != Tokenizer::Token::ANGLE_BRACKET_CLOSE) {
167                 Tokenizer::Token name(GetToken());
168                 AssertTokenType(name.type, Tokenizer::Token::IDENTIFIER);
169
170                 t = GetToken();
171                 AssertTokenType(t.type, Tokenizer::Token::COLON);
172
173                 Value *value(ParseValue());
174                 props->SetProperty(name.str, value);
175
176                 t = GetToken();
177                 if (t.type != Tokenizer::Token::ANGLE_BRACKET_CLOSE && t.type != Tokenizer::Token::COMMA) {
178                         throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or }");
179                 }
180         }
181
182         return props.release();
183 }
184
185 Value *Parser::ParseValue() {
186         Tokenizer::Token t(GetToken());
187         if (t.type == Tokenizer::Token::IDENTIFIER) {
188                 return new Value(t.str);
189         } else if (BeginningOfLiteral(t)) {
190                 tok.Putback(t);
191                 Literal *literal(ParseLiteral());
192                 return new Value(literal);
193         } else {
194                 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected literal or identifier");
195         }
196 }
197
198 Literal *Parser::ParseLiteral() {
199         Tokenizer::Token t(GetToken());
200         if (t.type == Tokenizer::Token::TYPE_NAME) {
201                 PropertyList *props(ParsePropertyList());
202                 return new Literal(t.str, props);
203         } else if (BeginningOfLiteral(t)) {
204                 switch (t.type) {
205                         case Tokenizer::Token::CHEVRON_OPEN:
206                                 tok.Putback(t);
207                                 return ParseVector();
208                         case Tokenizer::Token::BRACKET_OPEN:
209                                 tok.Putback(t);
210                                 return ParseArray();
211                         case Tokenizer::Token::PARENTHESIS_OPEN:
212                                 tok.Putback(t);
213                                 return ParseColor();
214                         case Tokenizer::Token::NUMBER:
215                                 return new Literal(t.number);
216                         case Tokenizer::Token::STRING:
217                                 return new Literal(t.str);
218                         case Tokenizer::Token::KEYWORD_FALSE:
219                                 return new Literal(false);
220                         case Tokenizer::Token::KEYWORD_TRUE:
221                                 return new Literal(true);
222                         default:
223                                 throw std::logic_error("literal switch reached impossible default branch oO");
224                 }
225         } else {
226                 throw new Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected type-name or primitive");
227         }
228 }
229
230 Literal *Parser::ParseArray() {
231         Tokenizer::Token t(GetToken());
232         AssertTokenType(t.type, Tokenizer::Token::BRACKET_OPEN);
233
234         Tokenizer::Token probe(GetToken());
235         tok.Putback(probe);
236
237         if (probe.type == Tokenizer::Token::ANGLE_BRACKET_OPEN) {
238                 vector<PropertyList *> values;
239                 while (t.type != Tokenizer::Token::BRACKET_CLOSE) {
240                         PropertyList *value(ParsePropertyList());
241                         values.push_back(value);
242
243                         t = GetToken();
244                         if (t.type != Tokenizer::Token::BRACKET_CLOSE && t.type != Tokenizer::Token::COMMA) {
245                                 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or ]");
246                         }
247                 }
248                 return new Literal(values);
249         } else {
250                 vector<Value *> values;
251                 while (t.type != Tokenizer::Token::BRACKET_CLOSE) {
252                         Value *value(ParseValue());
253                         values.push_back(value);
254
255                         t = GetToken();
256                         if (t.type != Tokenizer::Token::BRACKET_CLOSE && t.type != Tokenizer::Token::COMMA) {
257                                 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or ]");
258                         }
259                 }
260                 return new Literal(values);
261         }
262 }
263
264 Literal *Parser::ParseColor() {
265         string msg("error parsing color");
266         Tokenizer::Token t(GetToken());
267         AssertTokenType(t.type, Tokenizer::Token::PARENTHESIS_OPEN, msg);
268
269         Tokenizer::Token red(GetToken());
270         AssertTokenType(red.type, Tokenizer::Token::NUMBER, "error parsing red component of color");
271
272         t = GetToken();
273         AssertTokenType(t.type, Tokenizer::Token::COMMA, msg);
274
275         Tokenizer::Token green(GetToken());
276         AssertTokenType(green.type, Tokenizer::Token::NUMBER, "error parsing green component of color");
277
278         t = GetToken();
279         AssertTokenType(t.type, Tokenizer::Token::COMMA, msg);
280
281         Tokenizer::Token blue(GetToken());
282         AssertTokenType(blue.type, Tokenizer::Token::NUMBER, "error parsing blue component of color");
283
284         t = GetToken();
285         if (t.type == Tokenizer::Token::BRACKET_CLOSE) {
286                 return new Literal(red.number, green.number, blue.number);
287         } else if (t.type != Tokenizer::Token::COMMA) {
288                 Tokenizer::Token alpha(GetToken());
289                 AssertTokenType(alpha.type, Tokenizer::Token::NUMBER, "error parsing alpha component of color");
290
291                 t = GetToken();
292                 AssertTokenType(t.type, Tokenizer::Token::PARENTHESIS_CLOSE, msg);
293
294                 return new Literal(red.number, green.number, blue.number, alpha.number);
295         } else {
296                 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or ]");
297         }
298 }
299
300 Literal *Parser::ParseVector() {
301         std::string msg("error parsing vector");
302         Tokenizer::Token t(GetToken());
303         AssertTokenType(t.type, Tokenizer::Token::CHEVRON_OPEN, msg);
304
305         Tokenizer::Token x(GetToken());
306         AssertTokenType(x.type, Tokenizer::Token::NUMBER, "error parsing x component of vector");
307
308         t = GetToken();
309         AssertTokenType(t.type, Tokenizer::Token::COMMA, msg);
310
311         Tokenizer::Token y(GetToken());
312         AssertTokenType(y.type, Tokenizer::Token::NUMBER, "error parsing y component of vector");
313
314         t = GetToken();
315         AssertTokenType(t.type, Tokenizer::Token::CHEVRON_CLOSE, msg);
316
317         return new Literal(x.number, y.number);
318 }
319
320 void Parser::AssertTokenType(Tokenizer::Token::Type actual, Tokenizer::Token::Type expected) {
321         if (expected != actual) {
322                 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(actual) + ", expected " + TokenTypeToString(expected));
323         }
324 }
325
326 void Parser::AssertTokenType(Tokenizer::Token::Type actual, Tokenizer::Token::Type expected, const string &msg) {
327         if (expected != actual) {
328                 throw Error(file, tok.Line(), msg + ": unexpected token " + TokenTypeToString(actual) + ", expected " + TokenTypeToString(expected));
329         }
330 }
331
332 }