forked from COVESA/ifex
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
WIP: Alternative Translation method using table-driven approach
Signed-off-by: Gunnar Andersson <[email protected]>
- Loading branch information
Showing
6 changed files
with
605 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,281 @@ | ||
# SPDX-FileCopyrightText: Copyright (c) 2024 MBition GmbH. | ||
# SPDX-License-Identifier: MPL-2.0 | ||
|
||
# This file is part of the IFEX project | ||
# vim: tw=120 ts=4 et | ||
|
||
# Have to define a search path to submodule to make this work (might be rearranged later) | ||
import os | ||
import sys | ||
mydir = os.path.dirname(__file__) | ||
for p in ['pyfranca', 'pyfranca/pyfranca']: | ||
if p not in sys.path: | ||
sys.path.append(os.path.join(mydir,p)) | ||
|
||
import ifex.model.ifex_ast as ifex | ||
import other.franca.pyfranca.pyfranca as pyfranca | ||
import other.franca.rule_translator as m2m | ||
import pyfranca.ast as franca | ||
import re | ||
|
||
from ifex.model.ifex_ast_construction import add_constructors_to_ifex_ast_model, ifex_ast_as_yaml | ||
from other.franca.rule_translator import Initialize, Constant, ListOf, Unsupported | ||
|
||
def array_type_name(francaitem): | ||
return translate_type_name(francaitem) + '[]' # Unbounded arrays for now | ||
|
||
def translate_type_name(francaitem): | ||
return translate_type(francaitem) | ||
|
||
def concat_comments(list): | ||
return "\n".join(list) | ||
|
||
# If enumerator values are not given, we must use auto-generated values. | ||
# IFEX model requires all enumerators to be given values. | ||
enum_count = -1 | ||
def reset_enumerator_counter(_ignored): | ||
print("***Resetting enum counter") | ||
global enum_count | ||
enum_count = -1 | ||
|
||
def translate_enumerator_value(franca_int_value): | ||
if franca_int_value is None: | ||
global enum_count | ||
enum_count = enum_count + 1 | ||
return enum_count | ||
return translate_integer_constant(franca_int_value) | ||
|
||
# Integer value is represented by an instance of IntegerValue class type, which has a "value" member | ||
def translate_integer_constant(franca_int_value): | ||
return franca_int_value.value | ||
|
||
# Tip: This translation table format is described in more detail in rule_translator.py | ||
franca_to_ifex_mapping = { | ||
|
||
'global_attribute_map': { | ||
# Franca-name : IFEX-name | ||
'comments' : 'description', # FIXME allow transform also here, e.g. concat comments | ||
'extends' : None, # TODO | ||
'flags' : None | ||
}, | ||
|
||
'type_map': { | ||
(franca.Interface, ifex.Interface) : [], | ||
(franca.Package, ifex.Namespace) : [ | ||
# TEMPORARY: Translates only the first interface | ||
('interfaces', 'interface', lambda x: x[0]), | ||
('typecollections', 'namespaces') ], | ||
(franca.Method, ifex.Method) : [ | ||
('in_args', 'input'), | ||
('out_args', 'output'), | ||
('namespace', None) ], | ||
(franca.Argument, ifex.Argument) : [ | ||
('type', 'datatype', translate_type_name), ], | ||
(franca.Enumeration, ifex.Enumeration) : [ | ||
(Initialize(reset_enumerator_counter), None), | ||
('enumerators', 'options'), | ||
('extends', Unsupported), | ||
|
||
# Franca only knows integer-based Enumerations so we hard-code the enumeration datatype to be | ||
# int32 in the corresponding IFEX representation | ||
(Constant('int32'), 'datatype') | ||
], | ||
|
||
(franca.Enumerator, ifex.Option) : [ | ||
('value', 'value', translate_enumerator_value) | ||
], | ||
(franca.TypeCollection, ifex.Namespace) : [ | ||
('structs', 'structs'), | ||
('unions', None), # TODO - use the variant type on IFEX side, need to check its implementation first | ||
('arrays', 'typedefs'), | ||
('typedefs', 'typedefs') | ||
], | ||
(franca.Struct, ifex.Struct) : [ | ||
('fields', 'members') | ||
], | ||
(franca.StructField, ifex.Member) : [ | ||
('type', 'datatype', translate_type_name) | ||
] , | ||
(franca.Array, ifex.Typedef) : [ | ||
('type', 'datatype', array_type_name) | ||
], | ||
(franca.Attribute, ifex.Property) : [], | ||
(franca.Import, ifex.Include) : [], | ||
# TODO: More mapping to do, much is not yet defined here | ||
(franca.Package, ifex.Enumeration) : [], | ||
(franca.Package, ifex.Struct) : [], | ||
} | ||
} | ||
|
||
# Reminders of cases to be handled from previous implementation approach: | ||
# Structs_in_TypeCollection(franca_typecollection): | ||
# Structs_in_Interface(franca_interface): | ||
# Structs_in_Package(franca_package): | ||
# Enumerator_Value(v): | ||
# Enumerators_to_Options(enumerators, enumeration_name): | ||
# Enumerations_in_Interface(franca_interface): | ||
# Enumerations_in_Typecollection(franca_typecollection): | ||
# Enumerations_in_Package(franca_package): | ||
# Arguments_to_Arguments(franca_arguments): | ||
# Methods_to_Methods(franca_methods): | ||
# Attributes_to_Properties(franca_attributes): | ||
# Typedefs_from_TypeCollection(franca_typecollection): | ||
# Typedefs_from_TypeCollections(franca_typecollections): | ||
# Imports_to_Includes(franca_imports): | ||
# translate_type(t): | ||
# flatmap(function, input_array): | ||
# combined_name(parent, item): | ||
# getValue(intype, outtype): | ||
|
||
# Concepts to be covered (from francatypes User Guide 0.12.0.1) | ||
# 5 francatypes IDL Reference ......................................... 27 | ||
# 5.1 Data types 27 | ||
# 5.1.1 Primitivetypes ....................................................27 | ||
# OK -> covered in type_translation | ||
# 5.1.2 Integerwithoptionalrange ............................................29 | ||
# TODO: -> Equivalent concept in IFEX - but not yet supported in translator | ||
# 5.1.3 Arrays ..........................................................29 | ||
# TODO: -> To be tested/evaluated | ||
# 5.1.4 Enumerations .....................................................30 | ||
# OK (Supported in translator) | ||
# 5.1.5 Structures .......................................................31 | ||
# TODO: -> To be tested/evaluated | ||
# 5.1.6 Unions(akavariants)................................................32 | ||
# TODO: -> Equivalent concept in IFEX (variant) - but not yet supported in translator | ||
# 5.1.7 Maps(akadictionaries) ..............................................33 | ||
# TODO: -> Equivalent concept in IFEX (map) - but not yet supported in translator | ||
# 5.1.8 Typedefinitions(akaaliases) ..........................................33 | ||
# OK (Supported in translator) | ||
# 5.2 Constant definitions 33 | ||
# 5.1.4 Enumerations .....................................................30 | ||
# OK (Supported in translator) | ||
# 5.2.1 Primitiveconstants .................................................34 | ||
# TODO: -> To be tested/evaluated | ||
# 5.2.2 Complexconstants .................................................34 | ||
# TODO: -> To be tested/evaluated | ||
# 5.3 Expressions 35 | ||
# 5.3.1 Typesystem ......................................................35 | ||
# 5.3.2 Constantvalues....................................................36 | ||
# 5.3.3 Comparisonoperators ...............................................36 | ||
# 5.3.4 Arithmeticoperations ...............................................36 | ||
# 5.3.5 Booleanoperations .................................................36 | ||
# Expressions NOT SUPPORTED - Not formally defined in current IFEX spec | ||
# version. Their use seem not very clear (it seems also to be an unfinished | ||
# area also in francatypes specification. | ||
# 5.4 TypeCollection definition 36 | ||
# OK Supported in translator | ||
# 5.5 Interface definition 37 | ||
# 5.5.1 Basicinterfacedefinition .............................................37 | ||
# OK Supported in translator | ||
# 5.5.2 Attributes........................................................38 | ||
# OK Supported in translator (IFEX:Property) | ||
# 5.5.3 Methods.........................................................40 | ||
# OK Supported in translator | ||
# 5.5.4 Broadcasts .......................................................44 | ||
# OK Supported in translator (IFEX:Event) | ||
# TODO: -> To be tested/evaluated | ||
# (In IFEX we would rather | ||
# 5.5.5 Interfacesmanaginginterfaces .........................................45 | ||
# WIP: Exact translation is being evaluated. Basically it would add a | ||
# namespace to the "inner" definitions | ||
# 5.6 Contracts 45 | ||
# Contracts/PSM enforcement is not part of IFEX specification or project. | ||
# This is a potential extension, or simply use the francatypes IDL development | ||
# environment if this feature is desired. | ||
# 5.7 Comments 48 | ||
# 5.7.1 Unstructuredcomments ..............................................48 | ||
# TODO: -> Equivalent concept in IFEX - but not yet supported in translator | ||
# 5.7.2 Structuredcomments................................................48 | ||
# TODO: -> Equivalent concept in IFEX - but not yet supported in translator | ||
|
||
# Part Two | ||
# | ||
# 5.8 Fully qualified names, packages, and multiple files 48 | ||
# 5.8.1 Fullyqualifiednames ................................................48 | ||
# 5.8.2 Packagedeclarations ................................................48 | ||
# 5.8.3 Importsandnamespaceresolution .......................................50 | ||
# 6 francatypes Deployment Models .................................... 51 | ||
# -> Equivalent concept in IFEX - but not yet supported in translator | ||
# Every deployment model is bespoke, and therefore developing translations | ||
# for them, must also be on a case-by-case basis. | ||
# Out of scope here. | ||
|
||
# --- Map fundamental/built-in types --- | ||
|
||
type_translation = { | ||
franca.Boolean : "boolean", | ||
franca.ByteBuffer : "uint8[]", | ||
franca.ComplexType : "opaque", # FIXME this is actually a struct reference? | ||
franca.Double : "double", | ||
franca.Float : "float", | ||
franca.Int8 : "int8", | ||
franca.Int16 : "int16", | ||
franca.Int16 : "int16", | ||
franca.Int32 : "int32", | ||
franca.Int64 : "int64", | ||
franca.String : "string", | ||
franca.UInt8 : "uint8", | ||
franca.UInt16 : "uint16", | ||
franca.UInt32 : "uint32", | ||
franca.UInt64 : "uint64", | ||
} | ||
|
||
# ---------------------------------------------------------------------------- | ||
# HELPER FUNCTIONS | ||
# ---------------------------------------------------------------------------- | ||
|
||
def translate_type(t): | ||
if type(t) is franca.Enumeration: | ||
return t.name # FIXME use qualified name <InterfaceName>_<EnumerationName>, or change in the other place | ||
if type(t) is franca.Reference: | ||
return t.name | ||
if type(t) is franca.Array: | ||
# FIXME is size of array defined in FRANCA? | ||
converted_type = translate_type(t.type) | ||
converted_type = converted_type + '[]' | ||
return converted_type | ||
else: | ||
t2 = type_translation.get(type(t)) | ||
return t2 if t2 is not None else t | ||
|
||
# Rename fidl to ifex, for imports | ||
def ifex_import_ref_from_fidl(fidl_file): | ||
return re.sub('.fidl$', '.ifex', fidl_file) | ||
|
||
# ---------------------------------------------------------------------------- | ||
# --- MAIN conversion function --- | ||
# ---------------------------------------------------------------------------- | ||
|
||
# Build the Franca AST | ||
def parse_franca(fidl_file): | ||
processor = pyfranca.Processor() | ||
return processor.import_file(fidl_file) # This returns the top level package | ||
|
||
# --- Script entry point --- | ||
|
||
if __name__ == '__main__': | ||
|
||
if len(sys.argv) != 2: | ||
print(f"Usage: python {os.path.basename(__file__)} <filename>") | ||
sys.exit(1) | ||
|
||
# Add the type-checking constructor mixin | ||
# FIXME Add this back later for strict checking | ||
#add_constructors_to_ifex_ast_model() | ||
|
||
try: | ||
# Parse franca input and create franca AST (top node is the Package definition) | ||
franca_ast = parse_franca(sys.argv[1]) | ||
|
||
# Convert Franca AST to IFEX AST | ||
ifex_ast = m2m.transform(franca_to_ifex_mapping, franca_ast) | ||
|
||
# Output as YAML | ||
print(ifex_ast_as_yaml(ifex_ast)) | ||
|
||
except FileNotFoundError: | ||
log("ERROR: File not found") | ||
except Exception as e: | ||
raise(e) | ||
log("ERROR: An unexpected error occurred: {}".format(e)) | ||
|
Submodule pyfranca
added at
e847ef
Oops, something went wrong.