blob: de0dd516702ab8571c3319af2ad8bf36acc8938f [file] [log] [blame]
# Copyright 2018 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
from __future__ import print_function
from collections import OrderedDict
import json
import re
import sys
from typing import Any
description = ""
primitiveTypes = [
"integer",
"number",
"boolean",
"string",
"object",
"any",
"array",
"binary",
]
def assignType(
item: dict, type: str, is_array: bool = False, map_binary_to_string: bool = False
) -> None:
if is_array:
item["type"] = "array"
item["items"] = 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: dict, experimental: bool | Any, deprecated: bool | Any, name: str | Any = None
) -> OrderedDict[str, Any]:
result = 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: str, file_name: str, map_binary_to_string: bool = False
) -> OrderedDict[str, Any]:
protocol = OrderedDict()
protocol["version"] = 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:
# enum literal
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: str, file_name: str, map_binary_to_string: bool = False
) -> OrderedDict[str, Any] | Any:
if file_name.endswith(".pdl"):
return parse(data, file_name, map_binary_to_string)
return json.loads(data)