• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2018 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5from __future__ import print_function
6import collections
7import json
8import os.path
9import re
10import sys
11
12description = ''
13
14
15primitiveTypes = ['integer', 'number', 'boolean', 'string', 'object', 'any', 'array', 'binary']
16
17
18def assignType(item, type, is_array=False, map_binary_to_string=False):
19    if is_array:
20        item['type'] = 'array'
21        item['items'] = collections.OrderedDict()
22        assignType(item['items'], type, False, map_binary_to_string)
23        return
24
25    if type == 'enum':
26        type = 'string'
27    if map_binary_to_string and type == 'binary':
28        type = 'string'
29    if type in primitiveTypes:
30        item['type'] = type
31    else:
32        item['$ref'] = type
33
34
35def createItem(d, experimental, deprecated, name=None):
36    result = collections.OrderedDict(d)
37    if name:
38        result['name'] = name
39    global description
40    if description:
41        result['description'] = description.strip()
42    if experimental:
43        result['experimental'] = True
44    if deprecated:
45        result['deprecated'] = True
46    return result
47
48
49def parse(data, file_name, map_binary_to_string=False):
50    protocol = collections.OrderedDict()
51    protocol['version'] = collections.OrderedDict()
52    protocol['domains'] = []
53    domain = None
54    item = None
55    subitems = None
56    nukeDescription = False
57    global description
58    lines = data.split('\n')
59    for i in range(0, len(lines)):
60        if nukeDescription:
61            description = ''
62            nukeDescription = False
63        line = lines[i]
64        trimLine = line.strip()
65
66        if trimLine.startswith('#'):
67            if len(description):
68              description += '\n'
69            description += trimLine[2:]
70            continue
71        else:
72            nukeDescription = True
73
74        if len(trimLine) == 0:
75            continue
76
77        match = re.compile(r'^(experimental )?(deprecated )?domain (.*)').match(line)
78        if match:
79            domain = createItem({'domain' : match.group(3)}, match.group(1), match.group(2))
80            protocol['domains'].append(domain)
81            continue
82
83        match = re.compile(r'^  depends on ([^\s]+)').match(line)
84        if match:
85            if 'dependencies' not in domain:
86                domain['dependencies'] = []
87            domain['dependencies'].append(match.group(1))
88            continue
89
90        match = re.compile(r'^  (experimental )?(deprecated )?type (.*) extends (array of )?([^\s]+)').match(line)
91        if match:
92            if 'types' not in domain:
93                domain['types'] = []
94            item = createItem({'id': match.group(3)}, match.group(1), match.group(2))
95            assignType(item, match.group(5), match.group(4), map_binary_to_string)
96            domain['types'].append(item)
97            continue
98
99        match = re.compile(r'^  (experimental )?(deprecated )?(command|event) (.*)').match(line)
100        if match:
101            list = []
102            if match.group(3) == 'command':
103                if 'commands' in domain:
104                    list = domain['commands']
105                else:
106                    list = domain['commands'] = []
107            else:
108                if 'events' in domain:
109                    list = domain['events']
110                else:
111                    list = domain['events'] = []
112
113            item = createItem({}, match.group(1), match.group(2), match.group(4))
114            list.append(item)
115            continue
116
117        match = re.compile(r'^      (experimental )?(deprecated )?(optional )?(array of )?([^\s]+) ([^\s]+)').match(line)
118        if match:
119            param = createItem({}, match.group(1), match.group(2), match.group(6))
120            if match.group(3):
121                param['optional'] = True
122            assignType(param, match.group(5), match.group(4), map_binary_to_string)
123            if match.group(5) == 'enum':
124                enumliterals = param['enum'] = []
125            subitems.append(param)
126            continue
127
128        match = re.compile(r'^    (parameters|returns|properties)').match(line)
129        if match:
130            subitems = item[match.group(1)] = []
131            continue
132
133        match = re.compile(r'^    enum').match(line)
134        if match:
135            enumliterals = item['enum'] = []
136            continue
137
138        match = re.compile(r'^version').match(line)
139        if match:
140            continue
141
142        match = re.compile(r'^  major (\d+)').match(line)
143        if match:
144            protocol['version']['major'] = match.group(1)
145            continue
146
147        match = re.compile(r'^  minor (\d+)').match(line)
148        if match:
149            protocol['version']['minor'] = match.group(1)
150            continue
151
152        match = re.compile(r'^    redirect ([^\s]+)').match(line)
153        if match:
154            item['redirect'] = match.group(1)
155            continue
156
157        match = re.compile(r'^      (  )?[^\s]+$').match(line)
158        if match:
159            # enum literal
160            enumliterals.append(trimLine)
161            continue
162
163        print('Error in %s:%s, illegal token: \t%s' % (file_name, i, line))
164        sys.exit(1)
165    return protocol
166
167
168def loads(data, file_name, map_binary_to_string=False):
169    if file_name.endswith(".pdl"):
170        return parse(data, file_name, map_binary_to_string)
171    return json.loads(data)
172