From 4576f7bf855fd625e68fb5dbf2b3c25e28d67d0e Mon Sep 17 00:00:00 2001 From: Zhelyapov Aleksey Date: Thu, 3 Jul 2025 18:28:17 +0300 Subject: [PATCH] Fixed IDL Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICK529 Signed-off-by: Zhelyapov Aleksey --- ets2panda/public/es2panda_lib.h | 2 + ets2panda/public/es2panda_lib.idl.erb | 79 +++++++------ ets2panda/public/es2panda_lib.rb | 82 ++++++++------ ets2panda/scripts/arkui-setup.sh | 4 + ets2panda/scripts/arkui.properties | 2 +- ets2panda/test/unit/plugin/CMakeLists.txt | 10 ++ .../plugin/compare_manual_capi_and_idl.py | 105 ++++++++++++++++++ 7 files changed, 211 insertions(+), 73 deletions(-) create mode 100644 ets2panda/test/unit/plugin/compare_manual_capi_and_idl.py diff --git a/ets2panda/public/es2panda_lib.h b/ets2panda/public/es2panda_lib.h index 9455780678..e3dfc585b2 100644 --- a/ets2panda/public/es2panda_lib.h +++ b/ets2panda/public/es2panda_lib.h @@ -170,6 +170,7 @@ typedef enum es2panda_ContextState es2panda_ContextState; // CC-OFFNXT(G.INC.08) project code style #include "generated/es2panda_lib/es2panda_lib_enums.inc" +// COMPARE_MANUAL_CAPI_AND_IDL_START struct CAPI_EXPORT es2panda_Impl { int version; @@ -281,6 +282,7 @@ struct CAPI_EXPORT es2panda_Impl { void (*InvalidateFileCache)(es2panda_GlobalContext *globalContext, const char *fileName); void (*RemoveFileCache)(es2panda_GlobalContext *globalContext, const char *fileName); void (*AddFileCache)(es2panda_GlobalContext *globalContext, const char *fileName); +// COMPARE_MANUAL_CAPI_AND_IDL_END // CC-OFFNXT(G.INC.08) project code style #include "generated/es2panda_lib/es2panda_lib_decl.inc" }; diff --git a/ets2panda/public/es2panda_lib.idl.erb b/ets2panda/public/es2panda_lib.idl.erb index c52ea85899..d788c8acec 100644 --- a/ets2panda/public/es2panda_lib.idl.erb +++ b/ets2panda/public/es2panda_lib.idl.erb @@ -20,35 +20,18 @@ typedef (String or f64 or boolean) es2panda_variantDoubleCharArrayBool; [Entity=Class] interface es2panda_Config {}; [Entity=Class] interface es2panda_Context {}; [Entity=Class] interface es2panda_GlobalContext {}; -[Entity=Class] interface es2panda_Program {}; [Entity=Class] interface es2panda_ExternalSource {}; -[Entity=Class] interface es2panda_ArkTsConfig {}; -[Entity=Class] interface es2panda_AstNode {}; -[Entity=Class] interface es2panda_FunctionSignature {}; [Entity=Class] interface es2panda_SourcePosition {}; [Entity=Class] interface es2panda_SourceRange {}; -[Entity=Class] interface es2panda_SrcDumper {}; -[Entity=Class] interface es2panda_AstDumper {}; [Entity=Class] interface es2panda_LabelPair {}; [Entity=Class] interface es2panda_ScriptFunctionData {}; [Entity=Class] interface es2panda_ImportSource {}; -[Entity=Class] interface es2panda_Signature {}; [Entity=Class] interface es2panda_SignatureInfo {}; -[Entity=Class] interface es2panda_CheckerContext {}; -[Entity=Class] interface es2panda_ResolveResult {}; -[Entity=Class] interface es2panda_ValidationInfo {}; -[Entity=Class] interface es2panda_Type {}; -[Entity=Class] interface es2panda_TypeRelation {}; [Entity=Class] interface es2panda_IndexInfo {}; -[Entity=Class] interface es2panda_GlobalTypesHolder {}; [Entity=Class] interface es2panda_ObjectDescriptor {}; -[Entity=Class] interface es2panda_Variable {}; -[Entity=Class] interface es2panda_Scope {}; [Entity=Class] interface es2panda_ScopeFindResult {}; [Entity=Class] interface es2panda_BindingProps {}; [Entity=Class] interface es2panda_Declaration {}; -[Entity=Class] interface es2panda_RecordTable {}; -[Entity=Class] interface es2panda_BoundContext {}; [Entity=Class] interface es2panda_AstVisitor {}; [Entity=Class] interface es2panda_AstVerifier {}; [Entity=Class] interface es2panda_VerifierMessage {}; @@ -57,9 +40,8 @@ typedef (String or f64 or boolean) es2panda_variantDoubleCharArrayBool; [Entity=Class] interface es2panda_IRNode {}; [Entity=Class] interface es2panda_ErrorLogger {}; [Entity=Class] interface es2panda_VerificationContext {}; -[Entity=Class] interface es2panda_ImportPathManager {}; -[Entity=Class] interface es2panda_Path {}; -[Entity=Class] interface es2panda_Options {}; +[Entity=Class] interface es2panda_DiagnosticKind {}; +[Entity=Class] interface es2panda_DiagnosticStorage {}; interface NodeTraverser { @@ -141,7 +123,14 @@ interface es2panda_DiagnosticInfo { attribute es2panda_SourcePosition pos; }; -dictionary es2panda_PluginDiagnosticType { +dictionary Es2pandaLanguage { + i32 LANGUAGE_AS = 0; + i32 LANGUAGE_JS = 1; + i32 LANGUAGE_TS = 2; + i32 LANGUAGE_ETS = 3; +}; + +dictionary es2panda_PluginDiagnosticType { i32 ES2PANDA_PLUGIN_WARNING = 0; i32 ES2PANDA_PLUGIN_ERROR = 1; i32 ES2PANDA_PLUGIN_SUGGESTION = 2; @@ -168,11 +157,14 @@ typedef u64 Es2panda<%= name %>; % end +// COMPARE_MANUAL_CAPI_AND_IDL_START interface es2panda_Impl { + void MemInitialize(); + void MemFinalize(); es2panda_Config CreateConfig(i32 argc, sequence argv); void DestroyConfig(es2panda_Config config); String GetAllErrorMessages(es2panda_Context context); - es2panda_Options ConfigGetOptions(es2panda_Config config); + util.Options ConfigGetOptions(es2panda_Config config); es2panda_Context CreateContextFromFile(es2panda_Config config, String source_file_name); es2panda_Context CreateCacheContextFromFile(es2panda_Config config, String source_file_name, es2panda_GlobalContext globalContext, boolean isExternal); @@ -188,30 +180,36 @@ interface es2panda_Impl { es2panda_ContextState ContextState(es2panda_Context context); String ContextErrorMessage(es2panda_Context context); - es2panda_Program ContextProgram(es2panda_Context context); + parser.Program ContextProgram(es2panda_Context context); String ExternalSourceName(es2panda_ExternalSource e_source); - sequence ExternalSourcePrograms(es2panda_ExternalSource e_source, sequence len_p); + sequence ExternalSourcePrograms(es2panda_ExternalSource e_source, sequence len_p); void AstNodeForEach(ir.AstNode ast, AstNodeForEachFunction func, VoidPtr arg); - + String NumberLiteralStrConst(es2panda_Context context, ir.AstNode classInstance); VoidPtr AllocMemory(es2panda_Context context, u32 numberOfElements, u32 sizeOfElement); es2panda_SourcePosition CreateSourcePosition(es2panda_Context context, u32 index, u32 line); es2panda_SourceRange CreateSourceRange(es2panda_Context context, es2panda_SourcePosition start, es2panda_SourcePosition end); + u32 SourcePositionCol(es2panda_Context context, es2panda_SourcePosition position); u32 SourcePositionIndex(es2panda_Context context, es2panda_SourcePosition position); u32 SourcePositionLine(es2panda_Context context, es2panda_SourcePosition position); es2panda_SourcePosition SourceRangeStart(es2panda_Context context, es2panda_SourceRange range); es2panda_SourcePosition SourceRangeEnd(es2panda_Context context, es2panda_SourceRange range); + es2panda_DiagnosticKind CreateDiagnosticKind(es2panda_Context context, String dmessage, + es2panda_PluginDiagnosticType etype); es2panda_DiagnosticInfo CreateDiagnosticInfo(es2panda_Context context, es2panda_DiagnosticKind kind, sequence args, u32 argc, es2panda_SourcePosition position); - es2panda_SuggestionInfo CreateDiagnosticInfo(es2panda_Context context, es2panda_DiagnosticKind kind, + es2panda_SuggestionInfo CreateSuggestionInfo(es2panda_Context context, es2panda_DiagnosticKind kind, sequence args, u32 argc, String substitutionCode, es2panda_SourceRange range); void LogDiagnosticWithSuggestion(es2panda_Context context, es2panda_DiagnosticInfo diagnosticInfo, es2panda_SuggestionInfo suggestionInfo); - void LogTypeError(es2panda_Context context, String errorMsg, es2panda_SourcePosition pos); - void LogWarning(es2panda_Context context, String warnMsg, es2panda_SourcePosition pos); - void LogSyntaxError(es2panda_Context context, String errorMsg, es2panda_SourcePosition pos); + void LogDiagnostic(es2panda_Context context, es2panda_DiagnosticKind kind, sequence args, + u32 argc, es2panda_SourcePosition pos); + es2panda_DiagnosticStorage GetSemanticErrors(es2panda_Context ctx); + es2panda_DiagnosticStorage GetSyntaxErrors(es2panda_Context ctx); + es2panda_DiagnosticStorage GetPluginErrors(es2panda_Context ctx); + es2panda_DiagnosticStorage GetWarnings(es2panda_Context ctx); boolean IsAnyError(es2panda_Context context); varbinder.Scope AstNodeFindNearestScope(es2panda_Context ctx, ir.AstNode node); varbinder.Scope AstNodeRebind(es2panda_Context ctx, ir.AstNode node); @@ -223,15 +221,18 @@ interface es2panda_Impl { String JsdocStringFromDeclaration(es2panda_Context ctx, ir.AstNode node); String GetLicenseFromRootNode(es2panda_Context ctx, ir.AstNode node); ir.AstNode FirstDeclarationByNameFromNode(es2panda_Context ctx, ir.AstNode node, String name); - ir.AstNode FirstDeclarationByNameFromProgram(es2panda_Context ctx, es2panda_Program program, String name); + ir.AstNode FirstDeclarationByNameFromProgram(es2panda_Context ctx, parser.Program program, String name); sequence AllDeclarationsByNameFromNode(es2panda_Context ctx, ir.AstNode node, String name); - sequence AllDeclarationsByNameFromProgram(es2panda_Context ctx, es2panda_Program program, String name); - void InsertETSImportDeclarationAndParse(es2panda_Context context, es2panda_Program program, - ETSImportDeclaration node); + sequence AllDeclarationsByNameFromProgram(es2panda_Context ctx, parser.Program program, String name); + i32 GenerateTsDeclarationsFromContext(es2panda_Context ctx, String outputDeclEts, String outputEts, + boolean exportAll, boolean isolated); + void InsertETSImportDeclarationAndParse(es2panda_Context context, parser.Program program, + ir.ETSImportDeclaration node); i32 GenerateStaticDeclarationsFromContext(es2panda_Context context, String outputPath); void InvalidateFileCache(es2panda_GlobalContext globalContext, String fileName); void RemoveFileCache(es2panda_GlobalContext globalContext, String fileName); void AddFileCache(es2panda_GlobalContext globalContext, String fileName); +// COMPARE_MANUAL_CAPI_AND_IDL_END % Es2pandaLibApi::ast_nodes&.each do |ast_node| % if ast_node != 'AstNode' && ast_node != 'TypeNode' @@ -260,9 +261,11 @@ interface es2panda_Impl { String AstNodeName(ir.AstNode ast); }; +% Es2pandaLibApi::classes&.each do |namespaceName, namespaceClasses| -namespace ir { +namespace <%= namespaceName %> { +% if namespaceName == 'ir' % number_literal_ast_node_type = Enums::enums['AstNodeType'].all_flags_with_value['NUMBER_LITERAL'] [Entity=Class, Es2pandaAstNodeType=<%= number_literal_ast_node_type %>, c_type=es2panda_AstNode] interface NumberLiteral: Literal { ir.AstNode Create(es2panda_Context ctx, i32 value); @@ -283,13 +286,7 @@ namespace ir { [get] String StrConst(es2panda_Context context); }; -}; // namespace ir - - -% Es2pandaLibApi::classes&.each do |namespaceName, namespaceClasses| - -namespace <%= namespaceName %> { - +% end % namespaceClasses&.each do |className, classData| [Entity=Class<%= classData.ast_node_type_value ? ", Es2pandaAstNodeType=#{classData.ast_node_type_value}" : '' diff --git a/ets2panda/public/es2panda_lib.rb b/ets2panda/public/es2panda_lib.rb index 82f2cd6522..3d4967cc44 100644 --- a/ets2panda/public/es2panda_lib.rb +++ b/ets2panda/public/es2panda_lib.rb @@ -558,7 +558,30 @@ module Es2pandaLibApi end def self.type_to_idl(type) - @@replace_to_idl_types ||= { + @@e2p_c_types ||= { + 'es2panda_AstNode' => 'ir.AstNode', + 'es2panda_ArkTsConfig' => 'es2panda.ArkTsConfig', + 'es2panda_SrcDumper' => 'ir.SrcDumper', + 'es2panda_AstDumper' => 'ir.AstDumper', + 'es2panda_FunctionSignature' => 'ir.FunctionSignature', + 'es2panda_ValidationInfo' => 'ir.ValidationInfo', + 'es2panda_Signature' => 'checker.Signature', + 'es2panda_GlobalTypesHolder' => 'checker.GlobalTypesHolder', + 'es2panda_Type' => 'checker.Type', + 'es2panda_TypeRelation' => 'checker.TypeRelation', + 'es2panda_CheckerContext' => 'checker.CheckerContext', + 'es2panda_ResolveResult' => 'checker.ResolveResult', + 'es2panda_Variable' => 'varbinder.Variable', + 'es2panda_Scope' => 'varbinder.Scope', + 'es2panda_RecordTable' => 'varbinder.RecordTable', + 'es2panda_BoundContext' => 'varbinder.BoundContext', + 'es2panda_ImportPathManager' => 'util.ImportPathManager', + 'es2panda_Path' => 'util.Path', + 'es2panda_Options' => 'util.Options', + 'es2panda_Program' => 'parser.Program' + } + + @@idl_primitive_types ||= { 'bool' => 'boolean', 'int' => 'i32', 'size_t' => 'u32', @@ -576,10 +599,11 @@ module Es2pandaLibApi 'sequence' => 'String' } - c_type = type['namespace'] && type['namespace'] != 'std' ? "#{type['namespace']}.#{type['name']}" : type['name'] - res_sequence_len = @@replace_to_idl_types.key?(c_type) ? (type['ptr_depth'] || 0) : ((type['ptr_depth'] || 1) - 1) - res = res_sequence_len.times.reduce(c_type) { |acc, _| "sequence<#{@@replace_to_idl_types[acc] || acc}>" } - @@replace_to_idl_types[res] || res + res = @@e2p_c_types[type['name']] || type['name'] + res = "#{type['namespace']}.#{res}" if type['namespace'] && !res.include?(".") && type['namespace'] != 'std' + res_sequence_len = @@idl_primitive_types.key?(res) ? (type['ptr_depth'] || 0) : ((type['ptr_depth'] || 1) - 1) + res = res_sequence_len.times.reduce(res) { |acc, _| "sequence<#{@@idl_primitive_types[acc] || acc}>" } + @@idl_primitive_types[res] || res end attr_reader :is_change_type @@ -698,16 +722,10 @@ module Es2pandaLibApi attr_accessor :ast_node_type_value def class_name - Es2pandaLibApi.classes&.each do |_namespace_name, namespace_classes| - if namespace_classes&.find { |_name, data| data == self } - return namespace_classes&.find { |_name, data| data == self }[0] - end + Es2pandaLibApi.classes&.each do |_namespace_name, classes| + return classes.find { |_, data| data == self }[0] if classes&.find { |_, data| data == self } end - if Es2pandaLibApi.structs.find { |_name, data| data == self }[0] - return Es2pandaLibApi.structs.find { |_name, data| data == self }[0] - end - - raise 'Unknown class name' + Es2pandaLibApi.structs.find { |_, data| data == self }&.first || (raise 'Unknown class name') end def class_c_type @@ -849,8 +867,8 @@ module Es2pandaLibApi Es2pandaLibApi.stat_add_class(1, class_name) Es2pandaLibApi.log('info', "Supported constructor for class '#{class_name}'\n") - res << { 'overload' => get_new_method_name(constructor_overload, '', ''), - 'idl_overload' => get_new_method_name(idl_constructor_overload, '', '', true), + res << { 'overload' => get_new_method_name(constructor_overload, '', '', class_name), + 'idl_overload' => get_new_method_name(idl_constructor_overload, '', '', class_name, true), 'args' => args, 'raw_decl' => constructor.raw_declaration } end else @@ -968,9 +986,9 @@ module Es2pandaLibApi res end - def get_new_method_name(function_overload, name, const, skip_namespace_overload = false) - function_name = if check_for_same_class_name && !skip_namespace_overload then class_base_namespace.capitalize - else '' end + name + (const != '' ? 'Const' : '') + def get_new_method_name(function_overload, name, const, return_type = '', skip_namespace_overload = false) + function_name = (check_for_same_class_name && !skip_namespace_overload ? class_base_namespace.capitalize : '') + + name + (%w[Create Update].include?(name) ? return_type : '') + (const != '' ? 'Const' : '') overload_name = function_name if function_overload.include?(function_name) @@ -1018,6 +1036,7 @@ module Es2pandaLibApi begin return_type = Type.new(add_base_namespace(replace_with_usings(method.return_type, usings)), class_base_namespace, 'return') + rt_name = method.return_type.name const = get_const_modifier(method) const_return = get_const_return_modifier(return_type) @@ -1040,18 +1059,18 @@ module Es2pandaLibApi rescue StandardError => e stat_function_overload = Marshal.load(Marshal.dump(function_overload)) error_catch_log('Method', method, e, class_name + - get_new_method_name(stat_function_overload, method.name, const)) + get_new_method_name(stat_function_overload, method.name, const, method.return_type.name)) else stat_function_overload = Marshal.load(Marshal.dump(function_overload)) Es2pandaLibApi.stat_add_method(1, class_name, class_base_namespace, class_name + - get_new_method_name(stat_function_overload, method.name, const)) + get_new_method_name(stat_function_overload, method.name, const, rt_name)) Es2pandaLibApi.log('info', 'supported method: ', method.name, ' class: ', class_name, "\n") res << { 'name' => method.name, 'const' => const, 'return_arg_to_str' => return_type.return_args_to_str, - 'overload_name' => get_new_method_name(function_overload, method.name, const), 'args' => args, - 'idl_name' => get_new_method_name(idl_function_overload, method.name, const, true), + 'overload_name' => get_new_method_name(function_overload, method.name, const, rt_name), + 'idl_name' => get_new_method_name(idl_function_overload, method.name, const, rt_name, true), 'return_type' => return_type, 'return_expr' => return_expr, 'raw_decl' => method.raw_declaration, - 'const_return' => const_return, 'get_modifier' => method['additional_attributes'] } + 'const_return' => const_return, 'get_modifier' => method['additional_attributes'], 'args' => args } end else Es2pandaLibApi.log('info', "Banned method\n") @@ -1451,7 +1470,8 @@ module Es2pandaLibApi return nil end - extends.gsub(/[<>]/, ' ').split.last.split('::').last + res = extends.gsub(/[<>]/, ' ').split.last.split('::').last(2).join('.') + res unless %w[T TypedBinder TypedParser].include?(res) end def template_extends(extends) @@ -1536,14 +1556,14 @@ module Es2pandaLibApi @classes['ir'][class_definition.name] = class_data end - extract_classes_in_namespace(data, 'checker') { |class_name| - @ast_types.include?(class_name) || ast_type_additional_children.include?(class_name) || - additional_classes_to_generate.include?(class_name) - } - extract_classes_in_namespace(data, 'varbinder') { |class_name| + extract_classes_in_namespace(data, 'checker') do |class_name| + @ast_types.include?(class_name) || ast_type_additional_children.include?(class_name) || + additional_classes_to_generate.include?(class_name) + end + extract_classes_in_namespace(data, 'varbinder') do |class_name| scopes.include?(class_name) || declarations.include?(class_name) || ast_variables.find { |x| x[1] == class_name } || additional_classes_to_generate.include?(class_name) - } + end extract_classes_in_namespace(data, 'parser') { |class_name| additional_classes_to_generate.include?(class_name) } extract_classes_in_namespace(data, 'util') { |class_name| additional_classes_to_generate.include?(class_name) } extract_classes_in_namespace(data, 'gen') { |class_name| additional_classes_to_generate.include?(class_name) } diff --git a/ets2panda/scripts/arkui-setup.sh b/ets2panda/scripts/arkui-setup.sh index 1a2cd0ca9d..df3db6d24a 100755 --- a/ets2panda/scripts/arkui-setup.sh +++ b/ets2panda/scripts/arkui-setup.sh @@ -201,6 +201,10 @@ case "${DEMO}" in ;; "empty") ;; + "idlinter") + npm -i @idlizer/idlinter + npx @idlizer/idlinter --check incremental/tools/panda/node_modules/@panda/sdk/ohos_arm64/include/tools/es2panda/generated/es2panda_lib/es2panda_lib.idl + ;; *) echo "Unknown demo" "${DEMO}" exit 1 diff --git a/ets2panda/scripts/arkui.properties b/ets2panda/scripts/arkui.properties index 596d66d775..9da3ed2374 100644 --- a/ets2panda/scripts/arkui.properties +++ b/ets2panda/scripts/arkui.properties @@ -1,3 +1,3 @@ ARKUI_DEV_REPO=https://gitee.com/rri_opensource/koala_projects.git -ARKUI_DEV_BRANCH=panda_rev_9-array-length-int +ARKUI_DEV_BRANCH=panda_rev_9-add-idlinter ARKUI_DEST=koala-sig diff --git a/ets2panda/test/unit/plugin/CMakeLists.txt b/ets2panda/test/unit/plugin/CMakeLists.txt index 924f4a3551..8567b6b167 100644 --- a/ets2panda/test/unit/plugin/CMakeLists.txt +++ b/ets2panda/test/unit/plugin/CMakeLists.txt @@ -224,3 +224,13 @@ foreach(TEST_DATA IN ITEMS ${PLUGIN_TESTS}) endforeach() add_dependencies(es2panda_tests es2panda-plugin-test) + +set(ES2PANDA_PUBLIC ${ES2PANDA_ROOT}/public) +add_custom_target(compare_manual_capi_and_idl + COMMAND python3 -B ${CMAKE_CURRENT_SOURCE_DIR}/compare_manual_capi_and_idl.py + --header ${ES2PANDA_PUBLIC}/es2panda_lib.h + --idl ${ES2PANDA_PUBLIC}/es2panda_lib.idl.erb + SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/compare_manual_capi_and_idl.py ${ES2PANDA_PUBLIC}/es2panda_lib.h + ${ES2PANDA_PUBLIC}/es2panda_lib.idl.erb +) +add_dependencies(es2panda_tests compare_manual_capi_and_idl) diff --git a/ets2panda/test/unit/plugin/compare_manual_capi_and_idl.py b/ets2panda/test/unit/plugin/compare_manual_capi_and_idl.py new file mode 100644 index 0000000000..6b2b8f479f --- /dev/null +++ b/ets2panda/test/unit/plugin/compare_manual_capi_and_idl.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python3 +# coding: utf-8 +# Copyright (c) 2025 Huawei Device Co., Ltd. +# 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 os +import sys +import re +import logging +import argparse +from pathlib import Path +from collections import defaultdict +from typing import List, DefaultDict + + +logging.basicConfig(stream=sys.stdout, level=logging.DEBUG, format="%(levelname)s:[%(name)s]: %(message)s", force=True) +logging.root.name = "CAPI_IDL_COMPARATOR" + + +def parse_arguments() -> argparse.Namespace: + parser = argparse.ArgumentParser(description="Compare manually written CAPI against IDL") + parser.add_argument("--header", type=str, required=True, help="Path to es2panda_lib.h") + parser.add_argument("--idl", type=str, required=True, help="Path to es2panda_lib.idl.erb") + + local_args = parser.parse_args() + if not os.path.isfile(local_args.header): + raise RuntimeError(f"Bad path to es2panda_lib.h: {local_args.header}") + if not os.path.isfile(local_args.idl): + raise RuntimeError(f"Bad path to es2panda_lib.h: {local_args.idl}") + + return local_args + + +def extract_interest(data: List[str]) -> List[str]: + start_marker = "COMPARE_MANUAL_CAPI_AND_IDL_START" + end_marker = "COMPARE_MANUAL_CAPI_AND_IDL_END" + start_index = -1 + end_index = -1 + + for i, line in enumerate(data): + if start_marker in line: + if start_index != -1: + raise RuntimeError(f"Double {start_marker}. Lines {start_index + 1} and {i + 1}") + start_index = i + if end_marker in line: + if start_index == -1: + raise RuntimeError(f"{end_marker} before {start_marker}. Line {i + 1}") + end_index = i + break + + if start_index == -1 or end_index == -1: + raise RuntimeError(f"Not found markers! {start_marker} line: {start_index}. {end_marker} line: {end_index}.") + + return data[start_index + 1 : end_index] + + +def get_api_list_from_file(path: Path, pattern: str) -> DefaultDict[str, int]: + store_data: DefaultDict[str, int] = defaultdict(int) + for line in extract_interest(path.read_text(encoding="utf-8").splitlines()): + res = re.search(pattern, line) + if res: + store_data[res.group(1)] += 1 + return store_data + + +def compare_api(header_data: DefaultDict[str, int], idl_data: DefaultDict[str, int]) -> bool: + compare_passed = True + total_keys = sorted(list(filter(lambda x: x.find("##") == -1, set(header_data.keys()) | set(idl_data.keys())))) + + header = "es2panda_lib.h" + idl = "es2panda_lib.idl.erb" + + for k in total_keys: + if not header_data.get(k): + logging.error(f"Function '{k}' not found in {header}") + compare_passed = False + elif not idl_data.get(k): + logging.error(f"Function '{k}' not found in {idl}") + compare_passed = False + elif header_data.get(k, 0) != idl_data.get(k, 0): + logging.error(f"Function '{k}': {header_data.get(k, 0)} in {header}, {idl_data.get(k, 0)} in {idl}") + compare_passed = False + + if not compare_passed: + logging.error(f"Hint: Manually written functions in {header} must be synchronized with {idl}.") + + return not compare_passed + + +if __name__ == "__main__": + args = parse_arguments() + header_api_list = get_api_list_from_file(Path(args.header), r"\(\*(.*?)\)") + idl_api_list = get_api_list_from_file(Path(args.idl), r"^\s*(?:\S+)\s+(\S+?)\(") + sys.exit(compare_api(header_api_list, idl_api_list)) -- Gitee