UNPKG

3.13 kBJavaScriptView Raw
1/* @flow weak */
2"use strict";
3
4/**
5 ### DSL for input parameters
6
7 There is a small DSL to help with `forall`. For example the two definitions below are equivalent:
8 ```js
9 var bool_fn_applied_thrice = jsc.forall("bool -> bool", "bool", check);
10 var bool_fn_applied_thrice = jsc.forall(jsc.fn(jsc.bool()), jsc.bool(), check);
11 ```
12
13 The DSL is based on a subset of language recognized by [typify-parser](https://github.com/phadej/typify-parser):
14 - *identifiers* are fetched from the predefined environment.
15 - *applications* are applied as one could expect: `"array bool"` is evaluated to `jsc.array(jsc.bool)`.
16 - *functions* are supported: `"bool -> bool"` is evaluated to `jsc.fn(jsc.bool)`.
17 - *square brackets* are treated as a shorthand for the array type: `"[nat]"` is evaluated to `jsc.array(jsc.nat)`.
18 - *union*: `"bool | nat"` is evaulated to `jsc.oneof(jsc.bool, jsc.nat)`.
19 - **Note** `oneof` cannot be shrinked, because the union is untagged, we don't know which shrink to use.
20 - *anonymous records*: `"{ b: bool; n: nat}"` is evaluated to `jsc.record({ n: jsc.bool, n: jsc.nat })`.
21*/
22
23var arbitrary = require("./arbitrary.js");
24var record = require("./record.js");
25var array = require("./array.js");
26var fn = require("./fn.js");
27var typifyParser = require("typify-parser");
28
29// Forward declarations
30var compileType;
31var compileTypeArray;
32
33function compileIdent(env, type) {
34 var g = env[type.value];
35 if (!g) {
36 throw new Error("Unknown arbitrary: " + type.value);
37 }
38 return g;
39}
40
41function compileApplication(env, type) {
42 var callee = compileType(env, type.callee);
43 var args = compileTypeArray(env, type.args);
44
45 return callee.apply(undefined, args);
46}
47
48function compileFunction(env, type) {
49 // we don't care about argument type
50 var result = compileType(env, type.result);
51 return fn.fn(result);
52}
53
54function compileBrackets(env, type) {
55 var arg = compileType(env, type.arg);
56 return array.array(arg);
57}
58
59function compileDisjunction(env, type) {
60 var args = compileTypeArray(env, type.args);
61 return arbitrary.oneof(args);
62}
63
64function compileRecord(env, type) {
65 // TODO: use mapValues
66 var spec = {};
67 Object.keys(type.fields).forEach(function (key) {
68 spec[key] = compileType(env, type.fields[key]);
69 });
70 return record.arbitrary(spec);
71}
72
73compileType = function compileTypeFn(env, type) {
74 switch (type.type) {
75 case "ident": return compileIdent(env, type);
76 case "application": return compileApplication(env, type);
77 case "function": return compileFunction(env, type);
78 case "brackets": return compileBrackets(env, type);
79 case "disjunction": return compileDisjunction(env, type);
80 case "record": return compileRecord(env, type);
81 case "number": return type.value;
82 default: throw new Error("Unsupported typify ast type: " + type.type);
83 }
84};
85
86compileTypeArray = function compileTypeArrayFn(env, types) {
87 return types.map(function (type) {
88 return compileType(env, type);
89 });
90};
91
92function parseTypify(env, str) {
93 var type = typifyParser(str);
94 return compileType(env, type);
95}
96
97module.exports = {
98 parseTypify: parseTypify,
99};