AAPT2: Separate out the various steps
An early refactor. Some ideas became clearer as
development continued. Now the various phases are much
clearer and more easily reusable.
Also added a ton of tests!
Change-Id: Ic8f0a70c8222370352e63533b329c40457c0903e
diff --git a/tools/aapt2/ValueVisitor.h b/tools/aapt2/ValueVisitor.h
new file mode 100644
index 0000000..ee058aa
--- /dev/null
+++ b/tools/aapt2/ValueVisitor.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_VALUE_VISITOR_H
+#define AAPT_VALUE_VISITOR_H
+
+#include "ResourceValues.h"
+
+namespace aapt {
+
+/**
+ * Visits a value and invokes the appropriate method based on its type. Does not traverse
+ * into compound types. Use ValueVisitor for that.
+ */
+struct RawValueVisitor {
+ virtual ~RawValueVisitor() = default;
+
+ virtual void visitItem(Item* value) {}
+ virtual void visit(Reference* value) { visitItem(value); }
+ virtual void visit(RawString* value) { visitItem(value); }
+ virtual void visit(String* value) { visitItem(value); }
+ virtual void visit(StyledString* value) { visitItem(value); }
+ virtual void visit(FileReference* value) { visitItem(value); }
+ virtual void visit(Id* value) { visitItem(value); }
+ virtual void visit(BinaryPrimitive* value) { visitItem(value); }
+
+ virtual void visit(Attribute* value) {}
+ virtual void visit(Style* value) {}
+ virtual void visit(Array* value) {}
+ virtual void visit(Plural* value) {}
+ virtual void visit(Styleable* value) {}
+};
+
+#define DECL_VISIT_COMPOUND_VALUE(T) \
+ virtual void visit(T* value) { \
+ visitSubValues(value); \
+ }
+
+/**
+ * Visits values, and if they are compound values, visits the components as well.
+ */
+struct ValueVisitor : public RawValueVisitor {
+ // The compiler will think we're hiding an overload, when we actually intend
+ // to call into RawValueVisitor. This will expose the visit methods in the super
+ // class so the compiler knows we are trying to call them.
+ using RawValueVisitor::visit;
+
+ void visitSubValues(Attribute* attribute) {
+ for (Attribute::Symbol& symbol : attribute->symbols) {
+ visit(&symbol.symbol);
+ }
+ }
+
+ void visitSubValues(Style* style) {
+ if (style->parent) {
+ visit(&style->parent.value());
+ }
+
+ for (Style::Entry& entry : style->entries) {
+ visit(&entry.key);
+ entry.value->accept(this);
+ }
+ }
+
+ void visitSubValues(Array* array) {
+ for (std::unique_ptr<Item>& item : array->items) {
+ item->accept(this);
+ }
+ }
+
+ void visitSubValues(Plural* plural) {
+ for (std::unique_ptr<Item>& item : plural->values) {
+ if (item) {
+ item->accept(this);
+ }
+ }
+ }
+
+ void visitSubValues(Styleable* styleable) {
+ for (Reference& reference : styleable->entries) {
+ visit(&reference);
+ }
+ }
+
+ DECL_VISIT_COMPOUND_VALUE(Attribute);
+ DECL_VISIT_COMPOUND_VALUE(Style);
+ DECL_VISIT_COMPOUND_VALUE(Array);
+ DECL_VISIT_COMPOUND_VALUE(Plural);
+ DECL_VISIT_COMPOUND_VALUE(Styleable);
+};
+
+/**
+ * Do not use directly. Helper struct for dyn_cast.
+ */
+template <typename T>
+struct DynCastVisitor : public RawValueVisitor {
+ T* value = nullptr;
+
+ void visit(T* v) override {
+ value = v;
+ }
+};
+
+/**
+ * Returns a valid pointer to T if the Value is of subtype T.
+ * Otherwise, returns nullptr.
+ */
+template <typename T>
+T* valueCast(Value* value) {
+ if (!value) {
+ return nullptr;
+ }
+ DynCastVisitor<T> visitor;
+ value->accept(&visitor);
+ return visitor.value;
+}
+
+} // namespace aapt
+
+#endif // AAPT_VALUE_VISITOR_H