--- /dev/null
+/*
+ * ParsedSource.cpp
+ *
+ * Created on: Aug 26, 2012
+ * Author: holy
+ */
+
+#include "ParsedSource.h"
+
+#include <ostream>
+#include <stdexcept>
+
+using std::map;
+using std::runtime_error;
+using std::string;
+using std::vector;
+
+namespace loader {
+
+void ParsedSource::AddDeclaration(Declaration *d) {
+ map<string, Declaration *>::iterator i(declarations.find(d->Identifier()));
+ if (i != declarations.end()) {
+ if (d->TypeName() != i->second->TypeName()) {
+ throw runtime_error("invalid redeclaration of " + i->second->TypeName() + " " + d->Identifier());
+ }
+ } else {
+ declarations.insert(std::make_pair(d->Identifier(), d));
+ }
+}
+
+void ParsedSource::ExportDeclaration(Declaration *d) {
+ AddDeclaration(d);
+ exports.insert(d->Identifier());
+}
+
+void ParsedSource::ExportIdentifier(const std::string &i) {
+ if (declarations.count(i)) {
+ exports.insert(i);
+ } else {
+ throw runtime_error("cannot export undeclared identifier " + i);
+ }
+}
+
+
+void Definition::SetValue(Literal *v) {
+ value = v;
+ isLiteral = true;
+}
+
+void Definition::SetValue(PropertyList *v) {
+ value = v;
+ isLiteral = false;
+}
+
+Literal *Definition::GetLiteral() {
+ if (isLiteral) {
+ return (Literal *)value;
+ } else {
+ throw runtime_error("tried to access properties as literal");
+ }
+}
+
+const Literal *Definition::GetLiteral() const {
+ if (isLiteral) {
+ return (Literal *)value;
+ } else {
+ throw runtime_error("tried to access properties as literal");
+ }
+}
+
+PropertyList *Definition::GetProperties() {
+ if (!isLiteral) {
+ return (PropertyList *)value;
+ } else {
+ throw runtime_error("tried to access literal value as property list");
+ }
+}
+
+const PropertyList *Definition::GetProperties() const {
+ if (!isLiteral) {
+ return (PropertyList *)value;
+ } else {
+ throw runtime_error("tried to access literal value as property list");
+ }
+}
+
+
+PropertyList::~PropertyList() {
+ for (map<string, Value *>::iterator i(props.begin()), end(props.end()); i != end; ++i) {
+ delete i->second;
+ }
+}
+
+
+Literal::Literal(const vector<Value *> &v)
+: props(0)
+, values(v)
+, i1(0), i2(0)
+, i3(0), i4(0)
+, b(false)
+, type(ARRAY) {
+
+}
+
+Literal::Literal(bool b)
+: props(0)
+, i1(0), i2(0)
+, i3(0), i4(0)
+, b(b)
+, type(BOOLEAN) {
+
+}
+
+Literal::Literal(int r, int g, int b, int a)
+: props(0)
+, i1(r), i2(g)
+, i3(b), i4(a)
+, b(false)
+, type(COLOR) {
+
+}
+
+Literal::Literal(const string &str)
+: props(0)
+, str(str)
+, i1(0), i2(0)
+, i3(0), i4(0)
+, b(false)
+, type(STRING) {
+
+}
+
+Literal::Literal(int x, int y)
+: props(0)
+, i1(x), i2(y)
+, i3(0), i4(0)
+, b(false)
+, type(VECTOR) {
+
+}
+
+Literal::Literal(const string &typeName, PropertyList *properties)
+: props(properties)
+, str(typeName)
+, i1(0), i2(0)
+, i3(0), i4(0)
+, b(false)
+, type(OBJECT) {
+
+}
+
+}
+
+
+namespace std {
+
+ostream &operator <<(ostream &out, const loader::ParsedSource &source) {
+ out << "parsed source file" << endl;
+ out << "declared objects: " << endl;
+ for (map<string, loader::Declaration *>::const_iterator i(source.Declarations().begin()), end(source.Declarations().end()); i != end; ++i) {
+ out << " - " << i->first << " of type " << i->second->TypeName() << endl;
+ }
+ out << "exported objects: " << endl;
+ for (set<string>::const_iterator i(source.Exports().begin()), end(source.Exports().end()); i != end; ++i) {
+ out << " - " << *i << endl;
+ }
+ return out;
+}
+
+}
--- /dev/null
+/*
+ * ParsedSource.h
+ *
+ * Created on: Aug 26, 2012
+ * Author: holy
+ */
+
+#ifndef LOADER_PARSEDSOURCE_H_
+#define LOADER_PARSEDSOURCE_H_
+
+#include <iosfwd>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+namespace loader {
+
+class PropertyList;
+class Value;
+
+class Literal {
+
+ enum Type {
+ ARRAY,
+ BOOLEAN,
+ COLOR,
+ NUMBER,
+ STRING,
+ VECTOR,
+ OBJECT
+ };
+
+public:
+ explicit Literal(const std::vector<Value *> &);
+ explicit Literal(bool);
+ Literal(int r, int g, int b, int a = 255);
+ Literal(const std::string &);
+ Literal(int x, int y);
+ Literal(const std::string &typeName, PropertyList *properties);
+
+private:
+ PropertyList *props;
+ std::string str;
+ std::vector<Value *> values;
+ int i1, i2, i3, i4;
+ bool b;
+ Type type;
+
+};
+
+
+class Value {
+
+public:
+ explicit Value(const std::string &identifier)
+ : literal(0), identifier(identifier), isLiteral(false) { }
+ explicit Value(Literal *literal)
+ : literal(literal), isLiteral(false) { }
+
+private:
+ Literal *literal;
+ std::string identifier;
+ bool isLiteral;
+
+};
+
+
+class PropertyList {
+
+public:
+ ~PropertyList();
+
+public:
+ void SetProperty(const std::string &name, Value *value) {
+ props[name] = value;
+ }
+
+private:
+ std::map<std::string, Value *> props;
+
+};
+
+
+class Declaration {
+
+public:
+ Declaration(const std::string &typeName, const std::string &identifier)
+ : typeName(typeName), identifier(identifier) { }
+ virtual ~Declaration() { }
+
+public:
+ const std::string &TypeName() const { return typeName; }
+ const std::string &Identifier() const { return identifier; }
+
+private:
+ std::string typeName;
+ std::string identifier;
+
+};
+
+
+class Definition
+: public Declaration {
+
+public:
+ Definition(const std::string &typeName, const std::string &identifier)
+ : Declaration(typeName, identifier), value(0), isLiteral(false) { }
+
+public:
+ void SetValue(Literal *);
+ void SetValue(PropertyList *);
+
+ bool HasLiteralValue() const { return isLiteral && value; }
+ bool HasProperties() const { return !isLiteral && value; }
+ Literal *GetLiteral();
+ const Literal *GetLiteral() const;
+ PropertyList *GetProperties();
+ const PropertyList *GetProperties() const;
+
+private:
+ void *value;
+ bool isLiteral;
+
+};
+
+
+class ParsedSource {
+
+public:
+ ParsedSource() { }
+ ~ParsedSource() { }
+
+public:
+ void AddDeclaration(Declaration *);
+ void ExportDeclaration(Declaration *);
+ void ExportIdentifier(const std::string &);
+
+ const std::map<std::string, Declaration *> Declarations() const { return declarations; }
+ const std::set<std::string> Exports() const { return exports; }
+
+private:
+ std::map<std::string, Declaration *> declarations;
+ std::set<std::string> exports;
+
+};
+
+}
+
+
+namespace std {
+
+ostream &operator <<(ostream &, const loader::ParsedSource &);
+
+}
+
+#endif /* LOADER_PARSEDSOURCE_H_ */
--- /dev/null
+/*
+ * Parser.cpp
+ *
+ * Created on: Aug 26, 2012
+ * Author: holy
+ */
+
+#include "Parser.h"
+
+#include <auto_ptr.h>
+#include <fstream>
+
+using std::auto_ptr;
+using std::ifstream;
+using std::string;
+using std::vector;
+
+namespace loader {
+
+void Parser::Parse() {
+ while (tok.HasMore()) {
+ ParseStatement();
+ }
+}
+
+void Parser::ParseStatement() {
+ Tokenizer::Token t(tok.GetNext());
+ switch (t.type) {
+ case Tokenizer::Token::KEYWORD_EXPORT:
+ ParseExportDirective();
+ break;
+ case Tokenizer::Token::KEYWORD_INCLUDE:
+ ParseIncludeDirective();
+ break;
+ case Tokenizer::Token::TYPE_NAME:
+ tok.Putback(t);
+ {
+ Declaration *decl(ProbeDefinition());
+ product.AddDeclaration(decl);
+ }
+ break;
+ default:
+ throw ParseError(string("unexpected token ") + TokenTypeToString(t.type));
+ }
+}
+
+void Parser::ParseExportDirective() {
+ Tokenizer::Token t(tok.GetNext());
+ if (t.type != Tokenizer::Token::IDENTIFIER) {
+ tok.Putback(t);
+ Declaration *decl(ProbeDefinition());
+ product.ExportDeclaration(decl);
+ } else {
+ product.ExportIdentifier(t.str);
+ }
+}
+
+void Parser::ParseIncludeDirective() {
+ Tokenizer::Token t(tok.GetNext());
+ AssertTokenType(t.type, Tokenizer::Token::STRING);
+ ifstream file(t.str.c_str()); // TODO: resolve path name
+ Parser sub(file, product);
+ sub.Parse();
+}
+
+Declaration *Parser::ProbeDefinition() {
+ string typeName(ParseTypeName());
+ string identifier(ParseIdentifier());
+
+ Tokenizer::Token t(tok.GetNext());
+ tok.Putback(t);
+ if (BeginOfPropertyList(t)) {
+ PropertyList *propertyList(ParsePropertyList());
+ Definition *dfn(new Definition(typeName, identifier));
+ dfn->SetValue(propertyList);
+ return dfn;
+ } else if (BeginningOfLiteral(t)) {
+ Literal *literal(ParseLiteral());
+ Definition *dfn(new Definition(typeName, identifier));
+ dfn->SetValue(literal);
+ return dfn;
+ } else {
+ return new Declaration(typeName, identifier);
+ }
+}
+
+bool Parser::BeginningOfLiteral(const Tokenizer::Token &t) const {
+ switch (t.type) {
+ case Tokenizer::Token::CHEVRON_OPEN:
+ case Tokenizer::Token::BRACKET_OPEN:
+ case Tokenizer::Token::PARENTHESIS_OPEN:
+ case Tokenizer::Token::NUMBER:
+ case Tokenizer::Token::STRING:
+ case Tokenizer::Token::KEYWORD_FALSE:
+ case Tokenizer::Token::KEYWORD_TRUE:
+ case Tokenizer::Token::TYPE_NAME:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool Parser::BeginOfPropertyList(const Tokenizer::Token &t) const {
+ return t.type == Tokenizer::Token::ANGLE_BRACKET_OPEN;
+}
+
+Definition *Parser::ParseDefinition() {
+ string typeName(ParseTypeName());
+ string identifier(ParseIdentifier());
+
+ Tokenizer::Token t(tok.GetNext());
+ tok.Putback(t);
+ if (BeginOfPropertyList(t)) {
+ PropertyList *propertyList(ParsePropertyList());
+ Definition *dfn(new Definition(typeName, identifier));
+ dfn->SetValue(propertyList);
+ return dfn;
+ } else if (BeginningOfLiteral(t)) {
+ Literal *literal(ParseLiteral());
+ Definition *dfn(new Definition(typeName, identifier));
+ dfn->SetValue(literal);
+ return dfn;
+ } else {
+ throw ParseError(string("unexpected token ") + TokenTypeToString(t.type) + ", expected property-list or literal");
+ }
+}
+
+string Parser::ParseIdentifier() {
+ Tokenizer::Token t(tok.GetNext());
+ AssertTokenType(t.type, Tokenizer::Token::IDENTIFIER);
+ return t.str;
+}
+
+string Parser::ParseTypeName() {
+ Tokenizer::Token t(tok.GetNext());
+ AssertTokenType(t.type, Tokenizer::Token::TYPE_NAME);
+ return t.str;
+}
+
+PropertyList *Parser::ParsePropertyList() {
+ Tokenizer::Token t(tok.GetNext());
+ AssertTokenType(t.type, Tokenizer::Token::ANGLE_BRACKET_OPEN);
+
+ auto_ptr<PropertyList> props(new PropertyList);
+
+ while (t.type != Tokenizer::Token::ANGLE_BRACKET_CLOSE) {
+ Tokenizer::Token name(tok.GetNext());
+ AssertTokenType(name.type, Tokenizer::Token::IDENTIFIER);
+
+ t = tok.GetNext();
+ AssertTokenType(t.type, Tokenizer::Token::COLON);
+
+ Value *value(ParseValue());
+ props->SetProperty(name.str, value);
+
+ t = tok.GetNext();
+ if (t.type != Tokenizer::Token::ANGLE_BRACKET_CLOSE && t.type != Tokenizer::Token::COMMA) {
+ throw ParseError(string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or }");
+ }
+ }
+
+ return props.release();
+}
+
+Value *Parser::ParseValue() {
+ Tokenizer::Token t(tok.GetNext());
+ if (t.type == Tokenizer::Token::IDENTIFIER) {
+ return new Value(t.str);
+ } else if (BeginningOfLiteral(t)) {
+ tok.Putback(t);
+ Literal *literal(ParseLiteral());
+ return new Value(literal);
+ } else {
+ throw new ParseError(string("unexpected token ") + TokenTypeToString(t.type) + ", expected literal or identifier");
+ }
+}
+
+Literal *Parser::ParseLiteral() {
+ Tokenizer::Token t(tok.GetNext());
+ if (t.type == Tokenizer::Token::TYPE_NAME) {
+ PropertyList *props(ParsePropertyList());
+ return new Literal(t.str, props);
+ } else if (BeginningOfLiteral(t)) {
+ switch (t.type) {
+ case Tokenizer::Token::CHEVRON_OPEN:
+ tok.Putback(t);
+ return ParseVector();
+ case Tokenizer::Token::BRACKET_OPEN:
+ tok.Putback(t);
+ return ParseArray();
+ case Tokenizer::Token::PARENTHESIS_OPEN:
+ tok.Putback(t);
+ return ParseColor();
+ case Tokenizer::Token::NUMBER:
+ return new Literal(t.number);
+ case Tokenizer::Token::STRING:
+ return new Literal(t.str);
+ case Tokenizer::Token::KEYWORD_FALSE:
+ return new Literal(false);
+ case Tokenizer::Token::KEYWORD_TRUE:
+ return new Literal(true);
+ default:
+ throw std::logic_error("literal switch reached impossible default branch oO");
+ }
+ } else {
+ throw new ParseError(string("unexpected token ") + TokenTypeToString(t.type) + ", expected type-name or primitive");
+ }
+}
+
+Literal *Parser::ParseArray() {
+ Tokenizer::Token t(tok.GetNext());
+ AssertTokenType(t.type, Tokenizer::Token::BRACKET_OPEN);
+
+ vector<Value *> values;
+
+ while (t.type != Tokenizer::Token::ANGLE_BRACKET_CLOSE) {
+ Value *value(ParseValue());
+ values.push_back(value);
+
+ t = tok.GetNext();
+ if (t.type != Tokenizer::Token::BRACKET_CLOSE && t.type != Tokenizer::Token::COMMA) {
+ throw ParseError(string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or ]");
+ }
+ }
+
+ return new Literal(values);
+}
+
+Literal *Parser::ParseColor() {
+ string msg("error parsing color");
+ Tokenizer::Token t(tok.GetNext());
+ AssertTokenType(t.type, Tokenizer::Token::PARENTHESIS_OPEN, msg);
+
+ Tokenizer::Token red(tok.GetNext());
+ AssertTokenType(red.type, Tokenizer::Token::NUMBER, "error parsing red component of color");
+
+ t = tok.GetNext();
+ AssertTokenType(t.type, Tokenizer::Token::COMMA, msg);
+
+ Tokenizer::Token green(tok.GetNext());
+ AssertTokenType(green.type, Tokenizer::Token::NUMBER, "error parsing green component of color");
+
+ t = tok.GetNext();
+ AssertTokenType(t.type, Tokenizer::Token::COMMA, msg);
+
+ Tokenizer::Token blue(tok.GetNext());
+ AssertTokenType(blue.type, Tokenizer::Token::NUMBER, "error parsing blue component of color");
+
+ t = tok.GetNext();
+ if (t.type == Tokenizer::Token::BRACKET_CLOSE) {
+ return new Literal(red.number, green.number, blue.number);
+ } else if (t.type != Tokenizer::Token::COMMA) {
+ Tokenizer::Token alpha(tok.GetNext());
+ AssertTokenType(alpha.type, Tokenizer::Token::NUMBER, "error parsing alpha component of color");
+
+ t = tok.GetNext();
+ AssertTokenType(t.type, Tokenizer::Token::PARENTHESIS_CLOSE, msg);
+
+ return new Literal(red.number, green.number, blue.number, alpha.number);
+ } else {
+ throw ParseError(string("unexpected token ") + TokenTypeToString(t.type) + ", expected , or ]");
+ }
+}
+
+Literal *Parser::ParseVector() {
+ std::string msg("error parsing vector");
+ Tokenizer::Token t(tok.GetNext());
+ AssertTokenType(t.type, Tokenizer::Token::CHEVRON_OPEN, msg);
+
+ Tokenizer::Token x(tok.GetNext());
+ AssertTokenType(x.type, Tokenizer::Token::NUMBER, "error parsing x component of vector");
+
+ t = tok.GetNext();
+ AssertTokenType(t.type, Tokenizer::Token::COMMA, msg);
+
+ Tokenizer::Token y(tok.GetNext());
+ AssertTokenType(y.type, Tokenizer::Token::NUMBER, "error parsing y component of vector");
+
+ t = tok.GetNext();
+ AssertTokenType(t.type, Tokenizer::Token::CHEVRON_CLOSE, msg);
+
+ return new Literal(x.number, y.number);
+}
+
+void Parser::AssertTokenType(Tokenizer::Token::Type actual, Tokenizer::Token::Type expected) {
+ if (expected != actual) {
+ throw ParseError(string("unexpected token ") + TokenTypeToString(actual) + ", expected " + TokenTypeToString(expected));
+ }
+}
+
+void Parser::AssertTokenType(Tokenizer::Token::Type actual, Tokenizer::Token::Type expected, const string &msg) {
+ if (expected != actual) {
+ throw ParseError(msg + ": unexpected token " + TokenTypeToString(actual) + ", expected " + TokenTypeToString(expected));
+ }
+}
+
+}