blob: c881eb2462a44c5867f8f81c22893bd3d38c9b9f [file] [log] [blame] [view] [edit]
# Internal Language
After type-checking, SpecTec converts the input specification into a more explicit internal representation called the *IL* (internal language).
The abstract syntax tree of the IL can be printed in an easily machine-readable S-expression format by invoking SpecTec in [AST mode](Usage.md#ast-mode).
The structure of the IL is described by the following grammar.
See the description of the SpecTec [language](Language.md) for details on the constructs.
#### Literals
```
bool ::= "true" | "false"
text ::= """ char* """
id ::= text
mixop ::= text
sign ::= "+" | "-"
nat ::= digit+
int ::= sign nat
rat ::= sign? nat "/" nat
real ::= sign? nat "." nat
num ::= "nat" nat | "int" int | "rat" rat | "real" real
```
Mixfix operators (mixop) are constructed by the frontend from the notation used in definitions of types or relations.
Essentially, they are a concatenation of the atom names occurring,
with interleaving `%` indicating the position of operands or nested expressions.
For example, the notation defined by the relation
```
relation Expr_ok: context |- exp : typ
```
will be represented by the mixfix operator `"%|-%:%"`,
applied to a triple of arguments.
#### Operators
```
unop ::= "not" | "plus" | "minus" | "plusminus" | "minusplus"
binop ::= "and" | "or" | "impl" | "equiv" | "add" | "sub" | "mul" | "div" | "mod" | "pow"
cmpop ::= "eq" | "ne" | "lt" | "gt" | "le" | "ge"
```
#### Iterations
```
iter ::=
"opt" ;; ?
"list" ;; *
"list1" ;; +
"listn" exp id? ;; ^n, ^(i<n)
```
#### Types
```
booltyp ::= "bool"
numtyp ::= "nat" | "int" | "rat" | "real"
texttyp ::= "text"
optyp ::= booltyp | numtyp
typ ::=
"var" id ;; t
booltyp ;; bool
numtyp ;; nat, int, ...
texttyp ;; text
"tup" typbind* ;; ( typ , ... , typ )
"iter" typ iter ;; typ*, typ+, ...
deftyp ::=
"alias" typ ;; typ
"struct" typfield* ;; { field , ... , field }
"variant" typcase* ;; case | ... | case
typbind ::= "bind" exp typ
typfield ::= "field" mixop bind* typ prem*
typcase ::= "case" mixop bind* typ prem*
```
#### Expressions
```
exp ::=
"var" id ;; x
"bool" bool ;; true, false
"num" num ;; 0, -2
"text" text ;; "text"
"un" unop optyp exp ;; <op> exp
"bin" binop optyp exp exp ;; exp <op> exp
"cmp" cmpop optyp exp exp ;; exp <cmp> exp
"idx" exp exp ;; exp[exp]
"slice" exp exp exp ;; exp[exp : exp]
"upd" exp path exp ;; exp[path = exp]
"ext" exp path exp ;; exp[path =++ exp]
"struct" expfield* ;; { atom exp, ... , atom exp }
"dot" exp mixop ;; exp.atom
"comp" exp exp ;; exp ++ exp (on records)
"mem" exp exp ;; exp <- exp
"len" exp ;; |exp|
"tup" exp* ;; (exp, ..., exp)
"call" id arg* ;; $x(arg, ..., arg)?
"iter" exp iter dom* ;; exp?, exp*, ...
"case" mixop exp ;; atom exp
"list" exp? ;; exp ... exp or [exp ... exp]
"cat" exp exp ;; exp ++ exp (on lists)
expfield ::= "field" mixop exp e
path ::=
"root" ;; .
"idx" path exp ;; path[exp]
"slice" path exp exp ;; path[exp : exp]
"dot" path mixop ;; path.atom
```
In addition to these explicit expressions,
the IL also contains internal expressions that are inserted by the type checker:
```
exp ::= ...
"proj" exp nat ;; tuple projection exp.i
"uncase" exp mixop ;; inverse of "case"
"opt" exp? ;; option value (eps or singletong value)
"unopt" exp ;; inverse of "opt"
"lift" exp ;; conversion from t? to t*
"cvt" numtyp numtyp exp ;; conversion from first to second numeric type
"sub" typ typ exp ;; subsumption from first to second type
```
Moreover, the IL explicitly annotates the variables iterated over by an iteration (its domain),
and expressions denoting the values they are drawn from:
```
dom ::= "dom" id exp ;; x <- exp
```
For the source input, these will typically take the form `x' <- x`,
where `x'` is an auxiliary introduced by the SpecTec frontend.
However, the upshot of this representation is that it is closed under substitution:
that is, `x'` is locally bound,
while the r.h.s. can be substituted by arbitrary expressions,
for example, when rewriting or reducing a term.
#### Grammars
```
sym ::=
"var" id arg* ;; x(arg, ..., arg)
"num" nat ;; 0x12
"text" text ;; "text"
"eps" ;; eps
"seq" sym* ;; sym ... sym
"alt" sym* ;; sym | ... | sym
"range" sym sym ;; sym | "..." | sym
"iter" sym iter dom ;; sym?, sym+, ...
"attr" exp sym ;; exp:sym
```
#### Premises
```
prem ::=
"rule" id mixop exp ;; -- id: mixop-exp
"if" exp ;; -- if exp
"else" ;; -- otherwise
"let" exp exp ;; -- if exp = exp (when one side introduces variables)
"iter" prem iter dom ;; -- prem*
```
#### Definitions
```
def ::=
"typ" id param* inst* ;; syntax x(param*) with instance definitions
"rel" id mixop typ rule* ;; relation x: mixop-typ with rules
"def" id param* typ clause* ;; def $x(param*) : typ with clauses
"gram" id param* typ prod* ;; grammar x(param*) : typ with productions
"rec" def* ;; inferred recursion group
inst ::= "inst" bind* arg* deftyp dt ;; syntax _(arg*) = deftyp
rule ::= "rule" id bind* mixop exp prem* ;; rule _/x mixop-exp -- prem*
clause ::= "clause" bind* arg* exp* prem* ;; def $_(arg*) = exp -- prem*
prod ::= "prod" bind* sym exp prem* ;; | sym => exp -- prem*
param ::=
"exp", id typ ;; x : typ
"typ", id ;; syntax x
"def", id param* typ ;; def $x(param*) : typ
"gram", id typ ;; grammar x : typ
arg ::=
"exp" exp ;; exp
"typ" typ ;; syntax typ
"def" id ;; def $x
"gram" sym ;; grammar sym
bind ::=
"exp" id typ
"typ" id
"def" id param* typ
"gram" id param* typ
```
The `bind`s are binders for the free variables in a definition and are inferred by the SpecTec frontend.
#### Scripts
```
script ::= def*
```