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