Switch the downloads API over to IDL/json_schema_compiler

Modify ppapi/generators/idl_parser.py to
0: not require a file-level comment (but generate the same parse tree structure),
1: actually support ext_attrs (modifiers) for dictionaries, and
2: support [ext_attr=(symbols|values)].

Modify json_schema_compiler to
0: use "base::Value" and any_helper.ANY_CLASS instead of Value and Any in order to support ArrayBuffers named |value| or |any|,
1: actually test that namespaces and dictionaries are sorted correctly,
2: fix HGenerator._FieldDependencyOrder(),
3: support [inline_doc] on dictionaries and enums,
4: support descriptions on enums,
5: support documentation_permissions_required,
6: support [legalValues=(values...)].

Review URL: https://chromiumcodereview.appspot.com/10639020

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@146201 0039d316-1c4b-4281-b951-d872f2087c98
parent df66ed60
......@@ -46,296 +46,162 @@ extern const char kNotImplementedError[];
} // namespace download_extension_errors
class DownloadsFunctionInterface {
public:
enum DownloadsFunctionName {
DOWNLOADS_FUNCTION_DOWNLOAD = 0,
DOWNLOADS_FUNCTION_SEARCH = 1,
DOWNLOADS_FUNCTION_PAUSE = 2,
DOWNLOADS_FUNCTION_RESUME = 3,
DOWNLOADS_FUNCTION_CANCEL = 4,
DOWNLOADS_FUNCTION_ERASE = 5,
DOWNLOADS_FUNCTION_SET_DESTINATION = 6,
DOWNLOADS_FUNCTION_ACCEPT_DANGER = 7,
DOWNLOADS_FUNCTION_SHOW = 8,
DOWNLOADS_FUNCTION_DRAG = 9,
DOWNLOADS_FUNCTION_GET_FILE_ICON = 10,
// Insert new values here, not at the beginning.
DOWNLOADS_FUNCTION_LAST
};
protected:
virtual ~DownloadsFunctionInterface() {}
// Return true if args_ is well-formed, otherwise set error_ and return false.
virtual bool ParseArgs() = 0;
// Implementation-specific logic. "Do the thing that you do." Should return
// true if the call succeeded and false otherwise.
virtual bool RunInternal() = 0;
// Which subclass is this.
virtual DownloadsFunctionName function() const = 0;
// Wrap ParseArgs(), RunInternal().
static bool RunImplImpl(DownloadsFunctionInterface* pimpl);
};
class SyncDownloadsFunction : public SyncExtensionFunction,
public DownloadsFunctionInterface {
protected:
explicit SyncDownloadsFunction(DownloadsFunctionName function);
virtual ~SyncDownloadsFunction();
// ExtensionFunction:
virtual bool RunImpl() OVERRIDE;
// DownloadsFunctionInterface:
virtual DownloadsFunctionName function() const OVERRIDE;
content::DownloadItem* GetActiveItem(int download_id);
private:
DownloadsFunctionName function_;
DISALLOW_COPY_AND_ASSIGN(SyncDownloadsFunction);
};
class AsyncDownloadsFunction : public AsyncExtensionFunction,
public DownloadsFunctionInterface {
protected:
explicit AsyncDownloadsFunction(DownloadsFunctionName function);
virtual ~AsyncDownloadsFunction();
// ExtensionFunction:
virtual bool RunImpl() OVERRIDE;
// DownloadsFunctionInterface:
virtual DownloadsFunctionName function() const OVERRIDE;
content::DownloadItem* GetActiveItem(int download_id);
private:
DownloadsFunctionName function_;
DISALLOW_COPY_AND_ASSIGN(AsyncDownloadsFunction);
};
class DownloadsDownloadFunction : public AsyncDownloadsFunction {
class DownloadsDownloadFunction : public AsyncExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION_NAME("downloads.download");
DownloadsDownloadFunction();
virtual bool RunImpl() OVERRIDE;
protected:
virtual ~DownloadsDownloadFunction();
// DownloadsFunctionInterface:
virtual bool ParseArgs() OVERRIDE;
virtual bool RunInternal() OVERRIDE;
private:
struct IOData {
public:
IOData();
~IOData();
GURL url;
string16 filename;
bool save_as;
base::ListValue* extra_headers;
std::string method;
std::string post_body;
content::ResourceDispatcherHost* rdh;
content::ResourceContext* resource_context;
int render_process_host_id;
int render_view_host_routing_id;
};
void BeginDownloadOnIOThread();
void OnStarted(content::DownloadId dl_id, net::Error error);
scoped_ptr<IOData> iodata_;
DISALLOW_COPY_AND_ASSIGN(DownloadsDownloadFunction);
};
class DownloadsSearchFunction : public SyncDownloadsFunction {
class DownloadsSearchFunction : public SyncExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION_NAME("downloads.search");
DownloadsSearchFunction();
virtual bool RunImpl() OVERRIDE;
protected:
virtual ~DownloadsSearchFunction();
// DownloadsFunctionInterface:
virtual bool ParseArgs() OVERRIDE;
virtual bool RunInternal() OVERRIDE;
private:
bool ParseOrderBy(const base::Value& order_by_value);
scoped_ptr<DownloadQuery> query_;
int get_id_;
bool has_get_id_;
DISALLOW_COPY_AND_ASSIGN(DownloadsSearchFunction);
};
class DownloadsPauseFunction : public SyncDownloadsFunction {
class DownloadsPauseFunction : public SyncExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION_NAME("downloads.pause");
DownloadsPauseFunction();
virtual bool RunImpl() OVERRIDE;
protected:
virtual ~DownloadsPauseFunction();
// DownloadsFunctionInterface:
virtual bool ParseArgs() OVERRIDE;
virtual bool RunInternal() OVERRIDE;
private:
int download_id_;
DISALLOW_COPY_AND_ASSIGN(DownloadsPauseFunction);
};
class DownloadsResumeFunction : public SyncDownloadsFunction {
class DownloadsResumeFunction : public SyncExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION_NAME("downloads.resume");
DownloadsResumeFunction();
virtual bool RunImpl() OVERRIDE;
protected:
virtual ~DownloadsResumeFunction();
// DownloadsFunctionInterface:
virtual bool ParseArgs() OVERRIDE;
virtual bool RunInternal() OVERRIDE;
private:
int download_id_;
DISALLOW_COPY_AND_ASSIGN(DownloadsResumeFunction);
};
class DownloadsCancelFunction : public SyncDownloadsFunction {
class DownloadsCancelFunction : public SyncExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION_NAME("downloads.cancel");
DownloadsCancelFunction();
virtual bool RunImpl() OVERRIDE;
protected:
virtual ~DownloadsCancelFunction();
// DownloadsFunctionInterface:
virtual bool ParseArgs() OVERRIDE;
virtual bool RunInternal() OVERRIDE;
private:
int download_id_;
DISALLOW_COPY_AND_ASSIGN(DownloadsCancelFunction);
};
class DownloadsEraseFunction : public AsyncDownloadsFunction {
class DownloadsEraseFunction : public AsyncExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION_NAME("downloads.erase");
DownloadsEraseFunction();
virtual bool RunImpl() OVERRIDE;
protected:
virtual ~DownloadsEraseFunction();
// DownloadsFunctionInterface:
virtual bool ParseArgs() OVERRIDE;
virtual bool RunInternal() OVERRIDE;
private:
DISALLOW_COPY_AND_ASSIGN(DownloadsEraseFunction);
};
class DownloadsSetDestinationFunction : public AsyncDownloadsFunction {
class DownloadsSetDestinationFunction : public AsyncExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION_NAME("downloads.setDestination");
DownloadsSetDestinationFunction();
virtual bool RunImpl() OVERRIDE;
protected:
virtual ~DownloadsSetDestinationFunction();
// DownloadsFunctionInterface:
virtual bool ParseArgs() OVERRIDE;
virtual bool RunInternal() OVERRIDE;
private:
DISALLOW_COPY_AND_ASSIGN(DownloadsSetDestinationFunction);
};
class DownloadsAcceptDangerFunction : public AsyncDownloadsFunction {
class DownloadsAcceptDangerFunction : public AsyncExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION_NAME("downloads.acceptDanger");
DownloadsAcceptDangerFunction();
virtual bool RunImpl() OVERRIDE;
protected:
virtual ~DownloadsAcceptDangerFunction();
// DownloadsFunctionInterface:
virtual bool ParseArgs() OVERRIDE;
virtual bool RunInternal() OVERRIDE;
private:
DISALLOW_COPY_AND_ASSIGN(DownloadsAcceptDangerFunction);
};
class DownloadsShowFunction : public AsyncDownloadsFunction {
class DownloadsShowFunction : public AsyncExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION_NAME("downloads.show");
DownloadsShowFunction();
virtual bool RunImpl() OVERRIDE;
protected:
virtual ~DownloadsShowFunction();
// DownloadsFunctionInterface:
virtual bool ParseArgs() OVERRIDE;
virtual bool RunInternal() OVERRIDE;
private:
DISALLOW_COPY_AND_ASSIGN(DownloadsShowFunction);
};
class DownloadsDragFunction : public AsyncDownloadsFunction {
class DownloadsOpenFunction : public AsyncExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION_NAME("downloads.drag");
DECLARE_EXTENSION_FUNCTION_NAME("downloads.open");
DownloadsOpenFunction();
virtual bool RunImpl() OVERRIDE;
protected:
virtual ~DownloadsOpenFunction();
private:
DISALLOW_COPY_AND_ASSIGN(DownloadsOpenFunction);
};
class DownloadsDragFunction : public AsyncExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION_NAME("downloads.drag");
DownloadsDragFunction();
virtual bool RunImpl() OVERRIDE;
protected:
virtual ~DownloadsDragFunction();
// DownloadsFunctionInterface:
virtual bool ParseArgs() OVERRIDE;
virtual bool RunInternal() OVERRIDE;
private:
DISALLOW_COPY_AND_ASSIGN(DownloadsDragFunction);
};
class DownloadsGetFileIconFunction : public AsyncDownloadsFunction {
class DownloadsGetFileIconFunction : public AsyncExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION_NAME("downloads.getFileIcon");
DownloadsGetFileIconFunction();
virtual bool RunImpl() OVERRIDE;
void SetIconExtractorForTesting(DownloadFileIconExtractor* extractor);
protected:
virtual ~DownloadsGetFileIconFunction();
// DownloadsFunctionInterface:
virtual bool ParseArgs() OVERRIDE;
virtual bool RunInternal() OVERRIDE;
private:
void OnIconURLExtracted(const std::string& url);
FilePath path_;
......
......@@ -13,7 +13,6 @@
#include "chrome/browser/extensions/api/context_menu/context_menu_api.h"
#include "chrome/browser/extensions/api/cookies/cookies_api.h"
#include "chrome/browser/extensions/api/declarative/declarative_api.h"
#include "chrome/browser/extensions/api/downloads/downloads_api.h"
#include "chrome/browser/extensions/api/extension_action/extension_browser_actions_api.h"
#include "chrome/browser/extensions/api/extension_action/extension_page_actions_api.h"
#include "chrome/browser/extensions/api/extension_action/extension_script_badge_api.h"
......@@ -451,19 +450,6 @@ void ExtensionFunctionRegistry::ResetFunctions() {
RegisterFunction<RemovePermissionsFunction>();
RegisterFunction<RequestPermissionsFunction>();
// Downloads
RegisterFunction<DownloadsDownloadFunction>();
RegisterFunction<DownloadsSearchFunction>();
RegisterFunction<DownloadsPauseFunction>();
RegisterFunction<DownloadsResumeFunction>();
RegisterFunction<DownloadsCancelFunction>();
RegisterFunction<DownloadsEraseFunction>();
RegisterFunction<DownloadsSetDestinationFunction>();
RegisterFunction<DownloadsAcceptDangerFunction>();
RegisterFunction<DownloadsShowFunction>();
RegisterFunction<DownloadsDragFunction>();
RegisterFunction<DownloadsGetFileIconFunction>();
// PageCapture
RegisterFunction<PageCaptureSaveAsMHTMLFunction>();
......
......@@ -32,6 +32,7 @@
'idl_schema_files': [
'alarms.idl',
'app_window.idl',
'downloads.idl',
'experimental_bluetooth.idl',
'experimental_discovery.idl',
'experimental_dns.idl',
......
This diff is collapsed.
This diff is collapsed.
......@@ -365,8 +365,6 @@ void ExtensionAPI::InitDefaultConfiguration() {
IDR_EXTENSION_API_JSON_DECLARATIVE_WEBREQUEST));
RegisterSchema("devtools", ReadFromResource(
IDR_EXTENSION_API_JSON_DEVTOOLS));
RegisterSchema("downloads", ReadFromResource(
IDR_EXTENSION_API_JSON_DOWNLOADS));
RegisterSchema("events", ReadFromResource(
IDR_EXTENSION_API_JSON_EVENTS));
RegisterSchema("experimental.accessibility", ReadFromResource(
......
......@@ -83,13 +83,13 @@ def parse_idl_file(path):
api_def = idl_schema.Load(path)
for namespace_def in api_def:
namespace_dot = namespace_def['namespace'] + '.'
types = dict((type_['id'], type_)
for type_ in namespace_def.get('types', [])
if type_)
inline_types = dict((type_['id'], type_)
for type_ in namespace_def.get('types', [])
if type_ and type_.get('inline_doc', False))
def SubstituteInlineDoc(prop):
prop_ref_type = prop.get('$ref', '')
type_obj = types.get(namespace_dot + prop_ref_type,
types.get(prop_ref_type, {}))
type_obj = inline_types.get(namespace_dot + prop_ref_type,
inline_types.get(prop_ref_type, {}))
if not type_obj:
return
if 'properties' in type_obj:
......@@ -113,17 +113,18 @@ def parse_idl_file(path):
if (prop.get('type', '') == 'array' and
prop.get('items', {}).get('$ref', '').startswith(namespace_dot)):
prop['items']['$ref'] = prop['items']['$ref'][len(namespace_dot):]
if prop.get('inline_doc', False):
del prop['inline_doc']
SubstituteInlineDoc(prop)
if 'items' in prop:
SubstituteInlineDoc(prop['items'])
SubstituteInlineDoc(prop)
if 'items' in prop:
SubstituteInlineDoc(prop['items'])
for type_ in namespace_def.get('types', []):
if type_.get('id', '').startswith(namespace_dot):
type_['id'] = type_['id'][len(namespace_dot):]
for prop in type_.get('properties', {}).values():
FixReferences(prop)
if type_.get('inline_doc', False):
del type_['inline_doc']
type_['nodoc'] = True
for func in namespace_def.get('functions', []):
for param in func.get('parameters', []):
FixReferences(param)
......
......@@ -150,7 +150,6 @@
"chrome.experimental.discovery.clearAllSuggestions": "experimental.discovery.html#method-clearAllSuggestions",
"chrome.experimental.discovery.removeSuggestion": "experimental.discovery.html#method-removeSuggestion",
"chrome.experimental.discovery.suggest": "experimental.discovery.html#method-suggest",
"chrome.experimental.dns.resolve": "experimental.dns.html#method-resolve",
"chrome.experimental.fontSettings.clearDefaultFixedFontSize": "experimental.fontSettings.html#method-clearDefaultFixedFontSize",
"chrome.experimental.fontSettings.clearDefaultFontSize": "experimental.fontSettings.html#method-clearDefaultFontSize",
"chrome.experimental.fontSettings.clearFont": "experimental.fontSettings.html#method-clearFont",
......@@ -170,10 +169,6 @@
"chrome.experimental.fontSettings.setMinimumFontSize": "experimental.fontSettings.html#method-setMinimumFontSize",
"chrome.experimental.identity.getAuthToken": "experimental.identity.html#method-getAuthToken",
"chrome.experimental.identity.launchWebAuthFlow": "experimental.identity.html#method-launchWebAuthFlow",
"chrome.experimental.idltest.getArrayBuffer": "experimental.idltest.html#method-getArrayBuffer",
"chrome.experimental.idltest.nocompileFunc": "experimental.idltest.html#method-nocompileFunc",
"chrome.experimental.idltest.sendArrayBuffer": "experimental.idltest.html#method-sendArrayBuffer",
"chrome.experimental.idltest.sendArrayBufferView": "experimental.idltest.html#method-sendArrayBufferView",
"chrome.experimental.infobars.show": "experimental.infobars.html#method-show",
"chrome.experimental.keybinding.onCommand": "experimental.keybinding.html#event-onCommand",
"chrome.experimental.mediaGalleries.assembleMediaFile": "experimental.mediaGalleries.html#method-assembleMediaFile",
......
......@@ -26,7 +26,6 @@
<include name="IDR_EXTENSION_API_JSON_EXPERIMENTAL_ACCESSIBILITY" file="extensions\api\experimental_accessibility.json" type="BINDATA" />
<include name="IDR_EXTENSION_API_JSON_EXPERIMENTAL_APP" file="extensions\api\experimental_app.json" type="BINDATA" />
<include name="IDR_EXTENSION_API_JSON_EXPERIMENTAL_BOOKMARKMANAGER" file="extensions\api\experimental_bookmark_manager.json" type="BINDATA" />
<include name="IDR_EXTENSION_API_JSON_DOWNLOADS" file="extensions\api\downloads.json" type="BINDATA" />
<include name="IDR_EXTENSION_API_JSON_EXPERIMENTAL_FONTSSETTINGS" file="extensions\api\experimental_font_settings.json" type="BINDATA" />
<include name="IDR_EXTENSION_API_JSON_EXPERIMENTAL_IDENTITY" file="extensions\api\experimental_identity.json" type="BINDATA" />
<include name="IDR_EXTENSION_API_JSON_EXPERIMENTAL_INFOBARS" file="extensions\api\experimental_infobars.json" type="BINDATA" />
......
......@@ -221,6 +221,15 @@ class IDLParser(IDLLexer):
p[0] = ListFromConcat(Copyright, Filedoc, p[3], p[4])
if self.parse_debug: DumpReduction('top', p)
def p_top_short(self, p):
"""top : COMMENT ext_attr_block top_list"""
Copyright = self.BuildComment('Copyright', p, 1)
Filedoc = IDLNode('Comment', self.lexobj.filename, p.lineno(2)-1,
p.lexpos(2)-1, [self.BuildAttribute('NAME', ''),
self.BuildAttribute('FORM', 'cc')])
p[0] = ListFromConcat(Copyright, Filedoc, p[2], p[3])
if self.parse_debug: DumpReduction('top', p)
# Build a list of top level items.
def p_top_list(self, p):
"""top_list : callback_decl top_list
......@@ -289,11 +298,11 @@ class IDLParser(IDLLexer):
#
# Dictionary
#
# A dictionary contains is a named list of optional and required members.
# A dictionary is a named list of optional and required members.
#
def p_dictionary_block(self, p):
"""dictionary_block : modifiers DICTIONARY SYMBOL '{' struct_list '}' ';'"""
p[0] = self.BuildNamed('Dictionary', p, 3, ListFromConcat(p[5]))
p[0] = self.BuildNamed('Dictionary', p, 3, ListFromConcat(p[1], p[5]))
#
# Callback
......@@ -370,6 +379,29 @@ class IDLParser(IDLLexer):
p[0] = ListFromConcat(self.BuildAttribute(p[1], 'True'), p[2])
if self.parse_debug: DumpReduction('ext_attribute_list', p)
def p_ext_attr_list_values(self, p):
"""ext_attr_list : SYMBOL '=' '(' values ')' ext_attr_cont
| SYMBOL '=' '(' symbols ')' ext_attr_cont"""
p[0] = ListFromConcat(self.BuildAttribute(p[1], p[4]), p[6])
def p_values(self, p):
"""values : value values_cont"""
p[0] = ListFromConcat(p[1], p[2])
def p_symbols(self, p):
"""symbols : SYMBOL symbols_cont"""
p[0] = ListFromConcat(p[1], p[2])
def p_symbols_cont(self, p):
"""symbols_cont : ',' SYMBOL symbols_cont
| """
if len(p) > 1: p[0] = ListFromConcat(p[2], p[3])
def p_values_cont(self, p):
"""values_cont : ',' value values_cont
| """
if len(p) > 1: p[0] = ListFromConcat(p[2], p[3])
def p_ext_attr_cont(self, p):
"""ext_attr_cont : ',' ext_attr_list
|"""
......@@ -555,7 +587,7 @@ class IDLParser(IDLLexer):
def p_param_item(self, p):
"""param_item : modifiers optional SYMBOL arrays identifier"""
typeref = self.BuildAttribute('TYPEREF', p[3])
children = ListFromConcat(p[1],p[2], typeref, p[4])
children = ListFromConcat(p[1], p[2], typeref, p[4])
p[0] = self.BuildNamed('Param', p, 5, children)
if self.parse_debug: DumpReduction('param_item', p)
......
This diff is collapsed.
......@@ -7,7 +7,6 @@ from model import PropertyType
import any_helper
import cpp_util
import schema_util
import string
class CppTypeGenerator(object):
"""Manages the types of properties and provides utilities for getting the
......@@ -191,9 +190,10 @@ class CppTypeGenerator(object):
c.Append('typedef std::string %s;' % type_name)
elif namespace.types[type_].type_ == PropertyType.ARRAY:
c.Append('typedef std::vector<%(item_type)s> %(name)s;')
c.Substitute({'name': type_name, 'item_type':
self.GetType(namespace.types[type_].item_type,
wrap_optional=True)})
c.Substitute({
'name': type_name,
'item_type': self.GetType(namespace.types[type_].item_type,
wrap_optional=True)})
else:
c.Append('struct %s;' % type_name)
c.Append('}')
......
......@@ -59,12 +59,14 @@ class CppTypeGeneratorTest(unittest.TestCase):
def testGenerateIncludesAndForwardDeclarationsMultipleTypes(self):
m = model.Model()
self.tabs_json[0]['types'].append(self.permissions_json[0]['types'][0])
tabs_namespace = m.AddNamespace(self.tabs_json[0],
'path/to/tabs.json')
self.windows_json[0]['functions'].append(
self.permissions_json[0]['functions'][1])
# Insert 'windows' before 'tabs' in order to test that they are sorted
# properly.
windows = m.AddNamespace(self.windows_json[0],
'path/to/windows.json')
tabs_namespace = m.AddNamespace(self.tabs_json[0],
'path/to/tabs.json')
manager = CppTypeGenerator('', windows, self.windows.unix_name)
manager.AddNamespace(tabs_namespace, self.tabs.unix_name)
self.assertEquals('#include "path/to/tabs.h"',
......@@ -81,16 +83,18 @@ class CppTypeGeneratorTest(unittest.TestCase):
def testGenerateIncludesAndForwardDeclarationsDependencies(self):
m = model.Model()
browser_action_namespace = m.AddNamespace(self.browser_action_json[0],
'path/to/browser_action.json')
# Insert 'font_settings' before 'browser_action' in order to test that
# CppTypeGenerator sorts them properly.
font_settings_namespace = m.AddNamespace(self.font_settings_json[0],
'path/to/font_settings.json')
browser_action_namespace = m.AddNamespace(self.browser_action_json[0],
'path/to/browser_action.json')
manager = CppTypeGenerator('', self.dependency_tester,
self.dependency_tester.unix_name)
manager.AddNamespace(browser_action_namespace,
self.browser_action.unix_name)
manager.AddNamespace(font_settings_namespace,
self.font_settings.unix_name)
manager.AddNamespace(browser_action_namespace,
self.browser_action.unix_name)
self.assertEquals('#include "path/to/browser_action.h"\n'
'#include "path/to/font_settings.h"',
manager.GenerateIncludes().Render())
......
......@@ -5,8 +5,6 @@
from code import Code
from model import PropertyType
import cpp_util
import model
import os
import schema_util
class HGenerator(object):
......@@ -110,7 +108,8 @@ class HGenerator(object):
raise ValueError("Illegal circular dependency via cycle " +
", ".join(map(lambda x: x.name, path + [type_])))
for prop in type_.properties.values():
if not prop.optional and prop.type_ == PropertyType.REF:
if (prop.type_ == PropertyType.REF and
schema_util.GetNamespace(prop.ref_type) == self._namespace.name):
ExpandType(path + [type_], self._namespace.types[prop.ref_type])
if not type_ in dependency_order:
dependency_order.append(type_)
......@@ -177,7 +176,6 @@ class HGenerator(object):
if type_.description:
c.Comment(type_.description)
c.Append('typedef std::string %(classname)s;')
c.Substitute({'classname': classname})
else:
if type_.description:
c.Comment(type_.description)
......@@ -189,18 +187,18 @@ class HGenerator(object):
.Concat(self._GenerateFields(type_.properties.values()))
)
if type_.from_json:
(c.Comment('Populates a %s object from a Value. Returns'
(c.Comment('Populates a %s object from a base::Value. Returns'
' whether |out| was successfully populated.' % classname)
.Append(
'static bool Populate(const Value& value, %(classname)s* out);')
.Append('static bool Populate(const base::Value& value, '
'%(classname)s* out);')
.Append()
)
if type_.from_client:
(c.Comment('Returns a new DictionaryValue representing the'
(c.Comment('Returns a new base::DictionaryValue representing the'
' serialized form of this %s object. Passes '
'ownership to caller.' % classname)
.Append('scoped_ptr<DictionaryValue> ToValue() const;')
.Append('scoped_ptr<base::DictionaryValue> ToValue() const;')
)
(c.Eblock()
......@@ -238,7 +236,8 @@ class HGenerator(object):
.Concat(self._GenerateFields(function.params))
.Append('~Params();')
.Append()
.Append('static scoped_ptr<Params> Create(const ListValue& args);')
.Append('static scoped_ptr<Params> Create('
'const base::ListValue& args);')
.Eblock()
.Sblock(' private:')
.Append('Params();')
......@@ -273,7 +272,7 @@ class HGenerator(object):
enum_name,
prop,
prop.enum_values))
c.Append('static scoped_ptr<Value> CreateEnumValue(%s %s);' %
c.Append('static scoped_ptr<base::Value> CreateEnumValue(%s %s);' %
(enum_name, prop.unix_name))
return c
......@@ -285,7 +284,7 @@ class HGenerator(object):
c.Sblock('namespace Result {')
params = function.callback.params
if not params:
c.Append('Value* Create();')
c.Append('base::Value* Create();')
else:
c.Concat(self._GeneratePropertyStructures(params))
......@@ -297,11 +296,12 @@ class HGenerator(object):
if param.description:
c.Comment(param.description)
if param.type_ == PropertyType.ANY:
c.Comment("Value* Result::Create(Value*) not generated "
c.Comment("base::Value* Result::Create(base::Value*) not generated "
"because it's redundant.")
continue
c.Append('Value* Create(const %s);' % cpp_util.GetParameterDeclaration(
param, self._cpp_type_generator.GetType(param)))
c.Append('base::Value* Create(const %s);' %
cpp_util.GetParameterDeclaration(
param, self._cpp_type_generator.GetType(param)))
c.Eblock('};')
return c
......@@ -55,7 +55,7 @@ def ProcessComment(comment):
# Escape double quotes.
comment = comment.replace('"', '\\"');
# Find all the parameter comments of the form "|name|: comment".
# Find all the parameter comments of the form '|name|: comment'.
parameter_starts = list(re.finditer(r'\n *\|([^|]*)\| *: *', comment))
# Get the parent comment (everything before the first parameter comment.
......@@ -104,9 +104,9 @@ class Param(object):
self.node = param_node
def process(self, callbacks):
return Typeref(self.node.GetProperty( 'TYPEREF'),
return Typeref(self.node.GetProperty('TYPEREF'),
self.node,
{ 'name': self.node.GetName() }).process(callbacks)
{'name': self.node.GetName()}).process(callbacks)
class Dictionary(object):
'''
......@@ -122,30 +122,12 @@ class Dictionary(object):
if node.cls == 'Member':
k, v = Member(node).process(callbacks)
properties[k] = v
return { 'id': self.node.GetName(),
'properties': properties,
'type': 'object' }
class Enum(object):
'''
Given an IDL Enum node, converts into a Python dictionary that the JSON
schema compiler expects to see.
'''
def __init__(self, enum_node):
self.node = enum_node
def process(self, callbacks):
enum = []
for node in self.node.children:
if node.cls == 'EnumItem':
name = node.GetName()
enum.append(name)
else:
sys.exit("Did not process %s %s" % (node.cls, node))
return { "id" : self.node.GetName(),
'enum': enum,
'type': 'string' }
result = {'id': self.node.GetName(),
'properties': properties,
'type': 'object'}
if self.node.GetProperty('inline_doc'):
result['inline_doc'] = True
return result
class Member(object):
......@@ -169,8 +151,7 @@ class Member(object):
if node.cls == 'Comment':
(parent_comment, parameter_comments) = ProcessComment(node.GetName())
properties['description'] = parent_comment
for node in self.node.children:
if node.cls == 'Callspec':
elif node.cls == 'Callspec':
is_function = True
name, parameters = Callspec(node, parameter_comments).process(callbacks)
properties['parameters'] = parameters
......@@ -180,6 +161,13 @@ class Member(object):
else:
properties = Typeref(self.node.GetProperty('TYPEREF'),
self.node, properties).process(callbacks)
enum_values = self.node.GetProperty('legalValues')
if enum_values:
if properties['type'] == 'integer':
enum_values = map(int, enum_values)
elif properties['type'] == 'double':
enum_values = map(float, enum_values)
properties['enum'] = enum_values
return name, properties
class Typeref(object):
......@@ -240,42 +228,70 @@ class Typeref(object):
return result
class Enum(object):
'''
Given an IDL Enum node, converts into a Python dictionary that the JSON
schema compiler expects to see.
'''
def __init__(self, enum_node):
self.node = enum_node
self.description = ''
def process(self, callbacks):
enum = []
for node in self.node.children:
if node.cls == 'EnumItem':
enum.append(node.GetName())
elif node.cls == 'Comment':
self.description = ProcessComment(node.GetName())[0]
else:
sys.exit('Did not process %s %s' % (node.cls, node))
result = {'id' : self.node.GetName(),
'description': self.description,
'type': 'string',
'enum': enum}
if self.node.GetProperty('inline_doc'):
result['inline_doc'] = True
return result
class Namespace(object):
'''
Given an IDLNode representing an IDL namespace, converts into a Python
dictionary that the JSON schema compiler expects to see.
'''
def __init__(self, namespace_node, nodoc=False):
def __init__(self, namespace_node, nodoc=False, permissions=None):
self.namespace = namespace_node
self.nodoc = nodoc
self.events = []
self.functions = []
self.types = []
self.callbacks = {}
self.permissions = permissions or []
def process(self):
for node in self.namespace.children:
cls = node.cls
if cls == "Dictionary":
if node.cls == 'Dictionary':
self.types.append(Dictionary(node).process(self.callbacks))
elif cls == "Callback":
elif node.cls == 'Callback':
k, v = Member(node).process(self.callbacks)
self.callbacks[k] = v
elif cls == "Interface" and node.GetName() == "Functions":
elif node.cls == 'Interface' and node.GetName() == 'Functions':
self.functions = self.process_interface(node)
elif cls == "Interface" and node.GetName() == "Events":
elif node.cls == 'Interface' and node.GetName() == 'Events':
self.events = self.process_interface(node)
elif cls == "Enum":
elif node.cls == 'Enum':
self.types.append(Enum(node).process(self.callbacks))
else:
sys.exit("Did not process %s %s" % (node.cls, node))
return { 'events': self.events,
'functions': self.functions,
'types': self.types,
'namespace': self.namespace.GetName(),
'nodoc': self.nodoc }
sys.exit('Did not process %s %s' % (node.cls, node))
return {'namespace': self.namespace.GetName(),
'nodoc': self.nodoc,
'documentation_permissions_required': self.permissions,
'types': self.types,
'functions': self.functions,
'events': self.events}
def process_interface(self, node):
members = []
......@@ -296,23 +312,25 @@ class IDLSchema(object):
def process(self):
namespaces = []
nodoc = False
permissions = None
for node in self.idl:
nodoc = False
cls = node.cls
if cls == 'Namespace':
namespace = Namespace(node, nodoc)
if node.cls == 'Namespace':
namespace = Namespace(node, nodoc, permissions)
namespaces.append(namespace.process())
elif cls == 'Copyright':
elif node.cls == 'Copyright':
continue
elif cls == 'Comment':
elif node.cls == 'Comment':
continue
elif cls == 'ExtAttribute':
elif node.cls == 'ExtAttribute':
if node.name == 'nodoc':
nodoc = bool(node.value)
elif node.name == 'permissions':
permission = node.value.split(',')
else:
continue
else:
sys.exit("Did not process %s %s" % (node.cls, node))
sys.exit('Did not process %s %s' % (node.cls, node))
schema_util.PrefixSchemasWithNamespace(namespaces)
return namespaces
......
......@@ -56,11 +56,18 @@ class IdlSchemaTest(unittest.TestCase):
'parameters':[{'type':'integer', 'name':'x'}]}}]
self.assertEquals(expected, getParams(schema, 'whatever'))
def testLegalValues(self):
self.assertEquals({
'x': {'name': 'x', 'type': 'integer', 'enum': [1,2],
'description': 'This comment tests \\\"double-quotes\\\".'},
'y': {'name': 'y', 'type': 'string'}},
getType(self.idl_basics, 'idl_basics.MyType1')['properties'])
def testEnum(self):
schema = self.idl_basics
expected = {'enum': ['name1', 'name2'],
expected = {'enum': ['name1', 'name2'], 'description': 'Enum description',
'type': 'string', 'id': 'idl_basics.EnumType'}
self.assertEquals(expected, getType(schema, 'idl_basics.EnumType'))
self.assertEquals(expected, getType(schema, expected['id']))
expected = [{'name':'type', '$ref':'idl_basics.EnumType'},
{'type':'function', 'name':'Callback5',
......
......@@ -193,7 +193,9 @@ class Property(object):
elif '$ref' in json:
self.ref_type = json['$ref']
self.type_ = PropertyType.REF
elif 'enum' in json:
elif 'enum' in json and json.get('type') == 'string':
# Non-string enums (as in the case of [legalValues=(1,2)]) should fall
# through to the next elif.
self.enum_values = []
for value in json['enum']:
self.enum_values.append(value)
......
......@@ -4,6 +4,10 @@
"""Utilies for the processing of schema python structures.
"""
def GetNamespace(ref_type):
if '.' in ref_type:
return ref_type[:ref_type.rindex('.')]
def StripSchemaNamespace(s):
last_dot = s.rfind('.')
if not last_dot == -1:
......
......@@ -5,13 +5,15 @@
// Tests a variety of basic API definition features.
namespace idl_basics {
// Enum description
enum EnumType {
name1,
name2
};
dictionary MyType1 {
long x; // This comment tests "double-quotes".
// This comment tests "double-quotes".
[legalValues=(1,2)] long x;
DOMString y;
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment