From fe4af314121eff21f735f8206e4f84cdf507f435 Mon Sep 17 00:00:00 2001 From: Hwanseung Lee Date: Tue, 7 Nov 2017 22:03:13 +0900 Subject: [PATCH 1/3] dictionary Signed-off-by: Hwanseung Lee --- generator/main.ts | 23 +++++++++++ generator/parser/dictionary_types.ts | 41 +++++++++++++++++++ generator/parser/idl_definition.ts | 4 ++ generator/parser/idl_definition_factory.ts | 6 +++ generator/parser/idl_dictionary.ts | 46 ++++++++++++++++++++++ generator/parser/idl_interface.ts | 3 ++ template/dictionary_types.njk | 38 ++++++++++++++++++ template/interface_cpp.njk | 3 ++ template/native_dictionary_traits.njk | 0 test/interface_dictionary.test.ts | 30 ++++++++++++++ test/test_interface.cc | 4 ++ test/test_interface.h | 5 +++ test/test_interface.idl | 9 ++++- 13 files changed, 211 insertions(+), 1 deletion(-) create mode 100644 generator/parser/dictionary_types.ts create mode 100644 generator/parser/idl_dictionary.ts create mode 100644 template/dictionary_types.njk create mode 100644 template/native_dictionary_traits.njk create mode 100644 test/interface_dictionary.test.ts diff --git a/generator/main.ts b/generator/main.ts index ee23399..97add8b 100644 --- a/generator/main.ts +++ b/generator/main.ts @@ -20,8 +20,10 @@ import * as nunjucks from 'nunjucks'; import * as path from 'path'; import * as file from './base/file'; +import DictionaryTypes from './parser/dictionary_types'; import EnumTypes from './parser/enum_types'; import IDLDefinition from './parser/idl_definition'; +import IDLDictionary from './parser/idl_dictionary'; import IDLEnum from './parser/idl_enum'; import IDLInterface from './parser/idl_interface'; import Parser from './parser/parser'; @@ -76,6 +78,7 @@ async function generateInterface( // TODO(hwansueng): This function should be improved. async function postProcessing(definitions: IDLDefinition[]) { let enum_types: EnumTypes = new EnumTypes(definitions); + let dict_types: DictionaryTypes = new DictionaryTypes(definitions); for (const definition of definitions) { if (definition.isIDLInterface()) { @@ -84,6 +87,7 @@ async function postProcessing(definitions: IDLDefinition[]) { if (member.arguments != null) { for (let args of member.arguments) { args.enum = enum_types.isEnumType(args.type); + args.dictionary = dict_types.isDictionaryType(args.type); } } } @@ -91,6 +95,24 @@ async function postProcessing(definitions: IDLDefinition[]) { } } +async function generateDictionaryType( + env: nunjucks.Environment, output_path: string, + definitions: IDLDefinition[]) { + const [dictionary_tmpl] = await Promise.all( + [file.read(path.resolve(TEMPLATE_DIR, 'dictionary_types.njk'))]); + + definitions.forEach(async (definition) => { + if (definition.isIDLDictionary()) { + const dictionary_file_path = path.resolve( + output_path, + definition.idl_dir_name + '/' + + changeCase.snakeCase(definition.name) + '.h'); + await file.write( + dictionary_file_path, env.renderString(dictionary_tmpl, definition)); + } + }); +} + async function main([root_dir, out_dir, ...idl_files]) { // We expect that current working directory will be $BACARDI_PATH. But it // might not be in Windows platform. So, we should resolve the path here. @@ -107,6 +129,7 @@ async function main([root_dir, out_dir, ...idl_files]) { let definitions: IDLDefinition[] = await Parser.parse(await reader.readAll(relative_idl_files)); + await generateDictionaryType(env, out_dir, definitions); await postProcessing(definitions); await generateInterface(env, out_dir, definitions); await generateBacardi(env, out_dir, definitions); diff --git a/generator/parser/dictionary_types.ts b/generator/parser/dictionary_types.ts new file mode 100644 index 0000000..fc15a23 --- /dev/null +++ b/generator/parser/dictionary_types.ts @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2017 The Bacardi Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import IDLDefinition from './idl_definition'; +import IDLDictionary from './idl_dictionary'; + + +export default class DictionaryTypes { + dictionaries: IDLDictionary[]; + + constructor(definitions: IDLDefinition[]) { + this.dictionaries = []; + definitions.forEach((definition) => { + if (definition.isIDLDictionary()) { + this.dictionaries.push(definition as IDLDictionary); + } + }); + } + + public isDictionaryType(source: string): IDLDictionary { + for (const item of this.dictionaries) { + if (item.name == source) { + return item; + } + } + return null; + } +} diff --git a/generator/parser/idl_definition.ts b/generator/parser/idl_definition.ts index fd77eff..b0cb064 100644 --- a/generator/parser/idl_definition.ts +++ b/generator/parser/idl_definition.ts @@ -36,4 +36,8 @@ export default abstract class IDLDefinition { public isIDLEnum(): boolean { return this.raw_idl_definition_info['type'] == 'enum'; } + + public isIDLDictionary(): boolean { + return this.raw_idl_definition_info['type'] == 'dictionary'; + } } diff --git a/generator/parser/idl_definition_factory.ts b/generator/parser/idl_definition_factory.ts index 48bdf07..e7c1902 100644 --- a/generator/parser/idl_definition_factory.ts +++ b/generator/parser/idl_definition_factory.ts @@ -15,6 +15,7 @@ */ import IDLDefinition from './idl_definition'; +import IDLDictionary from './idl_dictionary'; import IDLEnum from './idl_enum'; import IDLInterface from './idl_interface'; @@ -24,6 +25,8 @@ export default class IDLDefinitionFactory { return new IDLInterface(raw_idl_definition_info); } else if (this.isIDLEnum(raw_idl_definition_info)) { return new IDLEnum(raw_idl_definition_info); + } else if (this.isIDLDictionary(raw_idl_definition_info)) { + return new IDLDictionary(raw_idl_definition_info); } return null; @@ -35,4 +38,7 @@ export default class IDLDefinitionFactory { private static isIDLEnum(raw_idl_definition_info: {}): boolean { return raw_idl_definition_info['type'] == 'enum'; } + private static isIDLDictionary(raw_idl_definition_info: {}): boolean { + return raw_idl_definition_info['type'] == 'dictionary'; + } } diff --git a/generator/parser/idl_dictionary.ts b/generator/parser/idl_dictionary.ts new file mode 100644 index 0000000..e979a71 --- /dev/null +++ b/generator/parser/idl_dictionary.ts @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2017 The Bacardi Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import IDLDefinition from './idl_definition'; +import IDLIdentifier from './idl_identifier'; + +class DictionaryMember implements IDLIdentifier { + readonly type: string; + readonly name: string; + + constructor(raw_member_info: {}) { + this.type = raw_member_info['idlType']['idlType']; + this.name = raw_member_info['name']; + } +} + +export default class IDLDictionary extends IDLDefinition { + members: DictionaryMember[]; + + constructor(raw_idl_dic_info: {}) { + super(raw_idl_dic_info['name'], raw_idl_dic_info); + + this.members = []; + + raw_idl_dic_info['members'].forEach(raw_member_info => { + this.members.push(new DictionaryMember(raw_member_info)); + }); + } + + render(): void { + // TODO(zino): We should implement this function. + } +} diff --git a/generator/parser/idl_interface.ts b/generator/parser/idl_interface.ts index 6566d6a..1b506cd 100644 --- a/generator/parser/idl_interface.ts +++ b/generator/parser/idl_interface.ts @@ -15,6 +15,7 @@ */ import IDLDefinition from './idl_definition'; +import IDLDictionary from './idl_dictionary'; import IDLEnum from './idl_enum'; import IDLIdentifier from './idl_identifier'; @@ -24,11 +25,13 @@ class Argument implements IDLIdentifier { readonly type: string; readonly name: string; enum?: IDLEnum; + dictionary?: IDLDictionary; constructor(raw_argument_info: {}) { this.type = raw_argument_info['idlType']['idlType']; this.name = raw_argument_info['name']; this.enum = null; + this.dictionary = null; } } diff --git a/template/dictionary_types.njk b/template/dictionary_types.njk new file mode 100644 index 0000000..4315f78 --- /dev/null +++ b/template/dictionary_types.njk @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2017 The Bacardi Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef GEN_DICTIONARY_{{name | snakecase | upper}}_H_ +#define GEN_DICTIONARY_{{name | snakecase | upper}}_H_ + +class {{name}} { +public: +{% for member in members %} + bool has{{member.name | pascalcase}}() const { return has_{{member.name}}_; } + {{member.type}} {{member.name}}() const { + return {{member.name}}_; + } + inline void set{{member.name | pascalcase}}({{member.type}}); +{% endfor %} +private: +{% for member in members %} + bool has_{{member.name}}_ = false; +{% endfor %} +{% for member in members %} + {{member.type}} {{member.name}}_; +{% endfor %} +}; + +#endif // GEN_DICTIONARY_{{name | snakecase | upper}}_H_ diff --git a/template/interface_cpp.njk b/template/interface_cpp.njk index dbbb842..a9a8b7b 100644 --- a/template/interface_cpp.njk +++ b/template/interface_cpp.njk @@ -20,6 +20,9 @@ if (!EnumValidator::isValildEnum({{argument.name}}, enum_value_set)) { .ThrowAsJavaScriptException(); return{% if not is_constructor %} Napi::Value(){% endif %}; } +{% elif argument.dictionary %} +{{argument.type | pascalcase}} {{argument.name}}; +//FIXME(hwanseung): Make NatvieTypeTraits for dictionary types. {% else %} auto {{argument.name}} = NativeTypeTraits::NativeValue(info.Env(), info[{{loop.index0}}]); diff --git a/template/native_dictionary_traits.njk b/template/native_dictionary_traits.njk new file mode 100644 index 0000000..e69de29 diff --git a/test/interface_dictionary.test.ts b/test/interface_dictionary.test.ts new file mode 100644 index 0000000..fe6f924 --- /dev/null +++ b/test/interface_dictionary.test.ts @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2017 The Bacardi Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as bindings from 'bindings'; + +const bacardi = bindings('bacardi.node'); + +test( + 'Test call function which take dictionaries type as parameter', + async () => { + let test_interface = new bacardi.TestInterface(); + + var testDict = {a: 10}; + test_interface.voidMethodTestDictionaryArg(testDict); + expect(bacardi.TestInterface.getLastCallInfo()) + .toBe('VoidMethodTestDictionaryArg()'); + }); \ No newline at end of file diff --git a/test/test_interface.cc b/test/test_interface.cc index 0431896..b8297d5 100644 --- a/test/test_interface.cc +++ b/test/test_interface.cc @@ -130,3 +130,7 @@ double TestInterface::GetStaticDoubleNumber() { void TestInterface::SetStaticDoubleNumber(double number) { TestInterface::static_double_number_ = number; } + +void TestInterface::VoidMethodTestDictionaryArg(TestDict testDict) { + last_call_info_ = "VoidMethodTestDictionaryArg()"; +} diff --git a/test/test_interface.h b/test/test_interface.h index 5e6f4fe..009773b 100644 --- a/test/test_interface.h +++ b/test/test_interface.h @@ -19,6 +19,8 @@ #include +#include "test/test_dict.h" + class TestInterface { public: TestInterface(); @@ -57,6 +59,9 @@ class TestInterface { static double GetStaticDoubleNumber(); static void SetStaticDoubleNumber(double number); + // Dictionary + void VoidMethodTestDictionaryArg(TestDict testDict); + private: // FIXME(zino): Currently, we should set this variable in each methods. It's // not elegance way. We should find a way to get function name and signature diff --git a/test/test_interface.idl b/test/test_interface.idl index 9424809..8188d15 100644 --- a/test/test_interface.idl +++ b/test/test_interface.idl @@ -40,7 +40,7 @@ interface TestInterface { double doubleMethod(double number); string stringMethod(string string); - // enum + // Enum void voidMethodTestEnumArg(TestEnum enumValue); TestEnum enumReturnMethod(long index); @@ -50,6 +50,9 @@ interface TestInterface { static attribute double staticDoubleNumber; void readonlyAssignTest(double number); static double StaticTest(double number); + + // Dictionary + void voidMethodTestDictionaryArg(TestDict dicValue); }; enum TestEnum { @@ -57,3 +60,7 @@ enum TestEnum { "value2", "value3" }; + +dictionary TestDict { + double a; +}; \ No newline at end of file From 5eb768706fc9690cf0d6507f0e1867a2a00b8b5f Mon Sep 17 00:00:00 2001 From: Hwanseung Lee Date: Tue, 7 Nov 2017 22:03:13 +0900 Subject: [PATCH 2/3] add readonly keyword --- generator/parser/dictionary_types.ts | 3 +-- generator/parser/idl_dictionary.ts | 2 +- template/interface_cpp.njk | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/generator/parser/dictionary_types.ts b/generator/parser/dictionary_types.ts index fc15a23..ab4ea34 100644 --- a/generator/parser/dictionary_types.ts +++ b/generator/parser/dictionary_types.ts @@ -17,9 +17,8 @@ import IDLDefinition from './idl_definition'; import IDLDictionary from './idl_dictionary'; - export default class DictionaryTypes { - dictionaries: IDLDictionary[]; + readonly dictionaries: IDLDictionary[]; constructor(definitions: IDLDefinition[]) { this.dictionaries = []; diff --git a/generator/parser/idl_dictionary.ts b/generator/parser/idl_dictionary.ts index e979a71..94e1725 100644 --- a/generator/parser/idl_dictionary.ts +++ b/generator/parser/idl_dictionary.ts @@ -28,7 +28,7 @@ class DictionaryMember implements IDLIdentifier { } export default class IDLDictionary extends IDLDefinition { - members: DictionaryMember[]; + readonly members: DictionaryMember[]; constructor(raw_idl_dic_info: {}) { super(raw_idl_dic_info['name'], raw_idl_dic_info); diff --git a/template/interface_cpp.njk b/template/interface_cpp.njk index a9a8b7b..7231f3c 100644 --- a/template/interface_cpp.njk +++ b/template/interface_cpp.njk @@ -22,7 +22,7 @@ if (!EnumValidator::isValildEnum({{argument.name}}, enum_value_set)) { } {% elif argument.dictionary %} {{argument.type | pascalcase}} {{argument.name}}; -//FIXME(hwanseung): Make NatvieTypeTraits for dictionary types. +// FIXME(hwanseung): Make NatvieTypeTraits for dictionary types. {% else %} auto {{argument.name}} = NativeTypeTraits::NativeValue(info.Env(), info[{{loop.index0}}]); From 4d9759268d63d9144645c026dd1e8685ca13e056 Mon Sep 17 00:00:00 2001 From: Hwanseung Lee Date: Tue, 28 Nov 2017 22:59:26 +0900 Subject: [PATCH 3/3] rewrite comment Signed-off-by: Hwanseung Lee --- template/dictionary_types.njk | 8 +++----- template/interface_cpp.njk | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/template/dictionary_types.njk b/template/dictionary_types.njk index 4315f78..739d0af 100644 --- a/template/dictionary_types.njk +++ b/template/dictionary_types.njk @@ -20,16 +20,14 @@ class {{name}} { public: {% for member in members %} - bool has{{member.name | pascalcase}}() const { return has_{{member.name}}_; } {{member.type}} {{member.name}}() const { return {{member.name}}_; } - inline void set{{member.name | pascalcase}}({{member.type}}); + void set{{member.name | pascalcase}}({{member.type}} {{member.name}}) { + {{member.name}}_ = {{member.name}}; + } {% endfor %} private: -{% for member in members %} - bool has_{{member.name}}_ = false; -{% endfor %} {% for member in members %} {{member.type}} {{member.name}}_; {% endfor %} diff --git a/template/interface_cpp.njk b/template/interface_cpp.njk index 7231f3c..76629f4 100644 --- a/template/interface_cpp.njk +++ b/template/interface_cpp.njk @@ -22,7 +22,7 @@ if (!EnumValidator::isValildEnum({{argument.name}}, enum_value_set)) { } {% elif argument.dictionary %} {{argument.type | pascalcase}} {{argument.name}}; -// FIXME(hwanseung): Make NatvieTypeTraits for dictionary types. +// FIXME(hwanseung): Convert to native dictionary object from javascript object. {% else %} auto {{argument.name}} = NativeTypeTraits::NativeValue(info.Env(), info[{{loop.index0}}]);