def variant_accessor_functions(field: Field, variant_id: str, variant: Variant) -> List[Subprogram]: first_byte, last_byte, offset = field_location(field.name, variant_id, variant) name = f'Get_{field.name}_{variant_id}' precondition = Precondition( And(COMMON_PRECONDITION, LogCall(f'Valid_{field.name}_{variant_id} (Buffer)'))) functions: List[Subprogram] = [] if isinstance(field.type, Array): functions.append( ExpressionFunction(f'{name}_First', 'Types.Index_Type', [('Buffer', 'Types.Bytes')], first_byte, [precondition])) functions.append( ExpressionFunction(f'{name}_Last', 'Types.Index_Type', [('Buffer', 'Types.Bytes')], last_byte, [precondition])) else: functions.append( ExpressionFunction( name, field.type.name, [('Buffer', 'Types.Bytes')], Convert( field.type.name if field.type.constraints == TRUE else field.type.base_name, 'Buffer', first_byte, last_byte, offset), [precondition])) return functions
def enumeration_functions(enum: Enumeration) -> List[Subprogram]: common_precondition = And( Less(Value('Offset'), Number(8)), Equal( Length('Buffer'), Add( Div(Add(Size(enum.base_name), Value('Offset'), Number(-1)), Number(8)), Number(1)))) control_expression = LogCall( f'Convert_To_{enum.base_name} (Buffer, Offset)') validation_expression: Expr if enum.always_valid: validation_expression = Value('True') else: validation_cases: List[Tuple[Expr, Expr]] = [] validation_cases.extend( (value, Value('True')) for value in enum.literals.values()) validation_cases.append((Value('others'), Value('False'))) validation_expression = CaseExpression(control_expression, validation_cases) validation_function = ExpressionFunction( f'Valid_{enum.name}', 'Boolean', [('Buffer', 'Types.Bytes'), ('Offset', 'Natural')], validation_expression, [Precondition(common_precondition)]) function_name = f'Convert_To_{enum.name}' parameters = [('Buffer', 'Types.Bytes'), ('Offset', 'Natural')] precondition = Precondition( And(common_precondition, LogCall(f'Valid_{enum.name} (Buffer, Offset)'))) conversion_cases: List[Tuple[Expr, Expr]] = [] conversion_function: Subprogram if enum.always_valid: conversion_cases.extend((value, Aggregate(Value('True'), Value(key))) for key, value in enum.literals.items()) conversion_cases.append( (Value('others'), Aggregate(Value('False'), Value('Raw')))) conversion_function = Function( function_name, enum.name, parameters, [Declaration('Raw', enum.base_name, control_expression)], [ReturnStatement(CaseExpression(Value('Raw'), conversion_cases))], [precondition]) else: conversion_cases.extend( (value, Value(key)) for key, value in enum.literals.items()) conversion_cases.append( (Value('others'), LogCall(f'Unreachable_{enum.name}'))) conversion_function = ExpressionFunction( function_name, enum.name, parameters, CaseExpression(control_expression, conversion_cases), [precondition]) return [validation_function, conversion_function]
def field_accessor_functions(field: Field, package_name: str) -> List[Subprogram]: precondition = Precondition( And(COMMON_PRECONDITION, LogCall(f'Valid_{field.name} (Buffer)'))) functions: List[Subprogram] = [] if isinstance(field.type, Array): for attribute in ['First', 'Last']: functions.append( ExpressionFunction( f'Get_{field.name}_{attribute}', 'Types.Index_Type', [('Buffer', 'Types.Bytes')], IfExpression([( LogCall(f'Valid_{field.name}_{variant_id} (Buffer)'), LogCall( f'Get_{field.name}_{variant_id}_{attribute} (Buffer)' )) for variant_id in field.variants], 'Unreachable_Types_Index_Type'), [precondition])) body: List[Statement] = [ Assignment('First', MathCall(f'Get_{field.name}_First (Buffer)')), Assignment('Last', MathCall(f'Get_{field.name}_Last (Buffer)')) ] postcondition = Postcondition( And( Equal(Value('First'), MathCall(f'Get_{field.name}_First (Buffer)')), Equal(Value('Last'), MathCall(f'Get_{field.name}_Last (Buffer)')))) if 'Payload' not in field.type.name: predicate = f'{package_name}.{field.type.name}.Is_Contained (Buffer (First .. Last))' body.append(PragmaStatement('Assume', [predicate])) postcondition.expr = And(postcondition.expr, LogCall(predicate)) functions.append( Procedure(f'Get_{field.name}', [('Buffer', 'Types.Bytes'), ('First', 'out Types.Index_Type'), ('Last', 'out Types.Index_Type')], [], body, [precondition, postcondition])) else: functions.append( ExpressionFunction( f'Get_{field.name}', field.type.name, [('Buffer', 'Types.Bytes')], IfExpression( [(LogCall(f'Valid_{field.name}_{variant_id} (Buffer)'), MathCall(f'Get_{field.name}_{variant_id} (Buffer)')) for variant_id in field.variants], f'Unreachable_{field.type.name}'), [precondition])) return functions
def contain_functions() -> List[Subprogram]: return [ ExpressionFunction('Is_Contained', 'Boolean', [('Buffer', 'Types.Bytes')], aspects=[Ghost(), Import()]), Procedure('Label', [('Buffer', 'Types.Bytes')], [], [PragmaStatement('Assume', ['Is_Contained (Buffer)'])], aspects=[Postcondition(LogCall('Is_Contained (Buffer)'))]) ]
def message_validation_function(variants: List[Variant]) -> Subprogram: expr: LogExpr = FALSE for variant in variants: condition = variant_condition(variant) expr = condition if expr == FALSE else Or(expr, condition) return ExpressionFunction('Is_Valid', 'Boolean', [('Buffer', 'Types.Bytes')], expr, [Precondition(COMMON_PRECONDITION)])
def field_validation_function(field: Field) -> Subprogram: variants: List[LogExpr] = list(valid_variants(field)) expr = variants.pop() for e in variants: if e is not TRUE: expr = Or(expr, e) return ExpressionFunction(f'Valid_{field.name}', 'Boolean', [('Buffer', 'Types.Bytes')], expr, [Precondition(COMMON_PRECONDITION)])
def message_length_function(variants: List[Variant]) -> Subprogram: condition_expressions: List[Tuple[LogExpr, Expr]] = [] for variant in variants: condition = variant_condition(variant) length = Add( Last(variant.previous[-1][0]), -First(variant.previous[0][0]), Number(1)).simplified(variant.facts).simplified( value_to_call_facts(variant.previous)).to_bytes().simplified() condition_expressions.append((condition, length)) return ExpressionFunction( 'Message_Length', 'Types.Length_Type', [('Buffer', 'Types.Bytes')], IfExpression(condition_expressions, 'Unreachable_Types_Length_Type'), [Precondition(And(COMMON_PRECONDITION, LogCall('Is_Valid (Buffer)')))])
def variant_validation_function(field: Field, variant_id: str, variant: Variant) -> Subprogram: type_constraints: LogExpr = TRUE if field.type.constraints != TRUE or isinstance(field.type, Enumeration): first_byte, last_byte, offset = field_location(field.name, variant_id, variant) if field.type.constraints != TRUE: convert = Convert(field.type.base_name, 'Buffer', first_byte, last_byte, offset) type_constraints = field.type.constraints.simplified( {Value(field.type.name): convert}) if isinstance(field.type, Enumeration): type_constraints = And( type_constraints, LogCall((f'Valid_{field.type.name} (Buffer ({first_byte}' f' .. {last_byte}), {offset})'))) value_to_call = value_to_call_facts([(field.name, variant_id)] + variant.previous) return ExpressionFunction( f'Valid_{field.name}_{variant_id}', 'Boolean', [('Buffer', 'Types.Bytes')], And( LogCall( f'Valid_{variant.previous[-1][0]}_{variant.previous[-1][1]} (Buffer)' ) if variant.previous else TRUE, And( And( buffer_constraints(variant.facts[Last( field.name)].to_bytes()).simplified(value_to_call), variant.condition.simplified( variant.facts).simplified(value_to_call)), type_constraints)).simplified(), [Precondition(COMMON_PRECONDITION)])
def unreachable_function(type_name: str, base_name: str = None) -> Subprogram: return ExpressionFunction( f'Unreachable_{type_name}'.replace('.', '_'), type_name, [], First(type_name) if not base_name else Aggregate( Value('False'), First(base_name)), [Precondition(FALSE)])