Beta-release of the CBS framework
All references to names of funcons (etc.) in CBS specifications are hyperlinks leading to their declarations.
These hyperlinks avoid the need to drill down through the hierarchy of folders and files. Specifications in CBS are independent of the file system: all names declared in Funcons-beta are globally visible, and names declared in a particular language specification are local to that language, regardless of file structure.
The global Funcons-Index page lists the names of all current funcons, grouped according to their types. The local funcons-index page for a particular language lists only the names of the funcons actually used in its specification. The funcon reuse page shows which of the included languages reference each funcon.
Hovering on a reference to a funcon displays the declared arity of symbol:
values
stands for a single argument, and values*
for any number of
arguments.
The large button at the top right of each CBS page is a fixed drop-down menu.
For pages in Funcons-beta
, it has the following links:
For pages in Languages-beta/L
, it has also the following links:
L-Start
: the root of the CBS of language L
(which includes links to
all the other sections for that language)L-Funcons-Index
: the index of funcons used for language L
When a CBS web page is opened, all the rules, comments, and subsections are unfolded, as indicated by downward-pointing disclosure symbols (e.g.: ▼).
Sequences of rules, individual comments, and subsections can be folded/unfolded by clicking on a character in the line containing the disclosure symbol. Note that printing the page omits the disclosure symbols, but does not show lines hidden by the current folding.
The top right corner of each CBS web page has buttons for unfolding (▼) or folding (►) all rules, comments, or subsections on the current page. (These buttons require Javascript, and are not shown when Javascript is off.)
See the CBS of IMP for illustration of the following points.
Each file of the definition of a language L
starts with the line
Language "L"
. Splitting a language definition across multiple files
(within the same project) does not affect its well-formedness.
Language definitions can be split into numbered sections. A section number is
written #n
, where n
can be a series of numbers or (single) letters,
separated by dots. Section numbers are hyperlinks in a table of contents,
which is written [...]
, and in multi-line comments /*...*/
.
Multi-line comments are written /*...*/
, and may include funcon terms
(delimited by back-ticks `
). End-of-line comments are written //...
.
Syntax
introduces one or more grammar productions for the
abstract (context-free) syntax of the language, together with meta-variables
ranging over the associated sorts of ASTs.
-
.start
.Pgm
.::=
.'...'
.|
. All alternatives for the same
nonterminal have to be specified together.?
for optional parts,
*
for iteration, +
for non-empty iteration, and grouping parentheses
(...)
.Syntax
,
but it can be excluded between two symbols by inserting an underscore _
,
e.g., num ::= '-'?_decimal
.Lexis
introduces one or more grammar productions for the
lexical (regular or context-free) syntax of the language, together with
meta-variables ranging over the specified strings of characters.
'c1'
to 'c2'
is specified by 'c1'-'c2'
.
For example, decimal
is defined as ('0'-'9')+
.Lexis
.Lexis
productions are otherwise specified as for Syntax
.Parsers generated from grammars for abstract syntax are usually ambiguous.
Associativity, relative priority, and lexical disambiguation are currently
specified separately, using notation from SDF, embedded in multi-line comments
/*...*/
.
Semantics
introduces a declaration of a translation function
from ASTs (with strings as leaves) to funcon terms.
[[...]]
._:...
.:
. It is usually
a computation type =>t
for some value type t
; it can also be a
computation sequence type of the form (=>t)*
.Rule
introduces an equation defining the translation function
on trees matching a specified pattern.
\"...\"
produces a funcon string value from a lexical symbol
...
. (In contrast, "..."
is always a literal string, not containing
references to meta-variables.)[[...]] : s = [[...]]
, where
the patterns on both sides match the nonterminal symbol s
. Note
that desugaring rules do not refer to particular translation functions.All funcons (etc.) defined in Funcons-beta can be used in all language definitions. Funcons defined in a language definition file must have fresh names, and cannot be reused in other language definitions (except by copy-paste).
Funcon names start with lowercase letters, and may include letters, digits,
and dashes -
.
Variables in funcon terms start with uppercase letters, and may be suffixed by
digits and/or primes. Variables that stand for sequences of indefinite length
are suffixed by *
, +
, or ?
. Variables whose values are not required may
be replaced by underscores _
.
A funcon term formed from a funcon f
and argument sequence s
is written in
prefix form: f s
. When f
has no arguments, it is written without
parentheses: f
; when it has 2 or more arguments t1
, …, tn
, they are
written in ordinary parentheses: f(t1,...,tn)
. Parentheses are optional when
there is a single argument term, so both f t
and f(t)
are allowed.
f g t
is always grouped as f(g(t))
!Funcons are not higher-order, so implicit grouping of f g t
as (f g)(t)
would here be completely useless, as it would never give a well-formed term.
Grouping in funcon terms treats funcon names as prefix operations, such as the
‘-
’ in ‘-sin(x)
’. (Readers accustomed to higher-order programming in Haskell
may find it helpful to imagine f g t
written as f$g t
.)
Some funcons can take argument sequences of varying lengths; funcons may also
compute sequences of values. An example of a funcon that does both is
left-to-right
, which is used to ensure that arguments are evaluated in the
specified order (the default is to allow interleaving). Composition with
left-to-right
provides sequential variants of all multi-argument funcons, e.g.:
integer-add left-to-right(t1,t2)
(which abbreviates
integer-add(left-to-right(t1,t2))
)The following special forms of funcon terms are allowed:
'c'
(with the usual \
-escapes)"c1...cn"
(with the usual \
-escapes)[t1,...,tn]
, empty list [ ]
{t1,...,tn}
, empty set { }
{k1|->t1,...,kn|->tn}
, empty map map( )
t1|...|tn
t1&...&tn
~t
t*
, t+
, t?
, t^n
The funcon definitions in Funcons-beta are language-independent.
CBS specifications do not refer to the hierarchy of folders and files used for Funcons-beta.
Files in Funcons-beta are generally divided into unnumbered subsections.
The number of #
characters in a subsection heading indicates its level,
with the top level sections Computations and Values having a single #
.
In CBS, types are values. They can be given as arguments to funcons, and computed by funcons.
Type
introduces a declaration of a fresh funcon name for a type, and lists
any arguments. The type of values it computes is types
.
Type t... ~> t1
combines a type declaration with a
rewrite of the type to t1
.Type t... <: t1
combines a type declaration with an
assertion that t...
is a subtype of t1
.Datatype
introduces a definition of an algebraic datatype, written
t ::= f1(...) | ... | fn(...)
, which also declares the constructor funcons
fi(...):t
for its values.
Datatype t(...)
written without constructors allows
separate declaration of constructors with different instantiations of the
parameterised type t(...)
, corresponding to a GADT.Meta-variables
introduces type constraints on variables used in rules.
These constraints are usually of the form v <: t
where v
is a variable,
requiring v
to be a subtype of t
.
Funcon
introduces a declaration of a fresh funcon name, together with
its signature.
-
.t
is written :=>t
. For example, the signature of fail
is written
:=>empty-type
.t
is written (v1:ct1,...,vn:ctn):=>t
, where each vi
is a
variable, and each cti
is either a type of values ti
or a computation
type =>ti
. (Computation types =>ti
resemble the types of call-by-name
parameters in Scala.) For example, the signature of if-true-else
is
(_:booleans, _:=>T, _:=>T) : =>T
, where T
is a type variable.vi:ti
are implicitly pre-evaluated (possibly
interleaved) whereas evaluation of arguments specified by vi:=>ti
is
determined by explicit rules.*
, +
, or ?
, allowing use of the funcon
with varying numbers of arguments. (A sequence argument is usually at the
end, but could be anywhere, since the other arguments in an application
determine where to match it.)( )
. The result type in the signature of a partial funcon
is of the form t?
for some value type t
.(v1:ct1,...,vn:ctn):t
,
using a value result type t
instead of a computation result type =>t
.Alias
introduces an equation n1 = n2
that declares a fresh name n1
and defines it to be equivalent to another name n2
. n1
is usually an
abbreviation for a longer n2
; its declaration as an alias prevents it from
being defined elsewhere to have a different interpretation.
Built-in
introduces a declaration of a fresh funcon name and its
signature, but does not provide a definition for it. Built-ins can be regarded
as parameters of a collection of funcon definitions. They are generally
reserved for types of values such as integers, sets, and maps, which are not
amenable to specification using operational rules.
Auxiliary
introduces a name that is not intended for direct use in
language definitions.
Rule
introduces a formula or inference rule defining the
operational behaviour of a funcon.
t1 ~> t2
is a rewrite from t1
to t2
.t1 ---> t2
is simple transition from t1
to t2
.e(v) |- t1 ---> t2
specifies dependence on a contextual entity named e
.<t1,s(v1)> ---> <t2,s(v2)>
specifies inspection of a mutable entity named
s
and its replacement of its value v1
by v2
.t1 --i?(v*)-> t2
specifies a sequence of values v*
for an input entity
named i
.t1 --o!(v*)-> t2
specifies a sequence of values v*
for an output entity
named o
.t1 --c(v?)-> t2
specifies an optional valuev?
for a control entity
named c
.v:t
is restricted to value terms; un-annotated
variables range over computation terms (including value terms), except that
type variables declared by Meta-variables
are restricted to type terms.Datatype
definitions).Assert
introduces a formula that expresses the intention
that it should hold (either as a consequence of specified definitions, or
as a requirement for built-ins).
Entity
introduces a declaration of a fresh auxiliary entity name.
e(v:t) |- _ ---> _
declares a contextual entity e
of type t
, e.g.,
environment(_:environments) |- _ ---> _
. When a contextual entity is
omitted in a rule, it is implicitly the same in the conclusion and any
premises.<_,s(v1:t)> ---> <_,s(v2:t)>
declares a mutable entity s
of type t
,
e.g., < _ , store(_:stores) > ---> < _ , store(_:stores) >
. When a mutable
entity is omitted in an axiom, it is implicitly propagated unchanged.
When it is omitted in a rule with a single premise, its value before the
transition in the premise is the same as before the transition in the
conclusion, and similarly for its value after the transitions. Changes to
mutable entities are threaded through sequences of transitions._ --i?(v*:t*)-> _
declares an input entity i
of type t*
, e.g.,
_ -- standard-in?(_:values*) -> _
. When an input entity is omitted in an
axiom, it is implicitly required to be the empty sequence. When it is
omitted in a rule with a single premise, the sequence of values in the
conclusion is implicitly the same as in the premise. The value sequences
of an input entity are concatenated in sequences of transitions._ --o?(v*:t*)-> _
declares an output entity o
of type t*
, e.g.,
_ -- standard-out!(_:values*) -> _
. When an output entity is omitted in
a rule, the implicit requirements are analogous to those for input entities._ --c(v?:t?)-> _
declares a control entity c
of type t?
, e.g.,
_ --abrupted(_:values?)-> _
. When a control entity is omitted in a rule,
the implicit requirements are analogous to those for input entities,
except that a transition with a non-empty control entity value cannot be
followed by a further transition (before being handled).