2018-07-17 17:24:20 +00:00
|
|
|
# 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.
|
|
|
|
|
2019-02-08 23:50:24 +00:00
|
|
|
from __future__ import print_function
|
2018-07-17 17:24:20 +00:00
|
|
|
import collections
|
|
|
|
import json
|
|
|
|
import os.path
|
|
|
|
import re
|
|
|
|
import sys
|
|
|
|
|
|
|
|
description = ''
|
|
|
|
|
|
|
|
|
2019-07-03 09:40:36 +00:00
|
|
|
primitiveTypes = ['integer', 'number', 'boolean', 'string', 'object',
|
|
|
|
'any', 'array', 'binary']
|
2018-07-17 17:24:20 +00:00
|
|
|
|
2018-10-24 00:14:53 +00:00
|
|
|
|
|
|
|
def assignType(item, type, is_array=False, map_binary_to_string=False):
|
2019-07-03 09:40:36 +00:00
|
|
|
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
|
2018-07-17 17:24:20 +00:00
|
|
|
|
|
|
|
|
|
|
|
def createItem(d, experimental, deprecated, name=None):
|
2019-07-03 09:40:36 +00:00
|
|
|
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
|
2018-07-17 17:24:20 +00:00
|
|
|
|
|
|
|
|
2018-10-24 00:14:53 +00:00
|
|
|
def parse(data, file_name, map_binary_to_string=False):
|
2019-07-03 09:40:36 +00:00
|
|
|
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']
|
2018-07-17 17:24:20 +00:00
|
|
|
else:
|
2019-07-03 09:40:36 +00:00
|
|
|
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
|
2018-07-17 17:24:20 +00:00
|
|
|
|
|
|
|
|
2018-10-24 00:14:53 +00:00
|
|
|
def loads(data, file_name, map_binary_to_string=False):
|
2019-07-03 09:40:36 +00:00
|
|
|
if file_name.endswith(".pdl"):
|
|
|
|
return parse(data, file_name, map_binary_to_string)
|
|
|
|
return json.loads(data)
|