Common use of Operational Semantics Clause in Contracts

Operational Semantics. In general the operational semantics of the specification language is very similar to the operational semantics of the original programming language. In particular, the internal steps remain the same. Regarding the inference rules of the external steps, the crucial point is that we have to narrow down the communication steps such that the resulting trace semantics of the specification consists only of the specified traces (and their prefixes). This is implemented, on the one hand, by additional premises and, on the other hand, by allowing incoming communication only if a corresponding communication term is on top of the call stack. The different handling of interface communication as well as the absence of internal method and constructor calls also leads to a somewhat different, i.e., simpler, form of the call stack of a specification. For, the execution of a program never adds or removes an activation record but each inference rule only modifies the topmost activation record. Although this means that the call stack does not consist of several blocked and possibly one active activation record, we still dis- tinguish activation records which only allow incoming communication as the next interface communication from activation records which only allow outgoing com- munication as the next interface communication. Thus, for the activation records of the specification language we define AR ::= ARa | ARp ARa ::= (µ, mcact) ARp ::= (µ, mcpsv) mcact ::= sact | sact ; !return(e); ▇▇▇▇▇ mcpsv ::= spsv | spsv ; x =?return(T x).where(e); mcact The rules of the operational semantics are given in Table 3.3. The rules ▇▇▇▇▇ and NewO deal with outgoing method and, respectively, constructor call statements. Just as the corresponding rules of the programming language, the expressions within the actual call term are evaluated and the transi- tion is labeled with an outgoing call label. However, in the resulting configuration, the call stack is not blocked by a receive statement but instead only the actual call term of the statement is removed leaving the body of the call statement on top of the call stack. For, the body of the call statement comprises the desired tester/environment interactions that should occur until the call’s incoming return occurs. The variable structure is extended by a variable function for the local variables of the call statement. Note that, although ▇▇▇▇▇ and NewO resemble the corresponding rules of the programming language we do not add an activa- tion record as we did in the semantics of the programming language. Otherwise the local variables of this call statement wouldn’t be accessible by the body state- ment. Finally, the return statement is annotated with the return type of the called method or, respectively, the callee’s class name. sact = e!m(e) {T x; spsv ; x =?return(T x').where(e')} where o = [e ]v,µ, a = ν(Θ').(call o.m(v)⟩! o ∈ dom(∆) v = [e ]v,µ, 2h [▇▇▇▇▇] ∆ ▶ (h, v, (µ, sact ; mcact) ◦ CS) : Θ −→a ∆ ▶ (h, v, (vl·µ, spsv ; x =?return(T x').where(e'); mcact) ◦ CS) : Θ, Θ' sact = new!C(e) {T x; spsv ; x =?return(C x').where(e')} T = ∆ (o)(m).ran, Θ' = new(h, v, Θ), and vl = {x '→ ▇▇▇▇(T )} where v = [e ]v,µ, [NewO] a = ν(Θ ).(new C(v)⟩! C ∈ dom(∆) Θ' = new (h, v, Θ), and ∆ ▶ (h, v, (µ, sact ; mcact) ◦ CS) : Θ −→a ∆ ▶ (h, v, (vl·µ, spsv ; x =?return(C x').where(e'); mcact ◦ CS) : Θ, Θ' vl = {x '→ ▇▇▇▇(T )} a = ν(Θ').(return(v)⟩! ∆ ▶ (h, v, (v ·µ, !return e; mcact) ◦ CS) : Θ −→a where v = [e ]v,vl·µ and ∆ ▶ (h, v, (µ, mcact) ◦ CS) : Θ, Θ' spsv = (C x)?m(T x).where(e') {Tl xl; sact ; !return e} a = ν(∆'). call o.m(v) ? C = Θ(o) Θ a : ∆ [e' ]v,vl·µ = true [CallI] h Θ = new(h, v, Θ) where vl = {x '→ o, x '→ v, ∆ ▶ (h, v, (µ, spsv ; mcpsv ) ◦ CS) : Θ −→a ∆, ∆' ▶ (h, v, (vl·µ, sact ; !return e; mcpsv ◦ CS) : Θ spsv = new?(C x)C(T x).where(e') {Tl xl; sact ; !return} a = ν(∆'). new C(v) ? C dom(Θ) Θ a : ∆ [e ]v,vl·µ = true [NewI] h xl '→ ▇▇▇▇(Tl)} where o ∈ N \ dom(h), h' = h[o '→ Obj C ], ∆ ▶ (h, v, (µ, s ; mc act ) ◦ CS) : Θ −→a and ⊥ v = {x '→ o, x '→ v, ∆, ∆' ▶ (h', v, (vl·µ, sact ; !return x; mcact) ◦ CS) : Θ a = ν(∆').(return(v)⟩? ∆ ▶ a : Θ ∆, ∆', Θ ▶ v:T [e ]v,{x''→v}·vl·µ = true [RetI] h ∆ ▶ (h, v, v ·µ, x =?return(T x').where(e); mcact ◦ CS) : Θ −→ xl '→ ▇▇▇▇(Tl)} where (v', vl' ·µ') = v, v ·µ, x '→ v) ∆, ∆' ▶ (h, v', (µ', mcact) ◦ CS) : Θ stmtin = (C x)?m(T x).where(e') {Tl xl; sact ; !return e} a = ν(∆'). call o.m(v) ? C = Θ(o) Θ a : ∆ [e' ]v,vl·µ = true where stmtin ; stmt' [CaseIC ] h ∆ ▶ (h, v, (µ, case {stmt}; mcpsv) ◦ CS) : Θ −→a ∆, ∆' ▶ (h, v, (vl·µ, sact ; !return e; stmt'; mcpsv ◦ CS) : Θ stmtin = new?(C x)C(T x).where(e') {Tl xl; sact ; !return} a = ν(∆'). new C(v) ? C dom(Θ) Θ a : ∆ [e ]v,vl·µ = true [CaseIN ] h ∆ ▶ (h, v, (µ, case {stmt}; mcpsv ) ◦ CS) : Θ −→a ∆, ∆' ▶ (h', v, (vl·µ, sact ; !return x; mcact) ◦ CS) : Θ T x = mparams(C, m), and vl = {x '→ o, x '→ v, xl '→ ▇▇▇▇(Tl)} where stmtin ; stmt ∈ stmt T x = mparams(C, m), and v = {x '→ o, x '→ v, xl '→ ▇▇▇▇(Tl)} Table 3.3: Specification language for Japl: operational semantics (external) The rule RetO is almost identical to the former version, except that we do not have to remove an activation record from the call stack. Likewise, we only remove a variable function but not a method variable structure. The rules CallI and NewI can only be applied if the statement on top of the stack frame is indeed an incoming method call statement or an incoming constructor call statement, respectively. Additionally, we add a premise which asserts that the where-clause condition evaluates to true. The evaluation uses a variable context which is already extended by the formal parameters of the call terms, as the where-clause expression might contain references to parameters. Again, only the call term is removed from the call stack. Rule RetI deals with the incoming return term, which has been annotated with the proper return type. After the transition, the variable context is shortened by the top most variable function, since it represented the variables of the call statement which the return term belonged to. Note, that we first updated the old variable context with the incoming return value since we do not know whether the target variable was part of the call statement’s variables. The last rules CaseIC and CaseIN deal with the case statement. These rules are applicable exactly if rule CallI or rule NewI is applicable for at least one of its branches. One might think, it would be more straightforward to provide an internal rule which just reduces the case statement non-deterministically to one of its branches. However, not the specification but the external component should non-deterministically choose a branch. Leaving a statement on top of the stack frame after an outgoing call term has been processed, results in a crucial change of the language. Right after the call, the program is not blocked waiting for an incoming communication but it still can proceed. Although the type system ensures that assignments may not occur right after an outgoing call, still while-loops and conditional statements may be processed by means of internal communication steps. Thus, regarding internal computation steps, the specification language breaks the control flow requirement here. However, concerning the interface communication, also a specification still sticks to this requirement. For, the typing rules do not allow a nesting of statement which results in two consecutive incoming or two consecutive outgoing commu- nication terms. As a consequence, the traces of a specification program always satisfy the control flow requirement. Allowing while-loops and conditional statements in a passive control context, however, eases the definition of trace-based specifications. A while-loop in a pas- sive control context allows to specify repetitions of incoming calls where the exact number of repetitions depends on the incoming values and is, thus, not known statically. Conditional statements in a passive control context allow to specify different expectations depending on conditions unknown statically. Remark 3.4.1: Note, the lack of class definitions implies that all transition rules do not depend on the specification code. That is, we do not have to index transition steps by a specification.

Appears in 1 contract

Sources: License Agreement

Operational Semantics. In general the operational semantics of the specification language is very similar to the operational semantics of the original programming language. In particular, the internal steps remain the same. Regarding the inference rules of the external steps, the crucial point is that we have to narrow down the communication steps such that the resulting trace semantics of the specification consists only of the specified traces (and their prefixes). This is implemented, on the one hand, by additional premises and, on the other hand, by allowing incoming communication only if a corresponding communication term is on top of the call stack. The different handling of interface communication as well as the absence of internal method and constructor calls also leads to a somewhat different, i.e., simpler, form of the call stack of a specification. For, the execution of a program never adds or removes an activation record but each inference rule only modifies the topmost activation record. Although this means that the call stack does not consist of several blocked and possibly one active activation record, we still dis- tinguish activation records which only allow incoming communication as the next interface communication from activation records which only allow outgoing com- munication as the next interface communication. Thus, for the activation records of the specification language we define AR ::= ARa | ARp ARa ::= (µ, mcact) ARp ::= (µ, mcpsv) mcact ::= sact | sact ; !return(e); ▇▇▇▇▇ mcpsv ::= spsv | spsv ; x =?return(T x).where(e); mcact The rules of the operational semantics are given in Table 3.3. The rules ▇▇▇▇▇ and NewO deal with outgoing method and, respectively, constructor call statements. Just as the corresponding rules of the programming language, the expressions within the actual call term are evaluated and the transi- tion is labeled with an outgoing call label. However, in the resulting configuration, the call stack is not blocked by a receive statement but instead only the actual call term of the statement is removed leaving the body of the call statement on top of the call stack. For, the body of the call statement comprises the desired tester/environment interactions that should occur until the call’s incoming return occurs. The variable structure is extended by a variable function for the local variables of the call statement. Note that, although ▇▇▇▇▇ and NewO resemble the corresponding rules of the programming language we do not add an activa- tion record as we did in the semantics of the programming language. Otherwise the local variables of this call statement wouldn’t be accessible by the body state- ment. Finally, the return statement is annotated with the return type of the called method or, respectively, the callee’s class name. sact = e!m(e) {T x; spsv ; x =?return(T x').where(e'xr).where(er)} where o = [e ][ e] v,µ, a = ν(Θ').(call o.m(v)⟩ν(Θr).(call o.m(v))! o ∈ dom(∆) v = [e ][ e] v,µ, 2h [▇▇▇▇▇CallO] ∆ (h, v, (µ, sact ; mcact) ◦ CS) : Θ −→a ∆ (h, v, (vl·µ, spsv ; x =?return(T x').where(e'xr).where(er); mcact) ◦ CS) : Θ, Θ' Θr sact = new!C(e) {T x; spsv ; x =?return(C x').where(e'xr).where(er)} T = ∆ (o)(m).ran, Θ' Θr = new(h, v, Θ), and vl = {x '→ ▇▇▇▇(T ›→ ival(T )} where v = [e ][ e] v,µ, [NewO] a = ν(Θ ).(new C(v)⟩C(v))! C ∈ dom(∆) Θ' Θr = new (h, v, Θ), and ∆ (h, v, (µ, sact ; mcact) ◦ CS) : Θ −→a ∆ (h, v, (vl·µ, spsv ; x =?return(C x').where(e'xr).where(er); mcact ◦ CS) : Θ, Θ' Θr vl = {x '→ ▇▇▇▇(T ›→ ival(T )} a = ν(Θ').(return(v)⟩ν(Θr).(return(v))! ∆ (h, v, (v ·µ, !return e; mcact) ◦ CS) : Θ −→a where v = [e ][ e] v,vl·µ and ∆ (h, v, (µ, mcact) ◦ CS) : Θ, Θ' spsv = (C x)?m(T x).where(e') {Tl xl; sact ; !return e} a = ν(∆'). call o.m(v) ? C = Θ(o) Θ a : ∆ [e' ]v,vl·µ = true [CallI] h Θ = new(h, v, Θ) where vl = {x '→ o, x '→ v, ∆ ▶ (h, v, (µ, spsv ; mcpsv ) ◦ CS) : Θ −→a ∆, ∆' ▶ (h, v, (vl·µ, sact ; !return e; mcpsv ◦ CS) : Θ spsv = new?(C x)C(T x).where(e') {Tl xl; sact ; !return} a = ν(∆'). new C(v) ? C dom(Θ) Θ a : ∆ [e ]v,vl·µ = true [NewI] h xl '→ ▇▇▇▇(Tl)} where o ∈ N \ dom(h), h' = h[o '→ Obj C ], ∆ ▶ (h, v, (µ, s ; mc act ) ◦ CS) : Θ −→a and ⊥ v = {x '→ o, x '→ v, ∆, ∆' ▶ (h', v, (vl·µ, sact ; !return x; mcact) ◦ CS) : Θ a = ν(∆').(return(v)⟩? ∆ ▶ a : Θ ∆, ∆', Θ ▶ v:T [e ]v,{x''→v}·vl·µ = true [RetI] h ∆ ▶ (h, v, v ·µ, x =?return(T x').where(e); mcact ◦ CS) : Θ −→ xl '→ ▇▇▇▇(Tl)} where (v', vl' ·µ') = v, v ·µ, x '→ v) ∆, ∆' ▶ (h, v', (µ', mcact) ◦ CS) : Θ stmtin = (C x)?m(T x).where(e') {Tl xl; sact ; !return e} a = ν(∆'). call o.m(v) ? C = Θ(o) Θ a : ∆ [e' ]v,vl·µ = true where stmtin ; stmt' [CaseIC ] h ∆ ▶ (h, v, (µ, case {stmt}; mcpsv) ◦ CS) : Θ −→a ∆, ∆' ▶ (h, v, (vl·µ, sact ; !return e; stmt'; mcpsv ◦ CS) : Θ stmtin = new?(C x)C(T x).where(e') {Tl xl; sact ; !return} a = ν(∆'). new C(v) ? C dom(Θ) Θ a : ∆ [e ]v,vl·µ = true [CaseIN ] h ∆ ▶ (h, v, (µ, case {stmt}; mcpsv ) ◦ CS) : Θ −→a ∆, ∆' ▶ (h', v, (vl·µ, sact ; !return x; mcact) ◦ CS) : Θ T x = mparams(C, m), and vl = {x '→ o, x '→ v, xl '→ ▇▇▇▇(Tl)} where stmtin ; stmt ∈ stmt T x = mparams(C, m), and v = {x '→ o, x '→ v, xl '→ ▇▇▇▇(Tl)} Table 3.3: Specification language for Japl: operational semantics (external) The rule RetO is almost identical to the former version, except that we do not have to remove an activation record from the call stack. Likewise, we only remove a variable function but not a method variable structure. The rules CallI and NewI can only be applied if the statement on top of the stack frame is indeed an incoming method call statement or an incoming constructor call statement, respectively. Additionally, we add a premise which asserts that the where-clause condition evaluates to true. The evaluation uses a variable context which is already extended by the formal parameters of the call terms, as the where-clause expression might contain references to parameters. Again, only the call term is removed from the call stack. Rule RetI deals with the incoming return term, which has been annotated with the proper return type. After the transition, the variable context is shortened by the top most variable function, since it represented the variables of the call statement which the return term belonged to. Note, that we first updated the old variable context with the incoming return value since we do not know whether the target variable was part of the call statement’s variables. The last rules CaseIC and CaseIN deal with the case statement. These rules are applicable exactly if rule CallI or rule NewI is applicable for at least one of its branches. One might think, it would be more straightforward to provide an internal rule which just reduces the case statement non-deterministically to one of its branches. However, not the specification but the external component should non-deterministically choose a branch. Leaving a statement on top of the stack frame after an outgoing call term has been processed, results in a crucial change of the language. Right after the call, the program is not blocked waiting for an incoming communication but it still can proceed. Although the type system ensures that assignments may not occur right after an outgoing call, still while-loops and conditional statements may be processed by means of internal communication steps. Thus, regarding internal computation steps, the specification language breaks the control flow requirement here. However, concerning the interface communication, also a specification still sticks to this requirement. For, the typing rules do not allow a nesting of statement which results in two consecutive incoming or two consecutive outgoing commu- nication terms. As a consequence, the traces of a specification program always satisfy the control flow requirement. Allowing while-loops and conditional statements in a passive control context, however, eases the definition of trace-based specifications. A while-loop in a pas- sive control context allows to specify repetitions of incoming calls where the exact number of repetitions depends on the incoming values and is, thus, not known statically. Conditional statements in a passive control context allow to specify different expectations depending on conditions unknown statically. Remark 3.4.1: Note, the lack of class definitions implies that all transition rules do not depend on the specification code. That is, we do not have to index transition steps by a specification.Θr

Appears in 1 contract

Sources: License Agreement Concerning Inclusion of Doctoral Thesis in the Institutional Repository of the University of Leiden

Operational Semantics. In general the operational semantics of the specification language is very similar to the operational semantics of the original programming language. In particular, the internal steps remain the same. Regarding the inference rules of the external steps, the crucial point is that we have to narrow down the communication steps such that the resulting trace semantics of the specification consists only of the specified traces (and their prefixes). This is implemented, on the one hand, by additional premises and, on the other hand, by allowing incoming communication only if a corresponding communication term is on top of the call stack. The different handling of interface communication as well as the absence of internal method and constructor calls also leads to a somewhat different, i.e., simpler, form of the call stack of a specification. For, the execution of a program never adds or removes an activation record but each inference rule only modifies the topmost activation record. Although this means that the call stack does not consist of several blocked and possibly one active activation record, we still dis- tinguish activation records which only allow incoming communication as the next interface communication from activation records which only allow outgoing com- munication as the next interface communication. Thus, for the activation records of the specification language we define AR ::= ARa | ARp ARa ::= (µ, mcact) ARp ::= (µ, mcpsv) mcact ::= sact | sact ; !return(e); ▇▇▇▇▇ mcpsv ::= spsv | spsv ; x =?return(T x).where(e); mcact The rules of the operational semantics are given in Table 3.3. The rules ▇▇▇▇▇ and NewO deal with outgoing method and, respectively, constructor call statements. Just as the corresponding rules of the programming language, the expressions within the actual call term are evaluated and the transi- tion is labeled with an outgoing call label. However, in the resulting configuration, the call stack is not blocked by a receive statement but instead only the actual call term of the statement is removed leaving the body of the call statement on top of the call stack. For, the body of the call statement comprises the desired tester/environment interactions that should occur until the call’s incoming return occurs. The variable structure is extended by a variable function for the local variables of the call statement. Note that, although ▇▇▇▇▇ and NewO resemble the corresponding rules of the programming language we do not add an activa- tion record as we did in the semantics of the programming language. Otherwise the local variables of this call statement wouldn’t be accessible by the body state- ment. Finally, the return statement is annotated with the return type of the called method or, respectively, the callee’s class name. sact = e!m(e) {T x; spsv ; x =?return(T x').where(e')} where o = [e ]v,µ, , a = ν(Θ').(call o.m(v)⟩! o ∈ dom(∆) v = [e ]v,µ, 2h [▇▇▇▇▇CallO] ∆ ▶ (h, v, (µ, sact ; mcact) ◦ CS) : Θ −→a ∆ ▶ (h, v, (vl·µ, spsv ; x =?return(T x').where(e'); mcact) ◦ CS) : Θ, Θ' sact = new!C(e) {T x; spsv ; x =?return(C x').where(e')} T = ∆ (o)(m).ran, Θ' = new(h, v, Θ), and vl = {x '→ ▇▇▇▇(T ival(T )} where v = [e ]v,µ, [NewO] a = ν(Θ ).(new C(v)⟩! C ∈ dom(∆) Θ' = new (h, v, Θ), and ∆ ▶ (h, v, (µ, sact ; mcact) ◦ CS) : Θ −→a ∆ ▶ (h, v, (vl·µ, spsv ; x =?return(C x').where(e'); mcact ◦ CS) : Θ, Θ' vl = {x '→ ▇▇▇▇(T ival(T )} a = ν(Θ').(return(v)⟩! ∆ ▶ (h, v, (v ·µ, !return e; mcact) ◦ CS) : Θ −→a where v = [e ]v,vl·µ and ∆ ▶ (h, v, (µ, mcact) ◦ CS) : Θ, Θ' spsv = (C x)?m(T x).where(e') {Tl xl; sact ; !return e} a = ν(∆'). call o.m(v) ? C = Θ(o) Θ a : ∆ [e' ]v,vl·µ = true [CallI] h Θ = new(h, v, Θ) where vl = {x '→ o, x '→ v, ∆ ▶ (h, v, (µ, spsv ; mcpsv ) ◦ CS) : Θ −→a ∆, ∆' ▶ (h, v, (vl·µ, sact ; !return e; mcpsv ◦ CS) : Θ spsv = new?(C x)C(T x).where(e') {Tl xl; sact ; !return} a = ν(∆'). new C(v) ? C dom(Θ) Θ a : ∆ [e ]v,vl·µ = true [NewI] h xl '→ ▇▇▇▇(Tl)} where o ∈ N \ dom(h), h' = h[o '→ Obj C ], ∆ ▶ (h, v, (µ, s ; mc act ) ◦ CS) : Θ −→a and ⊥ v = {x '→ o, x '→ v, ∆, ∆' ▶ (h', v, (vl·µ, sact ; !return x; mcact) ◦ CS) : Θ a = ν(∆').(return(v)⟩? ∆ ▶ a : Θ ∆, ∆', Θ ▶ v:T [e ]v,{x''→v}·vl·µ = true [RetI] h ∆ ▶ (h, v, v ·µ, x =?return(T x').where(e); mcact ◦ CS) : Θ −→ xl '→ ▇▇▇▇(Tl)} where (v', vl' ·µ') = v, v ·µ, x '→ v) ∆, ∆' ▶ (h, v', (µ', mcact) ◦ CS) : Θ stmtin = (C x)?m(T x).where(e') {Tl xl; sact ; !return e} a = ν(∆'). call o.m(v) ? C = Θ(o) Θ a : ∆ [e' ]v,vl·µ = true where stmtin ; stmt' [CaseIC ] h ∆ ▶ (h, v, (µ, case {stmt}; mcpsv) ◦ CS) : Θ −→a ∆, ∆' ▶ (h, v, (vl·µ, sact ; !return e; stmt'; mcpsv ◦ CS) : Θ stmtin = new?(C x)C(T x).where(e') {Tl xl; sact ; !return} a = ν(∆'). new C(v) ? C dom(Θ) Θ a : ∆ [e ]v,vl·µ = true [CaseIN ] h ∆ ▶ (h, v, (µ, case {stmt}; mcpsv ) ◦ CS) : Θ −→a ∆, ∆' ▶ (h', v, (vl·µ, sact ; !return x; mcact) ◦ CS) : Θ T x = mparams(C, m), and vl = {x '→ o, x '→ v, xl '→ ▇▇▇▇(Tl)} where stmtin ; stmt ∈ stmt T x = mparams(C, m), and v = {x '→ o, x '→ v, xl '→ ▇▇▇▇(Tl)} Table 3.3: Specification language for Japl: operational semantics (external) The rule RetO is almost identical to the former version, except that we do not have to remove an activation record from the call stack. Likewise, we only remove a variable function but not a method variable structure. The rules CallI and NewI can only be applied if the statement on top of the stack frame is indeed an incoming method call statement or an incoming constructor call statement, respectively. Additionally, we add a premise which asserts that the where-clause condition evaluates to true. The evaluation uses a variable context which is already extended by the formal parameters of the call terms, as the where-clause expression might contain references to parameters. Again, only the call term is removed from the call stack. Rule RetI deals with the incoming return term, which has been annotated with the proper return type. After the transition, the variable context is shortened by the top most variable function, since it represented the variables of the call statement which the return term belonged to. Note, that we first updated the old variable context with the incoming return value since we do not know whether the target variable was part of the call statement’s variables. The last rules CaseIC and CaseIN deal with the case statement. These rules are applicable exactly if rule CallI or rule NewI is applicable for at least one of its branches. One might think, it would be more straightforward to provide an internal rule which just reduces the case statement non-deterministically to one of its branches. However, not the specification but the external component should non-deterministically choose a branch. Leaving a statement on top of the stack frame after an outgoing call term has been processed, results in a crucial change of the language. Right after the call, the program is not blocked waiting for an incoming communication but it still can proceed. Although the type system ensures that assignments may not occur right after an outgoing call, still while-loops and conditional statements may be processed by means of internal communication steps. Thus, regarding internal computation steps, the specification language breaks the control flow requirement here. However, concerning the interface communication, also a specification still sticks to this requirement. For, the typing rules do not allow a nesting of statement which results in two consecutive incoming or two consecutive outgoing commu- nication terms. As a consequence, the traces of a specification program always satisfy the control flow requirement. Allowing while-loops and conditional statements in a passive control context, however, eases the definition of trace-based specifications. A while-loop in a pas- sive control context allows to specify repetitions of incoming calls where the exact number of repetitions depends on the incoming values and is, thus, not known statically. Conditional statements in a passive control context allow to specify different expectations depending on conditions unknown statically. Remark 3.4.1: Note, the lack of class definitions implies that all transition rules do not depend on the specification code. That is, we do not have to index transition steps by a specification.

Appears in 1 contract

Sources: License Agreement Concerning Inclusion of Doctoral Thesis in the Institutional Repository of the University of Leiden