summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--build/json_schema_compile.gypi41
-rw-r--r--chrome/browser/extensions/api/dns/dns_api.cc22
-rw-r--r--chrome/browser/extensions/api/dns/dns_api.h3
-rw-r--r--chrome/browser/extensions/api/dns/dns_apitest.cc8
-rw-r--r--chrome/common/extensions/api/api.gyp4
-rw-r--r--chrome/common/extensions/api/experimental.dns.idl28
-rw-r--r--tools/json_schema_compiler/compiler.py16
-rw-r--r--tools/json_schema_compiler/idl_schema.py211
-rw-r--r--tools/json_schema_compiler/json_schema.py2
-rw-r--r--tools/json_schema_compiler/model.py3
10 files changed, 315 insertions, 23 deletions
diff --git a/build/json_schema_compile.gypi b/build/json_schema_compile.gypi
index 3abecf3..b44fe91 100644
--- a/build/json_schema_compile.gypi
+++ b/build/json_schema_compile.gypi
@@ -23,9 +23,48 @@
'<(api_gen_dir)/cc_generator.py',
'<(api_gen_dir)/code.py',
'<(api_gen_dir)/compiler.py',
+ '<(api_gen_dir)/cpp_type_generator.py',
'<(api_gen_dir)/cpp_util.py',
+ '<(api_gen_dir)/h_generator.py',
+ '<(api_gen_dir)/json_schema.py',
+ '<(api_gen_dir)/model.py',
+ '<(api_gen_dir)/util.cc',
+ '<(api_gen_dir)/util.h',
+ '<(api_gen_dir)/util_cc_helper.py',
+ # TODO(calamity): uncomment this when gyp on windows behaves like other
+ # platforms. List expansions of filepaths in inputs expand to different
+ # things.
+ # '<@(json_schema_files)',
+ ],
+ 'outputs': [
+ '<(SHARED_INTERMEDIATE_DIR)/<(cc_dir)/<(RULE_INPUT_ROOT).cc',
+ '<(SHARED_INTERMEDIATE_DIR)/<(cc_dir)/<(RULE_INPUT_ROOT).h',
+ ],
+ 'action': [
+ 'python',
+ '<(api_gen)',
+ '<(RULE_INPUT_PATH)',
+ '--root=<(DEPTH)',
+ '--destdir=<(SHARED_INTERMEDIATE_DIR)',
+ '--namespace=<(root_namespace)',
+ ],
+ 'message': 'Generating C++ code from <(RULE_INPUT_PATH) json files',
+ 'process_outputs_as_sources': 1,
+ },
+ {
+ 'rule_name': 'genapi_idl',
+ 'extension': 'idl',
+ 'inputs': [
+ '<(api_gen_dir)/any.cc',
+ '<(api_gen_dir)/any.h',
+ '<(api_gen_dir)/any_helper.py',
+ '<(api_gen_dir)/cc_generator.py',
+ '<(api_gen_dir)/code.py',
+ '<(api_gen_dir)/compiler.py',
'<(api_gen_dir)/cpp_type_generator.py',
+ '<(api_gen_dir)/cpp_util.py',
'<(api_gen_dir)/h_generator.py',
+ '<(api_gen_dir)/idl_schema.py',
'<(api_gen_dir)/model.py',
'<(api_gen_dir)/util.cc',
'<(api_gen_dir)/util.h',
@@ -47,7 +86,7 @@
'--destdir=<(SHARED_INTERMEDIATE_DIR)',
'--namespace=<(root_namespace)',
],
- 'message': 'Generating C++ code from <(RULE_INPUT_PATH) jsons',
+ 'message': 'Generating C++ code from <(RULE_INPUT_PATH) IDL files',
'process_outputs_as_sources': 1,
},
],
diff --git a/chrome/browser/extensions/api/dns/dns_api.cc b/chrome/browser/extensions/api/dns/dns_api.cc
index 2ddbd69..bc74483 100644
--- a/chrome/browser/extensions/api/dns/dns_api.cc
+++ b/chrome/browser/extensions/api/dns/dns_api.cc
@@ -8,18 +8,17 @@
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/io_thread.h"
+#include "chrome/common/extensions/api/experimental.dns.h"
#include "content/public/browser/browser_thread.h"
#include "net/base/host_port_pair.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
using content::BrowserThread;
+using namespace extensions::api::experimental;
namespace extensions {
-const char kAddressKey[] = "address";
-const char kResultCodeKey[] = "resultCode";
-
// static
net::HostResolver* DNSResolveFunction::host_resolver_for_testing;
@@ -42,7 +41,11 @@ void DNSResolveFunction::set_host_resolver_for_testing(
}
bool DNSResolveFunction::RunImpl() {
- EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &hostname_));
+ scoped_ptr<Resolve::Params> params(Resolve::Params::Create(*args_));
+ EXTENSION_FUNCTION_VALIDATE(params.get());
+
+ hostname_ = params->hostname;
+
bool result = BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&DNSResolveFunction::WorkOnIOThread, this));
@@ -77,14 +80,17 @@ void DNSResolveFunction::WorkOnIOThread() {
}
void DNSResolveFunction::OnLookupFinished(int resolve_result) {
- DictionaryValue* api_result = new DictionaryValue();
- api_result->SetInteger(kResultCodeKey, resolve_result);
+
+ scoped_ptr<ResolveCallbackResolveInfo> resolve_info(
+ new ResolveCallbackResolveInfo());
+ resolve_info->result_code = resolve_result;
if (resolve_result == net::OK) {
const struct addrinfo* head = addresses_->head();
DCHECK(head);
- api_result->SetString(kAddressKey, net::NetAddressToString(head));
+ resolve_info->address.reset(
+ new std::string(net::NetAddressToString(head)));
}
- result_.reset(api_result);
+ result_.reset(Resolve::Result::Create(*resolve_info));
response_ = true;
bool post_task_result = BrowserThread::PostTask(
diff --git a/chrome/browser/extensions/api/dns/dns_api.h b/chrome/browser/extensions/api/dns/dns_api.h
index 07c2c48..54a2002 100644
--- a/chrome/browser/extensions/api/dns/dns_api.h
+++ b/chrome/browser/extensions/api/dns/dns_api.h
@@ -19,9 +19,6 @@ class IOThread;
namespace extensions {
-extern const char kAddressKey[];
-extern const char kResultCodeKey[];
-
class DNSResolveFunction : public AsyncExtensionFunction {
public:
DNSResolveFunction();
diff --git a/chrome/browser/extensions/api/dns/dns_apitest.cc b/chrome/browser/extensions/api/dns/dns_apitest.cc
index d882aca..6614530 100644
--- a/chrome/browser/extensions/api/dns/dns_apitest.cc
+++ b/chrome/browser/extensions/api/dns/dns_apitest.cc
@@ -119,11 +119,11 @@ IN_PROC_BROWSER_TEST_F(DNSApiTest, DNSResolveIPLiteral) {
DictionaryValue *value = static_cast<DictionaryValue*>(result.get());
int resultCode;
- EXPECT_TRUE(value->GetInteger(extensions::kResultCodeKey, &resultCode));
+ EXPECT_TRUE(value->GetInteger("resultCode", &resultCode));
EXPECT_EQ(net::OK, resultCode);
std::string address;
- EXPECT_TRUE(value->GetString(extensions::kAddressKey, &address));
+ EXPECT_TRUE(value->GetString("address", &address));
EXPECT_EQ("127.0.0.1", address);
}
@@ -145,11 +145,11 @@ IN_PROC_BROWSER_TEST_F(DNSApiTest, DNSResolveHostname) {
DictionaryValue *value = static_cast<DictionaryValue*>(result.get());
int resultCode;
- EXPECT_TRUE(value->GetInteger(extensions::kResultCodeKey, &resultCode));
+ EXPECT_TRUE(value->GetInteger("resultCode", &resultCode));
EXPECT_EQ(net::OK, resultCode);
std::string address;
- EXPECT_TRUE(value->GetString(extensions::kAddressKey, &address));
+ EXPECT_TRUE(value->GetString("address", &address));
EXPECT_EQ(DNSApiTest::kAddress, address);
}
diff --git a/chrome/common/extensions/api/api.gyp b/chrome/common/extensions/api/api.gyp
index 896b31c..9c9d36c 100644
--- a/chrome/common/extensions/api/api.gyp
+++ b/chrome/common/extensions/api/api.gyp
@@ -9,6 +9,7 @@
'type': 'static_library',
'sources': [
'<@(json_schema_files)',
+ '<@(idl_schema_files)',
],
'includes': ['../../../../build/json_schema_compile.gypi'],
'variables': {
@@ -19,6 +20,9 @@
'tabs.json',
'windows.json',
],
+ 'idl_schema_files': [
+ 'experimental.dns.idl',
+ ],
'cc_dir': 'chrome/common/extensions/api',
'root_namespace': 'extensions::api',
},
diff --git a/chrome/common/extensions/api/experimental.dns.idl b/chrome/common/extensions/api/experimental.dns.idl
new file mode 100644
index 0000000..7fab5ad
--- /dev/null
+++ b/chrome/common/extensions/api/experimental.dns.idl
@@ -0,0 +1,28 @@
+// Copyright (c) 2012 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.
+
+// File-level comment to appease parser. Eventually this will not be necessary.
+
+[nodoc] namespace experimental.dns {
+
+ dictionary ResolveCallbackResolveInfo {
+ // The result code. Zero indicates success.
+ long resultCode;
+
+ // A string representing the IP address literal. Supplied only if resultCode
+ // indicates success. Note that we presently return only IPv4 addresses.
+ DOMString? address;
+ };
+
+ callback ResolveCallback = void (ResolveCallbackResolveInfo resolveInfo);
+
+ interface Functions {
+ // Resolves the given hostname or IP address literal.
+ // |hostname| : The hostname to resolve.
+ // |callback| : Called when the resolution operation completes.
+ static void resolve(DOMString hostname,
+ ResolveCallback callback);
+ };
+
+};
diff --git a/tools/json_schema_compiler/compiler.py b/tools/json_schema_compiler/compiler.py
index fb84a6c..f782f72 100644
--- a/tools/json_schema_compiler/compiler.py
+++ b/tools/json_schema_compiler/compiler.py
@@ -19,7 +19,8 @@ Usage example:
import cc_generator
import cpp_type_generator
import h_generator
-from json_schema import LoadJSON
+import idl_schema
+import json_schema
import model
import optparse
import os.path
@@ -47,17 +48,24 @@ if __name__ == '__main__':
api_model = model.Model()
-
# Actually generate for source file.
- api_defs = LoadJSON(schema)
+ schema_filename, schema_extension = os.path.splitext(schema)
+ if schema_extension == '.json':
+ api_defs = json_schema.Load(schema)
+ elif schema_extension == '.idl':
+ api_defs = idl_schema.Load(schema)
+ else:
+ sys.exit("Did not recognize file extension %s for schema %s" %
+ (schema_extension, schema))
for target_namespace in api_defs:
referenced_schemas = target_namespace.get('dependencies', [])
# Load type dependencies into the model.
+ # TODO(miket): do we need this in IDL?
for referenced_schema in referenced_schemas:
referenced_schema_path = os.path.join(
os.path.dirname(schema), referenced_schema + '.json')
- referenced_api_defs = LoadJSON(referenced_schema_path)
+ referenced_api_defs = json_schema.Load(referenced_schema_path)
for namespace in referenced_api_defs:
api_model.AddNamespace(namespace,
diff --git a/tools/json_schema_compiler/idl_schema.py b/tools/json_schema_compiler/idl_schema.py
new file mode 100644
index 0000000..d64f111
--- /dev/null
+++ b/tools/json_schema_compiler/idl_schema.py
@@ -0,0 +1,211 @@
+# Copyright (c) 2012 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.
+
+import os.path
+import sys
+
+# This file is a peer to json_schema.py. Each of these files understands a
+# certain format describing APIs (either JSON or IDL), reads files written
+# in that format into memory, and emits them as a Python array of objects
+# corresponding to those APIs, where the objects are formatted in a way that
+# the JSON schema compiler understands. compiler.py drives both idl_schema.py
+# and json_schema.py.
+
+# idl_parser expects to be able to import certain files in its directory,
+# so let's set things up the way it wants.
+idl_generators_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),
+ os.pardir, os.pardir, 'ppapi', 'generators')
+if idl_generators_path not in sys.path:
+ sys.path.insert(0, idl_generators_path)
+import idl_parser
+
+class Callspec(object):
+ '''
+ Given a Callspec node representing an IDL function declaration, converts into
+ a name/value pair where the value is a list of function parameters.
+ '''
+ def __init__(self, callspec_node):
+ self.node = callspec_node
+
+ def process(self, refs):
+ parameters = []
+ for node in self.node.children:
+ parameters.append(Param(node).process(refs))
+ return self.node.GetName(), parameters
+
+class Param(object):
+ '''
+ Given a Param node representing a function parameter, converts into a Python
+ dictionary that the JSON schema compiler expects to see.
+ '''
+ def __init__(self, param_node):
+ self.node = param_node
+
+ def process(self, refs):
+ return Typeref(self.node.GetProperty( 'TYPEREF'),
+ self.node,
+ { 'name': self.node.GetName() }).process(refs)
+
+class Dictionary(object):
+ '''
+ Given an IDL Dictionary node, converts into a Python dictionary that the JSON
+ schema compiler expects to see.
+ '''
+ def __init__(self, dictionary_node):
+ self.node = dictionary_node
+
+ def process(self, refs):
+ properties = {}
+ for node in self.node.children:
+ if node.cls == 'Member':
+ k, v = Member(node).process(refs)
+ properties[k] = v
+ return { 'id': self.node.GetName(),
+ 'properties': properties,
+ 'type': 'object' }
+
+class Member(object):
+ '''
+ Given an IDL dictionary or interface member, converts into a name/value pair
+ where the value is a Python dictionary that the JSON schema compiler expects
+ to see.
+ '''
+ def __init__(self, member_node):
+ self.node = member_node
+
+ def process(self, refs):
+ properties = {}
+ name = self.node.GetName()
+ if self.node.GetProperty('OPTIONAL'):
+ properties['optional'] = True
+ if self.node.GetProperty('nodoc'):
+ properties['nodoc'] = True
+ is_function = False
+ for node in self.node.children:
+ if node.cls == 'Callspec':
+ is_function = True
+ name, parameters = Callspec(node).process(refs)
+ properties['parameters'] = parameters
+ properties['name'] = name
+ if is_function:
+ properties['type'] = 'function'
+ else:
+ properties = Typeref(self.node.GetProperty('TYPEREF'),
+ self.node, properties).process(refs)
+ return name, properties
+
+class Typeref(object):
+ '''
+ Given a TYPEREF property representing the type of dictionary member or
+ function parameter, converts into a Python dictionary that the JSON schema
+ compiler expects to see.
+ '''
+ def __init__(self, typeref, parent, additional_properties={}):
+ self.typeref = typeref
+ self.parent = parent
+ self.additional_properties = additional_properties
+
+ def process(self, refs):
+ properties = self.additional_properties
+ if self.typeref == 'DOMString':
+ properties['type'] = 'string'
+ elif self.typeref == 'boolean':
+ properties['type'] = 'boolean'
+ elif self.typeref == 'long':
+ properties['type'] = 'integer'
+ elif self.typeref is None:
+ properties['type'] = 'function'
+ else:
+ try:
+ properties = refs[self.typeref]
+ except KeyError, e:
+ properties['$ref'] = self.typeref
+ return properties
+
+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):
+ self.namespace = namespace_node
+ self.nodoc = nodoc
+ self.events = []
+ self.functions = []
+ self.types = []
+ self.refs = {}
+
+ def process(self):
+ for node in self.namespace.children:
+ cls = node.cls
+ if cls == "Dictionary":
+ self.types.append(Dictionary(node).process(self.refs))
+ elif cls == "Callback":
+ k, v = Member(node).process(self.refs)
+ self.refs[k] = v
+ elif cls == "Interface" and node.GetName() == "Functions":
+ self.functions = self.process_interface(node)
+ elif cls == "Interface" and node.GetName() == "Events":
+ self.events = self.process_interface(node)
+ 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 }
+
+ def process_interface(self, node):
+ members = []
+ for member in node.children:
+ if member.cls == 'Member':
+ name, properties = Member(member).process(self.refs)
+ members.append(properties)
+ return members
+
+class IDLSchema(object):
+ '''
+ Given a list of IDLNodes and IDLAttributes, converts into a Python list
+ of api_defs that the JSON schema compiler expects to see.
+ '''
+
+ def __init__(self, idl):
+ self.idl = idl
+
+ def process(self):
+ namespaces = []
+ for node in self.idl:
+ nodoc = False
+ cls = node.cls
+ if cls == 'Namespace':
+ namespace = Namespace(node, nodoc)
+ namespaces.append(namespace.process())
+ elif cls == 'Copyright':
+ continue
+ elif cls == 'Comment':
+ continue
+ elif cls == 'ExtAttribute':
+ if node.name == 'nodoc':
+ nodoc = bool(node.value)
+ else:
+ continue
+ else:
+ sys.exit("Did not process %s %s" % (node.cls, node))
+ return namespaces
+
+def Load(filename):
+ '''
+ Given the filename of an IDL file, parses it and returns an equivalent
+ Python dictionary in a format that the JSON schema compiler expects to see.
+ '''
+
+ f = open(filename, 'r')
+ contents = f.read()
+ f.close()
+
+ idl = idl_parser.IDLParser().ParseData(contents, filename)
+ idl_schema = IDLSchema(idl)
+ return idl_schema.process()
diff --git a/tools/json_schema_compiler/json_schema.py b/tools/json_schema_compiler/json_schema.py
index aa192c0..779ec87 100644
--- a/tools/json_schema_compiler/json_schema.py
+++ b/tools/json_schema_compiler/json_schema.py
@@ -14,6 +14,6 @@ if third_party_path not in sys.path:
sys.path.insert(0, third_party_path)
import json_minify as minify
-def LoadJSON(filename):
+def Load(filename):
with open(filename, 'r') as handle:
return json.loads(minify.json_minify(handle.read()))
diff --git a/tools/json_schema_compiler/model.py b/tools/json_schema_compiler/model.py
index de392d2..cb569c6 100644
--- a/tools/json_schema_compiler/model.py
+++ b/tools/json_schema_compiler/model.py
@@ -90,7 +90,7 @@ class Type(object):
props = []
for prop_name, prop_json in json.get('properties', {}).items():
# TODO(calamity): support functions (callbacks) as properties. The model
- # doesn't support it yet because to h/cc generators don't -- this is
+ # doesn't support it yet because the h/cc generators don't -- this is
# because we'd need to hook it into a base::Callback or something.
#
# However, pragmatically it's not necessary to support them anyway, since
@@ -328,4 +328,3 @@ def GetModelHierarchy(entity):
entity = entity.parent
hierarchy.reverse()
return hierarchy
-