mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-02 05:48:38 +09:00
140 lines
4.4 KiB
Python
140 lines
4.4 KiB
Python
# 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)
|