This is a difficult question to get across because I don't think there is an established term for what I'm asking about. In the title I've called it "ways" of executing statements, but I mean something specific.
Background
Imperative languages typically have statements which "do something when they are executed". If the language's semantics are defined operationally then a specification might look something like this:
- An
ifstatement has an expression and a sub-statement. When anifstatement is executed, the expression is evaluated, and if its result is truthy then the sub-statement is executed; otherwise nothing happens.- A
whilestatement has an expression and a sub-statement. When awhilestatement is executed, the expression is evaluated, and if its result is truthy then the sub-statement is executed and then thewhilestatement is executed again; otherwise, nothing happens.- A
returnstatement has an expression. When areturnstatement is executed, the expression is evaluated, and the statement completes abruptly by causing the enclosing function to return with the expression's result.- ...
A full specification for a typical language like this must list, for each kind of statement, what happens "when that statement is executed".
My language MJr is not quite like that. There are two different ways of executing a statement ─ they can be "executed normally", or they can be "reset". In particular, the specification defines not just "when an X statement is executed" but also "when an X statement is reset". This is defined for every statement in the language; I'll try to simplify and omit irrelevant details:
- A
convchainstatement has [...] and a boolean flag at runtime. When aconvchainstatement is executed normally, if the flag is false then the flag is set to true and [...]; otherwise [...]. When aconvchainstatement is reset, the flag is set to false.- A
@limitstatement has an expression and a sub-statement, and a counter at runtime. When a@limitstatement is executed normally, if the counter is greater than zero then the sub-statement is executed normally, and the counter is decremented if the sub-statement succeeds; otherwise [...]. When a@limitstatement is reset, the expression is evaluated and its result is assigned to the counter, and the sub-statement is reset.- A
sequencestatement has a list of sub-statements. When asequencestatement is executed normally, each sub-statement is reset, then each sub-statement in turn is repeatedly executed normally until it does not succeed. When asequencestatement is reset, nothing happens.- A
markovstatement has a list of sub-statements. When amarkovstatement is executed normally, each sub-statement is reset, then repeatedly the sub-statements are executed normally, in turn starting from the first sub-statement, until one succeeds; this ends when no sub-statement succeeds. When amarkovstatement is reset, nothing happens.- ...
The exact details don't matter for this question; what matters is that there are two verbs, "execute normally" and "reset", and the semantics of the language define both "when S is executed normally" and "when S is reset", for each statement S. Both are things done at runtime and are part of the program's observable behaviour.
The timing of when each statement is "executed normally" or "reset" is determined by control-flow statements like sequence and markov, which each invoke both behaviours of their sub-statements when they are executed normally.
This is quite different from typical imperative languages, which only define one verb for executing a statement. A more concrete way of thinking about this might be that an interpreter for the language would have an execute() method and a reset() method for each statement node in the AST, where a typical language would only have one execute() method on each statement node. (In the interpreter for MarkovJunior, which MJr is based on, these methods are named Go() and Reset().) However, this question is not specifically about interpreters.
The question
What other languages (if any) have operational semantics with multiple "verbs" for executing statements, such that the language defines each verb for each kind of statement? I am interested in languages like this whether or not it has actually been spelled out in a formal specification.
Canmetafunction. Does this count as interpreting the same statements in different ways? $\endgroup$