summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Stöckel <astoecke@techfak.uni-bielefeld.de>2015-02-04 01:45:41 +0100
committerAndreas Stöckel <astoecke@techfak.uni-bielefeld.de>2015-02-04 01:45:41 +0100
commit835cca85ee45dd1b6722d761999c07c33fb97cc9 (patch)
treee4b9435222d100b6161277231ef3766cd3a45e11
parentec6306ad1e746d47ed66af6274fb6710c70933a2 (diff)
Implemented parsing of enum types
-rw-r--r--src/core/model/Typesystem.cpp79
-rw-r--r--src/core/model/Typesystem.hpp74
-rw-r--r--src/plugins/xml/XmlParser.cpp70
-rw-r--r--test/core/model/TypesystemTest.cpp1
-rw-r--r--testdata/xmlparser/color.oxm4
-rw-r--r--testdata/xmlparser/generic.oxm33
6 files changed, 173 insertions, 88 deletions
diff --git a/src/core/model/Typesystem.cpp b/src/core/model/Typesystem.cpp
index 7dd5613..a3c5b6d 100644
--- a/src/core/model/Typesystem.cpp
+++ b/src/core/model/Typesystem.cpp
@@ -67,10 +67,7 @@ bool Type::build(Variant &data, Logger &logger) const
return build(data, logger, NullMagicCallback);
}
-bool Type::doCheckIsa(Handle<const Type> type) const
-{
- return false;
-}
+bool Type::doCheckIsa(Handle<const Type> type) const { return false; }
bool Type::checkIsa(Handle<const Type> type) const
{
@@ -114,6 +111,11 @@ bool StringType::doBuild(Variant &data, Logger &logger,
/* Class EnumType */
+EnumType::EnumType(Manager &mgr, std::string name, Handle<Typesystem> system)
+ : Type(mgr, std::move(name), system, false), nextOrdinalValue(0)
+{
+}
+
bool EnumType::doBuild(Variant &data, Logger &logger,
const MagicCallback &magicCallback) const
{
@@ -145,32 +147,45 @@ bool EnumType::doBuild(Variant &data, Logger &logger,
throw LoggableException{"Expected integer or identifier", data};
}
-Rooted<EnumType> EnumType::createValidated(
- Manager &mgr, std::string name, Handle<Typesystem> system,
- const std::vector<std::string> &values, Logger &logger)
-{
- // Map used to store the unique values of the enum
- std::map<std::string, Ordinal> unique_values;
-
- // The given vector may not be empty
+bool EnumType::doValidate(Logger &logger) const{
+ bool ok = true;
if (values.empty()) {
- logger.error("Enumeration constants may not be empty.");
+ logger.error("Enum type must have at least one entry", *this);
+ ok = false;
}
+ return ok & validateName(logger);
+}
- // Iterate over the input vector, check the constant names for validity and
- // uniqueness and insert them into the internal values map
- for (size_t i = 0; i < values.size(); i++) {
- if (!Utils::isIdentifier(values[i])) {
- logger.error(std::string("\"") + values[i] +
- "\" is no valid identifier.");
- }
+void EnumType::addEntry(const std::string &entry, Logger &logger)
+{
+ if (!Utils::isIdentifier(entry)) {
+ logger.error(std::string("\"") + entry +
+ "\" is not a valid identifier.");
+ return;
+ }
- if (!(unique_values.insert(std::make_pair(values[i], i))).second) {
- logger.error(std::string("The value ") + values[i] +
- " was duplicated.");
- }
+ if (!values.emplace(entry, nextOrdinalValue).second) {
+ logger.error(std::string("The enumeration entry ") +entry +
+ std::string(" was duplicated"));
+ return;
+ }
+ nextOrdinalValue++;
+}
+
+void EnumType::addEntries(const std::vector<std::string> &entries, Logger &logger)
+{
+ for (const std::string &entry: entries) {
+ addEntry(entry, logger);
}
- return new EnumType{mgr, name, system, unique_values};
+}
+
+Rooted<EnumType> EnumType::createValidated(
+ Manager &mgr, std::string name, Handle<Typesystem> system,
+ const std::vector<std::string> &entries, Logger &logger)
+{
+ Rooted<EnumType> type = new EnumType{mgr, name, system};
+ type->addEntries(entries, logger);
+ return type;
}
std::string EnumType::nameOf(Ordinal i) const
@@ -390,12 +405,15 @@ bool StructType::buildFromMap(Variant &data, Logger &logger,
ok = false;
logger.error(std::string("Invalid attribute key \"") + key +
std::string("\""),
- value);
+ data);
}
}
// Copy the built array to the result and insert missing default values
+ // TODO: Nicer way of assigning a new variant value and keeping location?
+ SourceLocation loc = data.getLocation();
data = arr;
+ data.setLocation(loc);
return insertDefaults(data, set, logger) && ok;
}
@@ -470,7 +488,6 @@ bool StructType::doCheckIsa(Handle<const Type> type) const
return false;
}
-
Rooted<StructType> StructType::createValidated(
Manager &mgr, std::string name, Handle<Typesystem> system,
Handle<StructType> parentStructure, const NodeVector<Attribute> &attributes,
@@ -625,7 +642,6 @@ bool ArrayType::doCheckIsa(Handle<const Type> type) const
return t1->checkIsa(t2);
}
-
/* Class UnknownType */
bool UnknownType::doBuild(Variant &, Logger &, const MagicCallback &) const
@@ -706,6 +722,13 @@ Rooted<StructType> Typesystem::createStructType(const std::string &name)
return structType;
}
+Rooted<EnumType> Typesystem::createEnumType(const std::string &name)
+{
+ Rooted<EnumType> enumType{new EnumType(getManager(), name, this)};
+ addType(enumType);
+ return enumType;
+}
+
Rooted<Constant> Typesystem::createConstant(const std::string &name,
Variant value)
{
diff --git a/src/core/model/Typesystem.hpp b/src/core/model/Typesystem.hpp
index 7581626..819f90d 100644
--- a/src/core/model/Typesystem.hpp
+++ b/src/core/model/Typesystem.hpp
@@ -371,26 +371,16 @@ public:
private:
/**
- * Map containing the enumeration type values and the associated integer
- * representation.
+ * Value holding the next ordinal value that is to be used when adding a new
+ * type.
*/
- const std::map<std::string, Ordinal> values;
+ Ordinal nextOrdinalValue;
/**
- * Private constructor of the EnumType class used to create a new EnumType
- * instance from a previously created name to value map. The parameters are
- * not checked for validity.
- *
- * @param mgr is the underlying Manager instance.
- * @param name is the name of the EnumType instance. Should be a valid
- * identifier.
- * @param values is a vector containing the enumeration type constants.
+ * Map containing the enumeration type values and the associated integer
+ * representation.
*/
- EnumType(Manager &mgr, std::string name, Handle<Typesystem> system,
- std::map<std::string, Ordinal> values)
- : Type(mgr, std::move(name), system, false), values(std::move(values))
- {
- }
+ std::map<std::string, Ordinal> values;
protected:
/**
@@ -405,22 +395,61 @@ protected:
bool doBuild(Variant &data, Logger &logger,
const MagicCallback &magicCallback) const override;
+ /**
+ * Returns true if the internal value list is non-empty.
+ *
+ * @param logger is the logger instance to which validation errors are
+ * logged.
+ */
+ bool doValidate(Logger &logger) const override;
+
public:
/**
+ * Constructor of the EnumType class.
+ *
+ * @param mgr is the underlying Manager instance.
+ * @param name is the name of the EnumType instance. Should be a valid
+ * identifier.
+ * @param system is the parent typesystem.
+ */
+ EnumType(Manager &mgr, std::string name, Handle<Typesystem> system);
+
+ /**
+ * Adds a new entry to the enum. The enum element is validated, errors
+ * are logged in the given logger instance.
+ *
+ * @param entry is the name of the enum element that should be added.
+ * @param logger is the logger instance that should be used to write error
+ * messages.
+ */
+ void addEntry(const std::string &entry, Logger &logger);
+
+ /**
+ * Adds a new entry to the enum. The enum element is validated, errors
+ * are logged in the given logger instance.
+ *
+ * @param entires is a list containing the enum elements that should be
+ * added.
+ * @param logger is the logger instance that should be used to write error
+ * messages.
+ */
+ void addEntries(const std::vector<std::string> &entries, Logger &logger);
+
+ /**
* Creates a new enum instance and validates the incomming value vector.
*
* @param mgr is the underlying Manager instance.
* @param name is the name of the EnumType instance. Should be a valid
* identifier.
* @param system is a reference to the parent Typesystem instance.
- * @param values is a vector containing the enumeration type constants.
+ * @param entries is a vector containing the enumeration type constants.
* The constants are checked for validity (must be a valid identifier) and
* uniqueness (each value must exist exactly once).
* @param logger is the Logger instance into which errors should be written.
*/
static Rooted<EnumType> createValidated(
Manager &mgr, std::string name, Handle<Typesystem> system,
- const std::vector<std::string> &values, Logger &logger);
+ const std::vector<std::string> &entries, Logger &logger);
/**
* Creates a Variant containing a valid representation of a variable of this
@@ -1135,6 +1164,15 @@ public:
Rooted<StructType> createStructType(const std::string &name);
/**
+ * Creates a new EnumType instance with the given name. Adds the new
+ * EnumType as member to the typesystem.
+ *
+ * @param name is the name of the structure that should be created.
+ * @return the new EnumType instance.
+ */
+ Rooted<EnumType> createEnumType(const std::string &name);
+
+ /**
* Creates a new Constant instance with the given name. Adds the new
* Constant as member to the typesystem.
*
diff --git a/src/plugins/xml/XmlParser.cpp b/src/plugins/xml/XmlParser.cpp
index e56d528..92caf09 100644
--- a/src/plugins/xml/XmlParser.cpp
+++ b/src/plugins/xml/XmlParser.cpp
@@ -107,38 +107,50 @@ public:
{
scope().setFlag(ParserFlag::POST_HEAD, true);
- // Fetch the arguments used for creating this type
- const std::string &name = args["name"].asString();
- const std::string &parent = args["parent"].asString();
-
- // Fetch the current typesystem and create the struct node
+ // Fetch the current typesystem and create the enum node
Rooted<Typesystem> typesystem = scope().selectOrThrow<Typesystem>();
- Rooted<StructType> structType = typesystem->createStructType(name);
- structType->setLocation(location());
+ Rooted<EnumType> enumType =
+ typesystem->createEnumType(args["name"].asString());
+ enumType->setLocation(location());
- // Try to resolve the parent type and set it as parent structure
- if (!parent.empty()) {
- scope().resolve<StructType>(
- parent, structType, logger(),
- [](Handle<Node> parent, Handle<Node> structType,
- Logger &logger) {
- if (parent != nullptr) {
- structType.cast<StructType>()->setParentStructure(
- parent.cast<StructType>(), logger);
- }
- });
- }
- scope().push(structType);
+ scope().push(enumType);
}
+ void end() override { scope().pop(); }
+
+ static Handler *create(const HandlerData &handlerData)
+ {
+ return new TypesystemEnumHandler{handlerData};
+ }
+};
+
+class TypesystemEnumEntryHandler : public Handler {
+public:
+ using Handler::Handler;
+
+ std::string entry;
+
+ void start(Variant::mapType &args) override {}
+
void end() override
{
- scope().pop();
+ Rooted<EnumType> enumType = scope().selectOrThrow<EnumType>();
+ enumType->addEntry(entry, logger());
+ }
+
+ void data(const std::string &data, int field) override
+ {
+ if (field != 0) {
+ // TODO: This should be stored in the HandlerData
+ logger().error("Enum entry only has one field.");
+ return;
+ }
+ entry.append(data);
}
static Handler *create(const HandlerData &handlerData)
{
- return new TypesystemEnumHandler{handlerData};
+ return new TypesystemEnumEntryHandler{handlerData};
}
};
@@ -174,10 +186,7 @@ public:
scope().push(structType);
}
- void end() override
- {
- scope().pop();
- }
+ void end() override { scope().pop(); }
static Handler *create(const HandlerData &handlerData)
{
@@ -474,9 +483,15 @@ static const ParserState Typesystem =
.arguments({Argument::String("name", "")});
static const ParserState TypesystemEnum =
ParserStateBuilder()
+ .parent(&Typesystem)
.createdNodeType(&RttiTypes::EnumType)
.elementHandler(TypesystemEnumHandler::create)
- .parent(&Typesystem);
+ .arguments({Argument::String("name")});
+static const ParserState TypesystemEnumEntry =
+ ParserStateBuilder()
+ .parent(&TypesystemEnum)
+ .elementHandler(TypesystemEnumEntryHandler::create)
+ .arguments({});
static const ParserState TypesystemStruct =
ParserStateBuilder()
.parent(&Typesystem)
@@ -520,6 +535,7 @@ static const std::multimap<std::string, const ParserState *> XmlStates{
{"primitive", &DomainStructPrimitive},
{"typesystem", &Typesystem},
{"enum", &TypesystemEnum},
+ {"entry", &TypesystemEnumEntry},
{"struct", &TypesystemStruct},
{"field", &TypesystemStructField},
{"constant", &TypesystemConstant},
diff --git a/test/core/model/TypesystemTest.cpp b/test/core/model/TypesystemTest.cpp
index 2a2c81e..bf40356 100644
--- a/test/core/model/TypesystemTest.cpp
+++ b/test/core/model/TypesystemTest.cpp
@@ -400,6 +400,7 @@ TEST(EnumType, createValidated)
logger.reset();
Rooted<EnumType> enumType{
EnumType::createValidated(mgr, "enum", nullptr, {}, logger)};
+ ASSERT_FALSE(enumType->validate(logger));
ASSERT_EQ(Severity::ERROR, logger.getMaxEncounteredSeverity());
}
diff --git a/testdata/xmlparser/color.oxm b/testdata/xmlparser/color.oxm
index 8a12e7a..17adea4 100644
--- a/testdata/xmlparser/color.oxm
+++ b/testdata/xmlparser/color.oxm
@@ -1,5 +1,5 @@
<?xml version="1.0" standalone="yes"?>
-<ousia>
+<typesystem name="color">
<struct name="color">
<field name="r" type="int"/>
<field name="g" type="int"/>
@@ -15,4 +15,4 @@
<constant name="azure3" type="color" value="[193,205,205]"/>
<constant name="azure4" type="color" value="[131,139,139]"/>
<constant name="azure" type="color" value="[240,255,255]"/>
-</ousia>
+</typesystem>
diff --git a/testdata/xmlparser/generic.oxm b/testdata/xmlparser/generic.oxm
index 820deea..a23d5f8 100644
--- a/testdata/xmlparser/generic.oxm
+++ b/testdata/xmlparser/generic.oxm
@@ -1,21 +1,28 @@
<?xml version="1.0" standalone="yes"?>
-<typesystem name="bla">
- <import>color.oxm</import>
- <!--<struct name="color">
- <field name="r" type="int"/>
- <field name="g" type="int"/>
- <field name="b" type="int"/>
- </struct>-->
- <!--<include>color.oxm</include>-->
+<typesystem name="border">
+ <import>./color.oxm</import>
+
+ <enum name="border-style">
+ <entry>none</entry>
+ <entry>dotted</entry>
+ <entry>dashed</entry>
+ <entry>solid</entry>
+ <entry>double</entry>
+ <entry>groove</entry>
+ <entry>ridge</entry>
+ <entry>inset</entry>
+ <entry>outset</entry>
+ </enum>
<constant name="zero" value="0" type="int" />
- <constant name="zeros" value="[0, 0, 0]" type="int[]" />
- <constant name="manyZeros" value="[[eeeee, [2, 5], zeros], [42, 1000], [0, {3-5}]]" type="int[][][]" />
- <!--<constant name="black" value="[zero, zero, zero]" type="color" />-->
- <struct name="structWithColor">
+ <constant name="black" value="[zero, zero, zero]" type="color" />
+
+ <struct name="border">
<field name="color" type="color" default="black" />
+ <field name="style" type="border-style"/>
</struct>
- <constant name="aquamarineStructWithColor" value="[color=aquamarine]" type="structWithColor" />
+
+ <constant name="beautifulBorder" type="border" value="[color=aquamarine,style=solid]" />
</typesystem>
<!--<domain name="color">
<struct name="bla" cardinality="{1,2}" isa="blub"/>