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