from __future__ import print_function
import collections
import json
import re
import sys
description = ""
primitiveTypes = [
"integer",
"number",
"boolean",
"string",
"object",
"any",
"array",
"binary",
]
def assignType(item, type, is_array=False, map_binary_to_string=False):
if is_array:
item["type"] = "array"
item["items"] = collections.OrderedDict()
assignType(item["items"], type, False, map_binary_to_string)
return
if type == "enum":
type = "string"
if map_binary_to_string and type == "binary":
type = "string"
if type in primitiveTypes:
item["type"] = type
else:
item["$ref"] = type
def createItem(d, experimental, deprecated, name=None):
result = collections.OrderedDict(d)
if name:
result["name"] = name
global description
if description:
result["description"] = description.strip()
if experimental:
result["experimental"] = True
if deprecated:
result["deprecated"] = True
return result
def parse(data, file_name, map_binary_to_string=False):
protocol = collections.OrderedDict()
protocol["version"] = collections.OrderedDict()
protocol["domains"] = []
domain = None
item = None
subitems = None
nukeDescription = False
global description
lines = data.split("\n")
for i in range(0, len(lines)):
if nukeDescription:
description = ""
nukeDescription = False
line = lines[i]
trimLine = line.strip()
if trimLine.startswith("#"):
if len(description):
description += "\n"
description += trimLine[2:]
continue
else:
nukeDescription = True
if len(trimLine) == 0:
continue
match = re.compile(r"^(experimental )?(deprecated )?domain (.*)").match(line)
if match:
domain = createItem(
{"domain": match.group(3)}, match.group(1), match.group(2)
)
protocol["domains"].append(domain)
continue
match = re.compile(r"^ depends on ([^\s]+)").match(line)
if match:
if "dependencies" not in domain:
domain["dependencies"] = []
domain["dependencies"].append(match.group(1))
continue
match = re.compile(
r"^ (experimental )?(deprecated )?type (.*) "
r"extends (array of )?([^\s]+)"
).match(line)
if match:
if "types" not in domain:
domain["types"] = []
item = createItem({"id": match.group(3)}, match.group(1), match.group(2))
assignType(item, match.group(5), match.group(4), map_binary_to_string)
domain["types"].append(item)
continue
match = re.compile(
r"^ (experimental )?(deprecated )?(command|event) (.*)"
).match(line)
if match:
list = []
if match.group(3) == "command":
if "commands" in domain:
list = domain["commands"]
else:
list = domain["commands"] = []
else:
if "events" in domain:
list = domain["events"]
else:
list = domain["events"] = []
item = createItem({}, match.group(1), match.group(2), match.group(4))
list.append(item)
continue
match = re.compile(
r"^ (experimental )?(deprecated )?(optional )?"
r"(array of )?([^\s]+) ([^\s]+)"
).match(line)
if match:
param = createItem({}, match.group(1), match.group(2), match.group(6))
if match.group(3):
param["optional"] = True
assignType(param, match.group(5), match.group(4), map_binary_to_string)
if match.group(5) == "enum":
enumliterals = param["enum"] = []
subitems.append(param)
continue
match = re.compile(r"^ (parameters|returns|properties)").match(line)
if match:
subitems = item[match.group(1)] = []
continue
match = re.compile(r"^ enum").match(line)
if match:
enumliterals = item["enum"] = []
continue
match = re.compile(r"^version").match(line)
if match:
continue
match = re.compile(r"^ major (\d+)").match(line)
if match:
protocol["version"]["major"] = match.group(1)
continue
match = re.compile(r"^ minor (\d+)").match(line)
if match:
protocol["version"]["minor"] = match.group(1)
continue
match = re.compile(r"^ redirect ([^\s]+)").match(line)
if match:
item["redirect"] = match.group(1)
continue
match = re.compile(r"^ ( )?[^\s]+$").match(line)
if match:
enumliterals.append(trimLine)
continue
print("Error in %s:%s, illegal token: \t%s" % (file_name, i, line))
sys.exit(1)
return protocol
def loads(data, file_name, map_binary_to_string=False):
if file_name.endswith(".pdl"):
return parse(data, file_name, map_binary_to_string)
return json.loads(data)