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 create_scalar_accessor_functions(scalar_fields: Mapping[Field, Scalar]) -> UnitPart: def specification(field: Field, field_type: Type) -> FunctionSpecification: return FunctionSpecification( f"Get_{field.name}", field_type.full_name, [Parameter(["Ctx"], "Context")] ) def result(field: Field, field_type: Type) -> Expr: value = Selected( Indexed("Ctx.Cursors", Name(field.affixed_name)), f"Value.{field.name}_Value" ) if isinstance(field_type, Enumeration): return Call("Convert", [value]) return value return UnitPart( [ SubprogramDeclaration( specification(f, t), [ Precondition( And(VALID_CONTEXT, Call("Valid", [Name("Ctx"), Name(f.affixed_name)])) ) ], ) for f, t in scalar_fields.items() ], [ ExpressionFunctionDeclaration(specification(f, t), result(f, t)) for f, t in scalar_fields.items() ], )
def create_valid_message_function(self, message: Message) -> UnitPart: specification = FunctionSpecification("Valid_Message", "Boolean", [Parameter(["Ctx"], "Context")]) return UnitPart( [ SubprogramDeclaration( specification, [ Precondition( Call( self.prefix * message.identifier * "Has_Buffer", [Variable("Ctx")], )) ], ) ], private=[ ExpressionFunctionDeclaration( specification, self.valid_message_condition(message), ) ], )
def contains_function(name: str, pdu: str, field: str, sdu: str, condition: LogExpr) -> Subprogram: success_statements: List[Statement] = [ReturnStatement(TRUE)] aspects: List[Aspect] = [ Precondition( And(LogCall(f'{pdu}.Is_Contained (Buffer)'), LogCall(f'{pdu}.Is_Valid (Buffer)'))) ] if sdu != 'null': success_statements.insert( 0, PragmaStatement('Assume', [( f'{sdu}.Is_Contained (Buffer ({pdu}.Get_{field}_First (Buffer)' f' .. {pdu}.Get_{field}_Last (Buffer)))')])) aspects.append( Postcondition( IfExpression([ (LogCall(f'{name}\'Result'), LogCall((f'{sdu}.Is_Contained (Buffer (' f'{pdu}.Get_{field}_First (Buffer)' f' .. {pdu}.Get_{field}_Last (Buffer)))'))) ]))) return Function(name, 'Boolean', [('Buffer', 'Types.Bytes')], [], [ IfStatement([(condition, success_statements)]), ReturnStatement(FALSE) ], aspects)
def create_structural_valid_function() -> UnitPart: specification = FunctionSpecification( "Structural_Valid", "Boolean", [Parameter(["Ctx"], "Context"), Parameter(["Fld"], "Field")], ) return UnitPart( [SubprogramDeclaration(specification, [Precondition(VALID_CONTEXT)])], [ ExpressionFunctionDeclaration( specification, And( Or( *[ Equal( Selected(Indexed("Ctx.Cursors", Name("Fld")), "State"), Name(s) ) for s in ("S_Valid", "S_Structural_Valid") ] ) ), ) ], )
def create_composite_accessor_procedures(self, composite_fields: Sequence[Field]) -> UnitPart: def specification(field: Field) -> ProcedureSpecification: return ProcedureSpecification(f"Get_{field.name}", [Parameter(["Ctx"], "Context")]) return UnitPart( [ SubprogramDeclaration( specification(f), [ Precondition( And( VALID_CONTEXT, Call("Has_Buffer", [Name("Ctx")]), Call("Present", [Name("Ctx"), Name(f.affixed_name)]), ) ) ], [ FormalSubprogramDeclaration( ProcedureSpecification( f"Process_{f.name}", [Parameter([f.name], self.types.bytes)] ) ) ], ) for f in composite_fields ], [ SubprogramBody( specification(f), [ ObjectDeclaration( ["First"], self.types.index, Call( self.types.byte_index, [Selected(Indexed("Ctx.Cursors", Name(f.affixed_name)), "First")], ), True, ), ObjectDeclaration( ["Last"], self.types.index, Call( self.types.byte_index, [Selected(Indexed("Ctx.Cursors", Name(f.affixed_name)), "Last")], ), True, ), ], [ CallStatement( f"Process_{f.name}", [Slice("Ctx.Buffer.all", Name("First"), Name("Last"))], ) ], ) for f in composite_fields ], )
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 create_scalar_getter_functions( self, message: Message, scalar_fields: Mapping[Field, Scalar]) -> UnitPart: def specification(field: Field, field_type: Type) -> FunctionSpecification: if field_type.package == BUILTINS_PACKAGE: type_identifier = ID(field_type.name) else: type_identifier = self.prefix * field_type.identifier return FunctionSpecification(f"Get_{field.name}", type_identifier, [Parameter(["Ctx"], "Context")]) def result(field: Field) -> Expr: return Call( "To_Actual", [ Selected( Indexed(Variable("Ctx.Cursors"), Variable(field.affixed_name)), "Value") ], ) return UnitPart( [ # https://github.com/Componolit/Workarounds/issues/31 Pragma( "Warnings", [Variable("Off"), String("precondition is always False")]), *[ SubprogramDeclaration( specification(f, t), [ Precondition( Call( self.prefix * message.identifier * "Valid", [ Variable("Ctx"), Variable( self.prefix * message.identifier * f.affixed_name), ], ), ) ], ) for f, t in scalar_fields.items() ], Pragma( "Warnings", [Variable("On"), String("precondition is always False")]), ], private=[ ExpressionFunctionDeclaration(specification(f, t), result(f)) for f, t in scalar_fields.items() ], )
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 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 create_valid_message_function(self, message: Message) -> UnitPart: specification = FunctionSpecification( "Valid_Message", "Boolean", [Parameter(["Ctx"], "Context")] ) return UnitPart( [SubprogramDeclaration(specification, [Precondition(VALID_CONTEXT)])], [ ExpressionFunctionDeclaration( specification, valid_message_condition(message).simplified(self.common.substitution(message)), ) ], )
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 create_verify_message_procedure(self, message: Message) -> UnitPart: specification = ProcedureSpecification( "Verify_Message", [InOutParameter(["Ctx"], "Context")]) loop_invariant = And( Call("Has_Buffer", [Variable("Ctx")]), *common.context_invariant(message, loop_entry=True), ) return UnitPart( [ SubprogramDeclaration( specification, [ Precondition( Call( self.prefix * message.identifier * "Has_Buffer", [Variable("Ctx")], )), Postcondition( And( Call("Has_Buffer", [Variable("Ctx")]), *common.context_invariant(message), )), ], ) ], [ SubprogramBody( specification, [], [ ForIn( "F", Variable("Field"), [ PragmaStatement("Loop_Invariant", [loop_invariant]), CallStatement("Verify", [Variable("Ctx"), Variable("F")]), ], ) ], ) ], )
def create_incomplete_function() -> UnitPart: specification = FunctionSpecification( "Incomplete", "Boolean", [Parameter(["Ctx"], "Context"), Parameter(["Fld"], "Field")] ) return UnitPart( [SubprogramDeclaration(specification, [Precondition(VALID_CONTEXT)])], [ ExpressionFunctionDeclaration( specification, Equal( Selected(Indexed("Ctx.Cursors", Name("Fld")), "State"), Name("S_Incomplete") ), ) ], )
def create_valid_message_function(message: Message) -> UnitPart: specification = FunctionSpecification("Valid_Message", "Boolean", [Parameter(["Ctx"], "Context")]) return UnitPart( [ SubprogramDeclaration( specification, [Precondition(Call("Has_Buffer", [Variable("Ctx")]))], ) ], [ ExpressionFunctionDeclaration( specification, valid_message_condition(message).substituted( common.substitution(message)).simplified(), ) ], )
def create_incomplete_message_function(message: Message) -> UnitPart: specification = FunctionSpecification( "Incomplete_Message", "Boolean", [Parameter(["Ctx"], "Context")] ) return UnitPart( [SubprogramDeclaration(specification, [Precondition(VALID_CONTEXT)])], [ ExpressionFunctionDeclaration( specification, Or( *[ Call("Incomplete", [Name("Ctx"), Name(f.affixed_name)]) for f in message.fields ] ), ) ], )
def create_valid_function() -> UnitPart: specification = FunctionSpecification( "Valid", "Boolean", [Parameter(["Ctx"], "Context"), Parameter(["Fld"], "Field")] ) return UnitPart( [ SubprogramDeclaration( specification, [ Precondition(VALID_CONTEXT), Postcondition( If( [ ( Result("Valid"), And( Call("Structural_Valid", [Name("Ctx"), Name("Fld")]), Call("Present", [Name("Ctx"), Name("Fld")]), ), ) ] ) ), ], ) ], [ ExpressionFunctionDeclaration( specification, AndThen( Equal( Selected(Indexed("Ctx.Cursors", Name("Fld")), "State"), Name("S_Valid") ), Less( Selected(Indexed("Ctx.Cursors", Name("Fld")), "First"), Add(Selected(Indexed("Ctx.Cursors", Name("Fld")), "Last"), Number(1)), ), ), ) ], )
def create_scalar_accessor_functions( self, scalar_fields: Mapping[Field, Scalar]) -> UnitPart: def specification(field: Field, field_type: Type) -> FunctionSpecification: if field_type.package == BUILTINS_PACKAGE: type_name = ID(field_type.name) else: type_name = self.prefix * field_type.identifier return FunctionSpecification(f"Get_{field.name}", type_name, [Parameter(["Ctx"], "Context")]) def result(field: Field) -> Expr: return Call( "To_Actual", [ Selected( Indexed(Variable("Ctx.Cursors"), Variable(field.affixed_name)), f"Value.{field.name}_Value", ) ], ) return UnitPart( [ SubprogramDeclaration( specification(f, t), [ Precondition( Call("Valid", [Variable("Ctx"), Variable(f.affixed_name)]), ) ], ) for f, t in scalar_fields.items() ], [ ExpressionFunctionDeclaration(specification(f, t), result(f)) for f, t in scalar_fields.items() ], )
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 create_verify_message_procedure( message: Message, context_invariant: Sequence[Expr] ) -> UnitPart: specification = ProcedureSpecification( "Verify_Message", [InOutParameter(["Ctx"], "Context")] ) return UnitPart( [ SubprogramDeclaration( specification, [ Precondition(VALID_CONTEXT), Postcondition( And( VALID_CONTEXT, Equal( Call("Has_Buffer", [Name("Ctx")]), Old(Call("Has_Buffer", [Name("Ctx")])), ), *context_invariant, ) ), ], ) ], [ SubprogramBody( specification, [], [ CallStatement("Verify", [Name("Ctx"), Name(f.affixed_name)]) for f in message.fields ], ) ], )
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)])
def create_internal_functions( self, message: Message, scalar_fields: Mapping[Field, Scalar]) -> UnitPart: return UnitPart( [], [ SubprogramBody( ProcedureSpecification( "Set_Field_Value", [ InOutParameter(["Ctx"], "Context"), Parameter(["Val"], "Field_Dependent_Value"), OutParameter(["Fst", "Lst"], const.TYPES_BIT_INDEX), ], ), [ *common.field_bit_location_declarations( Variable("Val.Fld")), *common.field_byte_location_declarations(), *unique( self.insert_function(common.full_base_type_name(t)) for t in message.types.values() if isinstance(t, Scalar)), ], [ Assignment("Fst", Variable("First")), Assignment("Lst", Variable("Last")), CaseStatement( Variable("Val.Fld"), [( Variable(f.affixed_name), [ CallStatement( "Insert", [ Variable(f"Val.{f.name}_Value"), Slice( Variable("Ctx.Buffer.all"), Variable("Buffer_First"), Variable("Buffer_Last"), ), Variable("Offset"), ], ) if f in scalar_fields else NullStatement() ], ) for f in message.all_fields], ), ], [ Precondition( AndThen( Not(Constrained("Ctx")), Call("Has_Buffer", [Variable("Ctx")]), In(Variable("Val.Fld"), Range("Field")), Call("Valid_Next", [Variable("Ctx"), Variable("Val.Fld")]), common.sufficient_space_for_field_condition( Variable("Val.Fld")), ForAllIn( "F", Range("Field"), If([( Call( "Structural_Valid", [ Indexed( Variable("Ctx.Cursors"), Variable("F"), ) ], ), LessEqual( Selected( Indexed( Variable("Ctx.Cursors"), Variable("F"), ), "Last", ), Call( "Field_Last", [ Variable("Ctx"), Variable("Val.Fld") ], ), ), )]), ), )), Postcondition( And( Call("Has_Buffer", [Variable("Ctx")]), Equal( Variable("Fst"), Call( "Field_First", [Variable("Ctx"), Variable("Val.Fld")]), ), Equal( Variable("Lst"), Call( "Field_Last", [Variable("Ctx"), Variable("Val.Fld")]), ), GreaterEqual(Variable("Fst"), Variable("Ctx.First")), LessEqual(Variable("Fst"), Add(Variable("Lst"), Number(1))), LessEqual( Call(const.TYPES_BYTE_INDEX, [Variable("Lst")]), Variable("Ctx.Buffer_Last"), ), ForAllIn( "F", Range("Field"), If([( Call( "Structural_Valid", [ Indexed( Variable("Ctx.Cursors"), Variable("F"), ) ], ), LessEqual( Selected( Indexed( Variable("Ctx.Cursors"), Variable("F"), ), "Last", ), Variable("Lst"), ), )]), ), *[ Equal(e, Old(e)) for e in [ Variable("Ctx.Buffer_First"), Variable("Ctx.Buffer_Last"), Variable("Ctx.First"), Variable("Ctx.Cursors"), ] ], )), ], ) ] if scalar_fields else [], )
def create_composite_initialize_procedures(self, message: Message) -> UnitPart: def specification(field: Field) -> ProcedureSpecification: return ProcedureSpecification( f"Initialize_{field.name}", [InOutParameter(["Ctx"], "Context")] ) def specification_bounded(field: Field) -> ProcedureSpecification: return ProcedureSpecification( f"Initialize_Bounded_{field.name}", [InOutParameter(["Ctx"], "Context"), Parameter(["Length"], self.types.bit_length)], ) return UnitPart( [ SubprogramDeclaration( specification(f), [ Precondition( AndThen( *self.setter_preconditions(f), *self.unbounded_composite_setter_preconditions(message, f), ) ), Postcondition( And( *self.composite_setter_postconditions(message, f, message.types[f]), ) ), ], ) for f, t in message.types.items() if isinstance(t, Payload) and unbounded_setter_required(message, f) ] + [ SubprogramDeclaration( specification_bounded(f), [ Precondition( AndThen( *self.setter_preconditions(f), *self.bounded_composite_setter_preconditions(message, f), ) ), Postcondition( And( *self.composite_setter_postconditions(message, f, message.types[f]), ) ), ], ) for f, t in message.types.items() if isinstance(t, Payload) and bounded_setter_required(message, f) ], [ SubprogramBody( specification(f), self.common.field_bit_location_declarations(Name(f.affixed_name)), self.common.initialize_field_statements(message, f), ) for f, t in message.types.items() if isinstance(t, Payload) and unbounded_setter_required(message, f) ] + [ SubprogramBody( specification_bounded(f), [ ObjectDeclaration( ["First"], self.types.bit_index, Call("Field_First", [Name("Ctx"), Name(f.affixed_name)]), True, ), ObjectDeclaration( ["Last"], self.types.bit_index, Add(Name("First"), Name("Length"), -Number(1)), True, ), ], self.common.initialize_field_statements(message, f), ) for f, t in message.types.items() if isinstance(t, Payload) and bounded_setter_required(message, f) ], )
def create_scalar_setter_procedures( self, message: Message, scalar_fields: Mapping[Field, Scalar] ) -> UnitPart: def specification(field: Field, field_type: Type) -> ProcedureSpecification: type_name = ( field_type.enum_name if isinstance(field_type, Enumeration) and field_type.always_valid else field_type.name ) return ProcedureSpecification( f"Set_{field.name}", [ InOutParameter(["Ctx"], "Context"), Parameter(["Val"], f"{message.package}.{type_name}"), ], ) return UnitPart( [ SubprogramDeclaration( specification(f, t), [ Precondition( AndThen( *self.setter_preconditions(f), Call( "Field_Condition", [ Name("Ctx"), Aggregate( Name(f.affixed_name), Name("Val") if not isinstance(t, Enumeration) else Call("Convert", [Name("Val")]), ), ], ), Call("Valid", [Name("Val")]) if not isinstance(t, Enumeration) else TRUE, self.common.sufficient_space_for_field_condition( Name(f.affixed_name) ), ) ), Postcondition( And( VALID_CONTEXT, Call("Has_Buffer", [Name("Ctx")]), Call("Valid", [Name("Ctx"), Name(f.affixed_name)]), Equal( Call(f"Get_{f.name}", [Name("Ctx")]), Aggregate(TRUE, Name("Val")) if isinstance(t, Enumeration) and t.always_valid else Name("Val"), ), *self.setter_postconditions(message, f, t), *[ Equal( Call("Cursor", [Name("Ctx"), Name(p.affixed_name)]), Old(Call("Cursor", [Name("Ctx"), Name(p.affixed_name)])), ) for p in message.predecessors(f) ], ) ), ], ) for f, t in scalar_fields.items() ], [ SubprogramBody( specification(f, t), [ ObjectDeclaration( ["Field_Value"], "Field_Dependent_Value", Aggregate( Name(f.affixed_name), Name("Val") if not isinstance(t, Enumeration) else Call("Convert", [Name("Val")]), ), True, ), ObjectDeclaration(["First", "Last"], self.types.bit_index), ], [ CallStatement( "Reset_Dependent_Fields", [Name("Ctx"), Name(f.affixed_name)], ), CallStatement( "Set_Field_Value", [Name("Ctx"), Name("Field_Value"), Name("First"), Name("Last")], ), Assignment( "Ctx", Aggregate( Selected("Ctx", "Buffer_First"), Selected("Ctx", "Buffer_Last"), Selected("Ctx", "First"), Name("Last"), Selected("Ctx", "Buffer"), Selected("Ctx", "Cursors"), ), ), Assignment( Indexed(Selected("Ctx", "Cursors"), Name(f.affixed_name)), NamedAggregate( ("State", Name("S_Valid")), ("First", Name("First")), ("Last", Name("Last")), ("Value", Name("Field_Value")), ( "Predecessor", Selected( Indexed(Selected("Ctx", "Cursors"), Name(f.affixed_name)), "Predecessor", ), ), ), ), Assignment( Indexed( Selected("Ctx", "Cursors"), Call("Successor", [Name("Ctx"), Name(f.affixed_name)]), ), NamedAggregate( ("State", Name("S_Invalid")), ("Predecessor", Name(f.affixed_name)), ), ), ], ) for f, t in scalar_fields.items() ], )
def array_functions(array: Array, package: str) -> List[Subprogram]: common_precondition = LogCall(f'Is_Contained (Buffer)') return [ Function('Valid_First', 'Boolean', [('Buffer', 'Types.Bytes')], [], [ ReturnStatement( LogCall('Valid_Next (Buffer, Offset_Type (Buffer\'First))')) ], [Precondition(common_precondition)]), Procedure('Get_First', [ ('Buffer', 'Types.Bytes'), ('Offset', 'out Offset_Type'), ('First', 'out Types.Index_Type'), ('Last', 'out Types.Index_Type') ], [], [ Assignment('Offset', Value('Offset_Type (Buffer\'First)')), CallStatement('Get_Next', ['Buffer', 'Offset', 'First', 'Last']) ], [ Precondition( And(common_precondition, LogCall('Valid_First (Buffer)'))), Postcondition( And( And(GreaterEqual(Value('First'), First('Buffer')), LessEqual(Value('Last'), Last('Buffer'))), LogCall(f'{package}.{array.element_type}.Is_Contained ' '(Buffer (First .. Last))'))) ]), Function('Valid_Next', 'Boolean', [ ('Buffer', 'Types.Bytes'), ('Offset', 'Offset_Type') ], [], [ PragmaStatement('Assume', [ (f'{package}.{array.element_type}.Is_Contained ' '(Buffer (Types.Index_Type (Offset) .. Buffer\'Last))') ]), ReturnStatement( LogCall( f'{package}.{array.element_type}.Is_Valid ' '(Buffer (Types.Index_Type (Offset) .. Buffer\'Last))')) ], [Precondition(common_precondition)]), Procedure( 'Get_Next', [('Buffer', 'Types.Bytes'), ('Offset', 'in out Offset_Type'), ('First', 'out Types.Index_Type'), ('Last', 'out Types.Index_Type')], [], [ Assignment('First', Value('Types.Index_Type (Offset)')), Assignment( 'Last', Add( Value('First'), Cast( 'Types.Length_Type', MathCall(f'{package}.{array.element_type}.' 'Message_Length (Buffer (First ' '.. Buffer\'Last))')), Number(-1))), Assignment('Offset', Value('Offset_Type (Last + 1)')), PragmaStatement( 'Assume', [(f'{package}.{array.element_type}.Is_Contained ' '(Buffer (First .. Last))')]) ], [ Precondition( And(common_precondition, LogCall('Valid_Next (Buffer, Offset)'))), Postcondition( And( And(GreaterEqual(Value('First'), First('Buffer')), LessEqual(Value('Last'), Last('Buffer'))), LogCall(f'{package}.{array.element_type}.Is_Contained ' '(Buffer (First .. Last))'))) ]) ]
def create_composite_setter_procedures(self, message: Message) -> UnitPart: def specification(field: Field) -> ProcedureSpecification: return ProcedureSpecification(f"Set_{field.name}", [InOutParameter(["Ctx"], "Context")]) def specification_bounded(field: Field) -> ProcedureSpecification: return ProcedureSpecification( f"Set_Bounded_{field.name}", [InOutParameter(["Ctx"], "Context"), Parameter(["Length"], self.types.bit_length)], ) formal_parameters = [ FormalSubprogramDeclaration( ProcedureSpecification( "Process_Payload", [OutParameter(["Payload"], self.types.bytes)], ) ) ] return UnitPart( [ SubprogramDeclaration( specification(f), [ Precondition( AndThen( *self.setter_preconditions(f), *self.unbounded_composite_setter_preconditions(message, f), ) ), Postcondition( And( *self.composite_setter_postconditions(message, f, message.types[f]), ) ), ], formal_parameters, ) for f, t in message.types.items() if isinstance(t, Payload) and unbounded_setter_required(message, f) ] + [ SubprogramDeclaration( specification_bounded(f), [ Precondition( AndThen( *self.setter_preconditions(f), *self.bounded_composite_setter_preconditions(message, f), ) ), Postcondition( And( *self.composite_setter_postconditions(message, f, message.types[f]), ) ), ], formal_parameters, ) for f, t in message.types.items() if isinstance(t, Payload) and bounded_setter_required(message, f) ], [ SubprogramBody( specification(f), [ *self.common.field_bit_location_declarations(Name(f.affixed_name)), ExpressionFunctionDeclaration( FunctionSpecification("Buffer_First", self.types.index), Call(self.types.byte_index, [Name("First")]), ), ExpressionFunctionDeclaration( FunctionSpecification("Buffer_Last", self.types.index), Call(self.types.byte_index, [Name("Last")]), ), ], [ CallStatement(f"Initialize_{f.name}", [Name("Ctx")]), CallStatement( "Process_Payload", [ Slice( Selected(Selected("Ctx", "Buffer"), "all"), Name("Buffer_First"), Name("Buffer_Last"), ), ], ), ], ) for f, t in message.types.items() if isinstance(t, Payload) and unbounded_setter_required(message, f) ] + [ SubprogramBody( specification_bounded(f), [ ObjectDeclaration( ["First"], self.types.bit_index, Call("Field_First", [Name("Ctx"), Name(f.affixed_name)]), True, ), ObjectDeclaration( ["Last"], self.types.bit_index, Add(Name("First"), Name("Length"), -Number(1)), True, ), ExpressionFunctionDeclaration( FunctionSpecification("Buffer_First", self.types.index), Call(self.types.byte_index, [Name("First")]), ), ExpressionFunctionDeclaration( FunctionSpecification("Buffer_Last", self.types.index), Call(self.types.byte_index, [Name("Last")]), ), ], [ CallStatement( f"Initialize_Bounded_{f.name}", [Name("Ctx"), Name("Length")] ), CallStatement( "Process_Payload", [ Slice( Selected(Selected("Ctx", "Buffer"), "all"), Name("Buffer_First"), Name("Buffer_Last"), ), ], ), ], ) for f, t in message.types.items() if isinstance(t, Payload) and bounded_setter_required(message, f) ], )
def create_composite_accessor_procedures( composite_fields: Sequence[Field]) -> UnitPart: def specification(field: Field) -> ProcedureSpecification: return ProcedureSpecification(f"Get_{field.name}", [Parameter(["Ctx"], "Context")]) return UnitPart( [ SubprogramDeclaration( specification(f), [ Precondition( And( Call("Has_Buffer", [Variable("Ctx")]), Call("Present", [ Variable("Ctx"), Variable(f.affixed_name) ]), )) ], [ FormalSubprogramDeclaration( ProcedureSpecification( f"Process_{f.name}", [Parameter([f.name], const.TYPES_BYTES)])) ], ) for f in composite_fields ], [ SubprogramBody( specification(f), [ ObjectDeclaration( ["First"], const.TYPES_INDEX, Call( const.TYPES_BYTE_INDEX, [ Selected( Indexed(Variable("Ctx.Cursors"), Variable(f.affixed_name)), "First", ) ], ), True, ), ObjectDeclaration( ["Last"], const.TYPES_INDEX, Call( const.TYPES_BYTE_INDEX, [ Selected( Indexed(Variable("Ctx.Cursors"), Variable(f.affixed_name)), "Last", ) ], ), True, ), ], [ CallStatement( f"Process_{f.name}", [ Slice(Variable("Ctx.Buffer.all"), Variable("First"), Variable("Last")) ], ) ], ) for f in composite_fields ], )
def create_internal_functions( self, message: Message, scalar_fields: Mapping[Field, Scalar] ) -> UnitPart: return UnitPart( [], [ SubprogramBody( ProcedureSpecification( "Set_Field_Value", [ InOutParameter(["Ctx"], "Context"), Parameter(["Val"], "Field_Dependent_Value"), OutParameter(["Fst", "Lst"], self.types.bit_index), ], ), [ *self.common.field_bit_location_declarations(Selected("Val", "Fld")), *self.common.field_byte_location_declarations(), ], [ Assignment("Fst", Name("First")), Assignment("Lst", Name("Last")), CaseStatement( Selected("Val", "Fld"), [ ( Name(f.affixed_name), [ CallStatement( "Insert", [ Selected("Val", f"{f.name}_Value"), Slice( Selected(Selected("Ctx", "Buffer"), "all"), Name("Buffer_First"), Name("Buffer_Last"), ), Name("Offset"), ], ) if f in scalar_fields else NullStatement() ], ) for f in message.all_fields ], ), ], [ Precondition( AndThen( Not(Constrained("Ctx")), Call("Has_Buffer", [Name("Ctx")]), In(Selected("Val", "Fld"), Range("Field")), Call("Valid_Next", [Name("Ctx"), Selected("Val", "Fld")]), self.common.sufficient_space_for_field_condition( Selected("Val", "Fld") ), ForAllIn( "F", Range("Field"), If( [ ( Call( "Structural_Valid", [ Indexed( Selected("Ctx", "Cursors"), Name("F"), ) ], ), LessEqual( Selected( Indexed( Selected("Ctx", "Cursors"), Name("F"), ), "Last", ), Call( "Field_Last", [Name("Ctx"), Selected("Val", "Fld")], ), ), ) ] ), ), ) ), Postcondition( And( Call("Has_Buffer", [Name("Ctx")]), Equal( Name("Fst"), Call("Field_First", [Name("Ctx"), Selected("Val", "Fld")]), ), Equal( Name("Lst"), Call("Field_Last", [Name("Ctx"), Selected("Val", "Fld")]), ), GreaterEqual(Name("Fst"), Selected("Ctx", "First")), LessEqual(Name("Fst"), Add(Name("Lst"), Number(1))), LessEqual( Call(self.types.byte_index, [Name("Lst")]), Selected("Ctx", "Buffer_Last"), ), ForAllIn( "F", Range("Field"), If( [ ( Call( "Structural_Valid", [ Indexed( Selected("Ctx", "Cursors"), Name("F"), ) ], ), LessEqual( Selected( Indexed( Selected("Ctx", "Cursors"), Name("F"), ), "Last", ), Name("Lst"), ), ) ] ), ), *[ Equal(e, Old(e)) for e in [ Selected("Ctx", "Buffer_First"), Selected("Ctx", "Buffer_Last"), Selected("Ctx", "First"), Selected("Ctx", "Cursors"), ] ], ) ), ], ) ], )
def create_internal_functions( self, message: Message, scalar_fields: Mapping[Field, Type], composite_fields: Sequence[Field], ) -> UnitPart: def result(field: Field, message: Message) -> NamedAggregate: aggregate: List[Tuple[str, Expr]] = [ ("Fld", Variable(field.affixed_name)) ] if field in message.fields and isinstance(message.types[field], Scalar): aggregate.append(( f"{field.name}_Value", Call( "Extract", [ Slice( Variable("Ctx.Buffer.all"), Variable("Buffer_First"), Variable("Buffer_Last"), ), Variable("Offset"), ], ), )) return NamedAggregate(*aggregate) return UnitPart( [], [ ExpressionFunctionDeclaration( FunctionSpecification("Composite_Field", "Boolean", [Parameter(["Fld"], "Field")]), Case( Variable("Fld"), [(Variable(f.affixed_name), TRUE if f in composite_fields else FALSE) for f in message.fields], ), ), SubprogramBody( FunctionSpecification( "Get_Field_Value", "Field_Dependent_Value", [ Parameter(["Ctx"], "Context"), Parameter(["Fld"], "Field") ], ), [ *common.field_bit_location_declarations( Variable("Fld")), *common.field_byte_location_declarations(), *unique( self.extract_function(common.full_base_type_name( t)) for t in message.types.values() if isinstance(t, Scalar)), ] if scalar_fields else [], [ ReturnStatement( Case( Variable("Fld"), [(Variable(f.affixed_name), result(f, message)) for f in message.fields], )) ], [ Precondition( AndThen( Call("Has_Buffer", [Variable("Ctx")]), Call("Valid_Next", [Variable("Ctx"), Variable("Fld")]), Call("Sufficient_Buffer_Length", [Variable("Ctx"), Variable("Fld")]), )), Postcondition( Equal( Selected(Result("Get_Field_Value"), "Fld"), Variable("Fld"), )), ], ), ], )