// all API calls through '$' function/object
import $ from 'jquery';
// schedule a function to be called on load
$(function () { console.log('ready!'); });
// select all input elements in first form
const x = $('input', document.forms[0]);
// create new input elements with attributes
const y = $('<input>', { type: 'text' });
// create a resolved promise with a value
Promise.resolve(42)
.then(console.log) // 42
Promise.resolve({ then: 42 })
.then(console.log) // { then: 42 }
// create a promise with a "thenable"
Promise.resolve({ then: fulfill =>fulfill(42)})
.then(console.log) // 42
function max(a, b) {
requires(typeof(a)=="number");
requires(typeof(b)=="number");
ensures(result => result >= a);
if (a > b) {
return a;
} else {
return b;
}
}
$ \wedge~~~~a > b~\Rightarrow~result\negmedspace=\negmedspace a$
function sumTo (n) {
requires(Number.isInteger(n));
requires(n >= 0);
ensures(res => res === (n + 1) * n / 2);
let i = 0;
let s = 0;
while (i < n) {
invariant(Number.isInteger(i));
invariant(Number.isInteger(s));
invariant(i <= n);
invariant(s === (i + 1) * i / 2);
i++;
s = s + i;
}
return s;
}
function max(a, b) {
requires(typeof(a)=="number");
requires(typeof(b)=="number");
ensures(result => result >= a);
if (a > b) {
return a;
} else {
return b;
}
}
const x = max(23, 42);
assert(x >= 23);
$ \forall x. $
$ ~~~~ ( \forall a, b.~( $
$ ~~~~~~ \texttt{typeof}(a) = \texttt{"number"} ~\wedge~ $
$ ~~~~~~ \texttt{typeof}(b) = \texttt{"number"} ~\Rightarrow~ $
$ ~~~~~~ max(a, b) \ge a ) ) $
$ \wedge ~~~~ x = max(23, 42) $
$ \Longrightarrow x \ge 23$
spec
syntax and bounded, trigger-based quantifier instantiation algorithm
function inc (x) {
requires(Number.isInteger(x));
ensures(y => Number.isInteger(y) && y > x);
return x + 1;
}
$ \forall x. \{ call(x) \} \Rightarrow $
$ \left( isInt(x) ~\Rightarrow~pre(\texttt{inc}, x) \right) ~\wedge~ \left( isInt(x) \wedge \,post(\texttt{inc}, x)~\Rightarrow~ \texttt{inc}(x) > x \right)) $
function inc (x) {
requires(Number.isInteger(x));
ensures(y => Number.isInteger(y) && y > x);
return x + 1;
}
const y = inc(23);
assert(y > 23);
$ \forall y. $
$ ~~~~~~ \left( \forall x. \{ call(x) \} \Rightarrow \left( ...~\Rightarrow~pre(\texttt{inc}, x) \right) \wedge~ \left( ... \wedge \, post(\texttt{inc}, x) ~\Rightarrow~ ... \right) \right) $
$ \wedge ~~~~ call(23) $
$ \wedge ~~~~ post(\texttt{inc}, 23) $
$ \wedge ~~~~ y = \texttt{inc}(23) $
$ \Longrightarrow y > 23 $
function inc (x) {
requires(Number.isInteger(x));
ensures(y => Number.isInteger(y) && y > x);
return x + 1;
}
const y = inc(23);
assert(y > 23);
$ \forall y. $
$ ~~~~~~\, \left( isInt(23) ~\Rightarrow~pre(\texttt{inc}, 23) \right) $
$ \wedge~~~~ \left( isInt(23) ~\wedge~post(\texttt{inc},23)~\Rightarrow~ \texttt{inc}(23) > 23 \right) $
$ \wedge ~~~~ post(\texttt{inc}, 23) $
$ \wedge ~~~~ y = \texttt{inc}(23) $
$ \Longrightarrow y > 23$
function inc (x) {
requires(Number.isInteger(x));
ensures(y => Number.isInteger(y) && y > x);
return x + 1;
}
function twice (f, n) {
requires(spec(f, (x) => Number.isInteger(x),
(x,y) => Number.isInteger(y) && y > x));
requires(Number.isInteger(n));
ensures(res => res >= n + 2);
return f(f(n));
}
const m = twice(inc, 3);
assert(m >= 5);
function f (g) {
requires( spec(g, x => x > 3, (x, y) => y > 9));
assert( spec(g, x => x > 4, (x, y) => y > 8));
}
spec
on g
in the precondition satisfies the second, asserted spec
Promise
API, Parameterized List
class Adder {
constructor (base) { this.base = base; }
invariant () { return Number.isInteger(this.base); }
addTo (n) {
requires(Number.isInteger(n));
return this.base + n;
}
}
function f (a) {
requires(a instanceof Adder);
ensures(res => res !== 2); // does not hold for "new A(-1)"
return a.addTo(3);
}
$ \forall x. \{ access(x) \} \Rightarrow \left( ~x ~~\texttt{instanceof} ~~ \texttt{Adder} ~\Rightarrow~ isInt(x.base) \right) $
$T \in \text{Types} ~::=~ \{~x: B~|~ R~\} ~|~ x:T \rightarrow T \hspace{2.5em} B ~::=~ \text{Bool}~|~ \text{Int}$
spec
Promise
spec
When a promise resolve function F is called with argument resolution, the following steps are taken:
"then"
).
"PromiseJobs"
,
undefined
.
function proof_f_mono (f, proof_f_inc, n, m) {
// f is a function from non-negative int to int
requires(spec(f,
(x) => Number.isInteger(x) && x >= 0,
(x, y) => Number.isInteger(y) && pure()));
// proof_f_inc states that f is increasing
requires(spec(proof_f_inc,
x => Number.isInteger(x) && x >= 0,
x => f(x) <= f(x + 1) && pure()));
requires(Number.isInteger(n) && n >= 0);
requires(Number.isInteger(m) && m >= 0);
requires(n < m);
// show that f is increasing for arbitrary n,m
ensures(f(n) <= f(m));
ensures(pure()); // no side effects
proof_f_inc(n); // instantiate proof for n
if (n + 1 < m) {
// invoke induction hypothesis (I.H.)
proof_f_mono(f, proof_f_inc, n + 1, m);
}
}