This chapter introduces the Metaslang specification language.
The following sections give the grammar rules and meaning for each Metaslang language construct.
The grammar rules used to describe the Metaslang language use the conventions of (extended) BNF. For example, a grammar rule like:
wiffle ::= waffle [ waffle-tail ] | piffle { + piffle }* |
In the grammar rules terminal symbols appear in a bold font. Some of the terminal symbols used, like | and {, are very similar to the grammar signs like | and { as described above. They can hopefully be distinguished by their bold appearance.
Grammar rules may be recursive: a construct may be defined in terms of itself, directly or indirectly. For example, given the rule:
piffle ::= 1 | M { piffle }* |
1 M M1 M111 MMMM M1M1 |
spec ::= spec-form op ::= op-name |
spec
sort Even
op next : Even -> Even
axiom nextEffect is
fa(x : Even) ~(next x = x)
endspec |
Each model has to respect sorting; for example, given the above assignment to Even, the function that increments a number by 1 does not map all even numbers to even numbers, and therefore can not -- in the same model -- be assigned to next. Additionally, the axioms of the spec have to be satisfied by the model. The axiom labeled nextEffect above states that the function assigned to op-name next maps any value of the sort assigned to sort-name Even to a different value. So the squaring function, although sort-respecting, could not be assigned to next since it maps 0 to itself.
If all sort-respecting combinations of assignments of sorts to sort-names and ops to op-names fail the axioms test, the spec has no models and is called inconsistent. Although usually undesirable, an inconsistent spec is not by itself considered erroneous. The Specware system does not attempt to detect inconsistencies, but associated provers can sometimes be used to find them. Not always; in general it is undecidable whether a spec is consistent or not.
In general, the meaning of a construct in a model depends on the assignments of that model, and more generally on an environment: a model possibly extended with assignments to local-variables. For example, the meaning of the claim fa(x : Even) ~(next x = x) in the axiom nextEffect depends on the meanings of Even and next, while the sub-expression next x, for example, also depends on an assignment (of an "even" value) to x. To avoid laborious phrasings, the semantic descriptions use language like "the function next applied to x" as shorthand for this lengthy phrase: "the function assigned in the environment to next applied to the value assigned in the environment to x".
When an environment is extended with an assignment to a local-variable, any assignments to synonymous ops or other local-variables are superseded by the new assignment in the new environment. In terms of Metaslang text, within the scope of the binding of local-variables, synonymous ops and earlier introduced local-variables (that is, having the same name) are "hidden"; any use of the name in that scope refers to the textually most recently introduced local-variable. For example, given:
def x = "op-x"
def y = let v = "let-v" in x
def z = let x = "let-x" in x |
If no sort-respecting combinations of assignments exist for a given spec, it is considered incorrect, and is said to have a sort error (or type error). This is determined by Specware while elaborating the spec, and signaled as an error. Sort-incorrectness differs from inconsistency in that the meaning of the axioms does not come into play, and the question whether an incorrect spec is consistent is moot.
To be precise, there are subtle and less subtle differences between sort-incorrectness of a spec and its having no sort-respecting combinations of assignments. For example, the following spec is sort-correct but has no models:
spec
sort Empty = | Just Empty
op IdoNotExist : Empty
endspec |
Here is a sort-incorrect spec that has sort-respecting combinations of assignments:
spec
sort Outcome = | Positive | Negative
sort Sign = | Positive | Zero | Negative
def whatAmI = Positive
endspec |
def whatAmI : Sign = Positive
def whatAmI = Positive : Sign |
op signToNat : Sign -> Nat
def sw = signToNat whatAmI |
When code is generated for a spec, complete "self-contained" code is only generated for sort-definitions and op-definitions that are fully constructive. Non-constructiveness is "contagious": a definition is only constructive if all components of the definition are. The sort of a sort-name without definition is not constructive. A sort is only constructive if all component sorts are. An op without definition is non-constructive, and so is an op whose sort is non-constructive. A quantification is non-constructive. The built-in polymorphic equality predicate = is only constructive for discrete sorts (see below).
A sort is called discrete if the equality predicate = for that sort is constructive. The built-in sorts Integer, Nat, Boolean, Char and String are all discrete. Sort List S is discrete when S is. All function sorts are non-discrete (even when the domain sort is the unit sort). Sum sorts, product sorts and record sorts are discrete whenever all component sorts are. Subsort (S | P) is discrete when supersort S is. (Predicate P need not be constructive: the equality test is that of the supersort.) Quotient sort S / Q is discrete when predicate Q is constructive. (Sort S need not be discrete: the equality test on the quotient sort is just the predicate Q applied to pairs of members of the Q-equivalence classes.)