summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/harness/wptrunner/wptmanifest/serializer.py
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/harness/wptrunner/wptmanifest/serializer.py')
-rw-r--r--testing/web-platform/harness/wptrunner/wptmanifest/serializer.py140
1 files changed, 140 insertions, 0 deletions
diff --git a/testing/web-platform/harness/wptrunner/wptmanifest/serializer.py b/testing/web-platform/harness/wptrunner/wptmanifest/serializer.py
new file mode 100644
index 000000000..efa839d8d
--- /dev/null
+++ b/testing/web-platform/harness/wptrunner/wptmanifest/serializer.py
@@ -0,0 +1,140 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this file,
+# You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from node import NodeVisitor, ValueNode, ListNode, BinaryExpressionNode
+from parser import atoms, precedence
+
+atom_names = {v:"@%s" % k for (k,v) in atoms.iteritems()}
+
+named_escapes = set(["\a", "\b", "\f", "\n", "\r", "\t", "\v"])
+
+def escape(string, extras=""):
+ rv = ""
+ for c in string:
+ if c in named_escapes:
+ rv += c.encode("unicode_escape")
+ elif c == "\\":
+ rv += "\\\\"
+ elif c < '\x20':
+ rv += "\\x%02x" % ord(c)
+ elif c in extras:
+ rv += "\\" + c
+ else:
+ rv += c
+ return rv.encode("utf8")
+
+
+class ManifestSerializer(NodeVisitor):
+ def __init__(self, skip_empty_data=False):
+ self.skip_empty_data = skip_empty_data
+
+ def serialize(self, root):
+ self.indent = 2
+ rv = "\n".join(self.visit(root))
+ if rv[-1] != "\n":
+ rv = rv + "\n"
+ return rv
+
+ def visit_DataNode(self, node):
+ rv = []
+ if not self.skip_empty_data or node.children:
+ if node.data:
+ rv.append("[%s]" % escape(node.data, extras="]"))
+ indent = self.indent * " "
+ else:
+ indent = ""
+
+ for child in node.children:
+ rv.extend("%s%s" % (indent if item else "", item) for item in self.visit(child))
+
+ if node.parent:
+ rv.append("")
+
+ return rv
+
+ def visit_KeyValueNode(self, node):
+ rv = [escape(node.data, ":") + ":"]
+ indent = " " * self.indent
+
+ if len(node.children) == 1 and isinstance(node.children[0], (ValueNode, ListNode)):
+ rv[0] += " %s" % self.visit(node.children[0])[0]
+ else:
+ for child in node.children:
+ rv.append(indent + self.visit(child)[0])
+
+ return rv
+
+ def visit_ListNode(self, node):
+ rv = ["["]
+ rv.extend(", ".join(self.visit(child)[0] for child in node.children))
+ rv.append("]")
+ return ["".join(rv)]
+
+ def visit_ValueNode(self, node):
+ if "#" in node.data or (isinstance(node.parent, ListNode) and
+ ("," in node.data or "]" in node.data)):
+ if "\"" in node.data:
+ quote = "'"
+ else:
+ quote = "\""
+ else:
+ quote = ""
+ return [quote + escape(node.data, extras=quote) + quote]
+
+ def visit_AtomNode(self, node):
+ return [atom_names[node.data]]
+
+ def visit_ConditionalNode(self, node):
+ return ["if %s: %s" % tuple(self.visit(item)[0] for item in node.children)]
+
+ def visit_StringNode(self, node):
+ rv = ["\"%s\"" % escape(node.data, extras="\"")]
+ for child in node.children:
+ rv[0] += self.visit(child)[0]
+ return rv
+
+ def visit_NumberNode(self, node):
+ return [str(node.data)]
+
+ def visit_VariableNode(self, node):
+ rv = escape(node.data)
+ for child in node.children:
+ rv += self.visit(child)
+ return [rv]
+
+ def visit_IndexNode(self, node):
+ assert len(node.children) == 1
+ return ["[%s]" % self.visit(node.children[0])[0]]
+
+ def visit_UnaryExpressionNode(self, node):
+ children = []
+ for child in node.children:
+ child_str = self.visit(child)[0]
+ if isinstance(child, BinaryExpressionNode):
+ child_str = "(%s)" % child_str
+ children.append(child_str)
+ return [" ".join(children)]
+
+ def visit_BinaryExpressionNode(self, node):
+ assert len(node.children) == 3
+ children = []
+ for child_index in [1, 0, 2]:
+ child = node.children[child_index]
+ child_str = self.visit(child)[0]
+ if (isinstance(child, BinaryExpressionNode) and
+ precedence(node.children[0]) < precedence(child.children[0])):
+ child_str = "(%s)" % child_str
+ children.append(child_str)
+ return [" ".join(children)]
+
+ def visit_UnaryOperatorNode(self, node):
+ return [str(node.data)]
+
+ def visit_BinaryOperatorNode(self, node):
+ return [str(node.data)]
+
+
+def serialize(tree, *args, **kwargs):
+ s = ManifestSerializer(*args, **kwargs)
+ return s.serialize(tree)