]> git.localhorst.tv Git - l2e.git/blob - src/loader/Parser.cpp
more information in parsed source and output
[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() try {
48         return tok.GetNext();
49 } catch (Tokenizer::LexerError &e) {
50         throw Error(file, e.Line(), e.what());
51 }
52
53 void Parser::ParseExportDirective() {
54         Tokenizer::Token t(GetToken());
55         if (t.type != Tokenizer::Token::IDENTIFIER) {
56                 tok.Putback(t);
57                 Declaration *decl(ProbeDefinition());
58                 product.ExportDeclaration(decl);
59         } else {
60                 product.ExportIdentifier(t.str);
61         }
62 }
63
64 void Parser::ParseIncludeDirective() {
65         Tokenizer::Token t(GetToken());
66         AssertTokenType(t.type, Tokenizer::Token::STRING);
67         Parser sub(t.str.c_str(), product); // TODO: resolve path name
68         sub.Parse();
69 }
70
71 Declaration *Parser::ProbeDefinition() {
72         string typeName(ParseTypeName());
73         string identifier(ParseIdentifier());
74
75         Tokenizer::Token t(GetToken());
76         tok.Putback(t);
77         if (BeginOfPropertyList(t)) {
78                 auto_ptr<PropertyList> propertyList(ParsePropertyList());
79                 auto_ptr<Definition> dfn(new Definition(typeName, identifier));
80                 dfn->SetValue(propertyList.release());
81                 product.AddDefinition(dfn.get());
82                 return dfn.release();
83         } else if (BeginningOfLiteral(t)) {
84                 auto_ptr<Literal> literal(ParseLiteral());
85                 auto_ptr<Definition> dfn(new Definition(typeName, identifier));
86                 dfn->SetValue(literal.release());
87                 product.AddDefinition(dfn.get());
88                 return dfn.release();
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         Tokenizer::Token probe(GetToken());
222         tok.Putback(probe);
223
224         if (probe.type == Tokenizer::Token::ANGLE_BRACKET_OPEN) {
225                 vector<PropertyList *> values;
226                 while (t.type != Tokenizer::Token::BRACKET_CLOSE) {
227                         PropertyList *value(ParsePropertyList());
228                         values.push_back(value);
229
230                         t = GetToken();
231                         if (t.type != Tokenizer::Token::BRACKET_CLOSE && t.type != Tokenizer::Token::COMMA) {
232                                 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or ]");
233                         }
234                 }
235                 return new Literal(values);
236         } else {
237                 vector<Value *> values;
238                 while (t.type != Tokenizer::Token::BRACKET_CLOSE) {
239                         Value *value(ParseValue());
240                         values.push_back(value);
241
242                         t = GetToken();
243                         if (t.type != Tokenizer::Token::BRACKET_CLOSE && t.type != Tokenizer::Token::COMMA) {
244                                 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or ]");
245                         }
246                 }
247                 return new Literal(values);
248         }
249 }
250
251 Literal *Parser::ParseColor() {
252         string msg("error parsing color");
253         Tokenizer::Token t(GetToken());
254         AssertTokenType(t.type, Tokenizer::Token::PARENTHESIS_OPEN, msg);
255
256         Tokenizer::Token red(GetToken());
257         AssertTokenType(red.type, Tokenizer::Token::NUMBER, "error parsing red component of color");
258
259         t = GetToken();
260         AssertTokenType(t.type, Tokenizer::Token::COMMA, msg);
261
262         Tokenizer::Token green(GetToken());
263         AssertTokenType(green.type, Tokenizer::Token::NUMBER, "error parsing green component of color");
264
265         t = GetToken();
266         AssertTokenType(t.type, Tokenizer::Token::COMMA, msg);
267
268         Tokenizer::Token blue(GetToken());
269         AssertTokenType(blue.type, Tokenizer::Token::NUMBER, "error parsing blue component of color");
270
271         t = GetToken();
272         if (t.type == Tokenizer::Token::BRACKET_CLOSE) {
273                 return new Literal(red.number, green.number, blue.number);
274         } else if (t.type != Tokenizer::Token::COMMA) {
275                 Tokenizer::Token alpha(GetToken());
276                 AssertTokenType(alpha.type, Tokenizer::Token::NUMBER, "error parsing alpha component of color");
277
278                 t = GetToken();
279                 AssertTokenType(t.type, Tokenizer::Token::PARENTHESIS_CLOSE, msg);
280
281                 return new Literal(red.number, green.number, blue.number, alpha.number);
282         } else {
283                 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or ]");
284         }
285 }
286
287 Literal *Parser::ParseVector() {
288         std::string msg("error parsing vector");
289         Tokenizer::Token t(GetToken());
290         AssertTokenType(t.type, Tokenizer::Token::CHEVRON_OPEN, msg);
291
292         Tokenizer::Token x(GetToken());
293         AssertTokenType(x.type, Tokenizer::Token::NUMBER, "error parsing x component of vector");
294
295         t = GetToken();
296         AssertTokenType(t.type, Tokenizer::Token::COMMA, msg);
297
298         Tokenizer::Token y(GetToken());
299         AssertTokenType(y.type, Tokenizer::Token::NUMBER, "error parsing y component of vector");
300
301         t = GetToken();
302         AssertTokenType(t.type, Tokenizer::Token::CHEVRON_CLOSE, msg);
303
304         return new Literal(x.number, y.number);
305 }
306
307 void Parser::AssertTokenType(Tokenizer::Token::Type actual, Tokenizer::Token::Type expected) {
308         if (expected != actual) {
309                 throw Error(file, tok.Line(), string("unexpected token ") + TokenTypeToString(actual) + ", expected " + TokenTypeToString(expected));
310         }
311 }
312
313 void Parser::AssertTokenType(Tokenizer::Token::Type actual, Tokenizer::Token::Type expected, const string &msg) {
314         if (expected != actual) {
315                 throw Error(file, tok.Line(), msg + ": unexpected token " + TokenTypeToString(actual) + ", expected " + TokenTypeToString(expected));
316         }
317 }
318
319 }