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 |
op ::= op-name |
spec ::= spec-form |
spec
type Even
op next : Even -> Even
axiom nextEffect is
fa(x : Even) ~(next x = x)
endspec |
Each model has to respect typing; 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 claims (axioms, theorems and conjectures) of the spec have to be satisfied in the model. The axiom labeled nextEffect above states that the function assigned to op next maps any value of the type assigned to type-name Even to a different value. So the squaring function, although type-respecting, could not be assigned to next since it maps 0 to itself.
If all type-respecting combinations of assignments of types to type-names and values to ops fail the one or more claims, the spec has no models and is called inconsistent. Although usually undesirable, an inconsistent spec is not by itself considered ill formed. 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 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 simple-name) are "hidden"; any use of the simple-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 |
Next to the general requirement that each model respects typing, there are specific restrictions for various constructs that constrain the possible types for the components. For example, in an application f(x), the type of the actual-parameter x has to match the domain type of function f. These requirements are stated in the relevant sections of this language manual. If no type-respecting combinations of assignments meeting all these requirements exist for a given spec, it is considered type-incorrect and therefore ill formed. This is determined by Specware while elaborating the spec, and signaled as an error. Type-incorrectness differs from inconsistency in that the meaning of the claims does not come into play, and the question whether an ill-formed spec is consistent is moot.
To be precise, there are subtle and less subtle differences between type-incorrectness of a spec and its having no type-respecting combinations of assignments. For example, the following spec is type-correct but has no models:
spec
type Empty = | Just Empty
op IdoNotExist : Empty
endspec |
Here is a type-incorrect spec that has type-respecting combinations of assignments:
spec
type Outcome = | Positive | Negative
type 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 type-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 type of a type-name without definition is not constructive. A type is only constructive if all component types are. An op without definition is non-constructive, and so is an op whose type is non-constructive. A quantification is non-constructive. The polymorphic inbuilt-op = for testing equality and its inequality counterpart ~= are only constructive for discrete types (see below).
A type is called discrete if the equality predicate = for that type is constructive. The inbuilt and base-library types Boolean, Integer, NonZeroInteger, Nat, PosNat, Char, String and Compare are all discrete. Types List T and Option T are discrete when T is. All function types are non-discrete (even when the domain type is the unit type). Sum types, product types and record types are discrete whenever all component types are. Subtype (T | P) is discrete when supertype T is. (Predicate P need not be constructive: the equality test is that of the supertype.) Quotient type T / Q is discrete when predicate Q is constructive. (Type T need not be discrete: the equality test on the quotient type is just the predicate Q applied to pairs of members of the Q-equivalence classes.)