├── .gitignore
├── html
├── Makefile
├── aot.png
├── subtypes.png
├── github.css
├── highlight.pack.js
├── whatwg.css
└── subtypes.graffle
├── historic
├── def.pdf
├── subtypes.png
├── mathpartir.sty
├── subtypes.graffle
└── def.tex
├── lib
├── asm.js
├── env.js
├── report.js
├── fail.js
├── asmAssert.js
├── tables.js
├── types.js
└── validate.js
├── package.json
├── README.md
├── test
└── index.js
└── LICENSE
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
--------------------------------------------------------------------------------
/html/Makefile:
--------------------------------------------------------------------------------
1 | index.html: index.src.html
2 | anolis index.src.html index.html
3 |
--------------------------------------------------------------------------------
/html/aot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/no-problemo/asm.js/master/html/aot.png
--------------------------------------------------------------------------------
/historic/def.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/no-problemo/asm.js/master/historic/def.pdf
--------------------------------------------------------------------------------
/html/subtypes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/no-problemo/asm.js/master/html/subtypes.png
--------------------------------------------------------------------------------
/historic/subtypes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/no-problemo/asm.js/master/historic/subtypes.png
--------------------------------------------------------------------------------
/historic/mathpartir.sty:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/no-problemo/asm.js/master/historic/mathpartir.sty
--------------------------------------------------------------------------------
/lib/asm.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | validate: require('./validate'),
3 | ValidationError: require('./fail').ValidationError,
4 | types: require('./types')
5 | };
--------------------------------------------------------------------------------
/lib/env.js:
--------------------------------------------------------------------------------
1 | var dict = require('dict');
2 |
3 | function Env(v) {
4 | if (!(this instanceof Env))
5 | return new Env(v);
6 | this._v = v;
7 | this._dict = dict();
8 | }
9 |
10 | Env.prototype.lookup = function lookup(x) {
11 | return this._dict.get(x) || null;
12 | };
13 |
14 | Env.prototype.bind = function bind(x, t, loc) {
15 | if (x === 'arguments' || x === 'eval')
16 | this._v.fail("illegal binding: '" + x + "'", loc);
17 | if (this._dict.has(x))
18 | this._v.fail("duplicate binding for " + x, loc);
19 | this._dict.set(x, t);
20 | };
21 |
22 | module.exports = Env;
23 |
--------------------------------------------------------------------------------
/lib/report.js:
--------------------------------------------------------------------------------
1 | var ty = require('./types');
2 |
3 | function Report(globals, exports) {
4 | this._globals = globals;
5 | this._exports = exports;
6 | }
7 |
8 | Report.prototype.getFunction = function(f) {
9 | var global = this._globals.lookup(f);
10 | if (!global || !(global.type instanceof ty.Arrow))
11 | return null;
12 | return global.type;
13 | };
14 |
15 | Report.prototype.isSingleExport = function() {
16 | return this._exports.type === 'single';
17 | };
18 |
19 | // ( this.isSingleExport => () -> string)
20 | // (!this.isSingleExport => (string) -> string)
21 | Report.prototype.getExport = function(f) {
22 | return this._exports.type === 'single'
23 | ? this._exports.export.name
24 | : this._exports.exports.lookup(f).name;
25 | };
26 |
27 | module.exports = Report;
28 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "asm.js",
3 | "description": "Tools for the asm.js subset of JavaScript",
4 | "main": "lib/asm.js",
5 | "version": "0.0.3",
6 | "engines": {
7 | "node": ">=0.8.2"
8 | },
9 | "author": {
10 | "name": "Dave Herman"
11 | },
12 | "license": "Apache-2.0",
13 | "dependencies": {
14 | "esprima": "1.0.4",
15 | "dict": "1.4.0",
16 | "array-extended": "0.0.4",
17 | "pattern-match": "0.3.0"
18 | },
19 | "devDependencies": {
20 | "nodeunit": "0.9.0"
21 | },
22 | "directories": {
23 | "lib": "./lib"
24 | },
25 | "repository": {
26 | "type": "git",
27 | "url": "git://github.com/dherman/asm.js.git"
28 | },
29 | "keywords": [
30 | "javascript",
31 | "asm.js",
32 | "validator"
33 | ],
34 | "scripts": {
35 | "test": "nodeunit"
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/lib/fail.js:
--------------------------------------------------------------------------------
1 | var match = require('pattern-match');
2 |
3 | function ValidationError(message, stack) {
4 | Error.call(this, message);
5 | this.stack = stack;
6 | this.message = message;
7 | }
8 |
9 | ValidationError.prototype = Object.create(Error.prototype);
10 |
11 | function spaces(n) {
12 | var result = "";
13 | for (var i = 0; i < n; i++)
14 | result += " ";
15 | return result;
16 | }
17 |
18 | ValidationError.prototype.context = function() {
19 | if (!this.src || !this.loc)
20 | return null;
21 |
22 | var lines = this.src.split(/\r|\n|\r\n/);
23 | var start = this.loc.start;
24 | var line = lines[start.line - 1];
25 | return line + "\n" + spaces(start.column) + "^";
26 | };
27 |
28 | ValidationError.prototype.toString = function() {
29 | return this.context() + "\n\n" + Error.prototype.toString.call(this);
30 | };
31 |
32 | function fail(message, src, loc) {
33 | message = message + locToString(loc);
34 | // FIXME: V8-specific; make this stack-trace logic more robust
35 | var stack = (new Error).stack
36 | .replace(/[^n]*\n/, "ValidationError: " + message + "\n")
37 | .replace(/\n[^\n]*\n/, "\n");
38 | var e = new ValidationError(message, stack);
39 | e.src = src;
40 | e.loc = loc;
41 | throw e;
42 | }
43 |
44 | // (Loc) -> str
45 | function locToString(loc) {
46 | return match(loc, function(when) {
47 | when({
48 | start: { line: match.var('sl'), column: match.var('sc') },
49 | end: { line: match.var('el'), column: match.var('ec') }
50 | }, function(vars) {
51 | return " at " + vars.sl + ":" + vars.sc + "-" + vars.el + ":" + vars.ec;
52 | });
53 |
54 | when(match.any, function() {
55 | return "";
56 | });
57 | });
58 | }
59 |
60 | fail.locToString = locToString;
61 |
62 | fail.ValidationError = ValidationError;
63 |
64 | module.exports = fail;
65 |
--------------------------------------------------------------------------------
/html/github.css:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | github.com style (c) Vasily Polovnyov
4 |
5 | */
6 |
7 | .hljs {
8 | display: block;
9 | overflow-x: auto;
10 | padding: 0.5em;
11 | color: #333;
12 | background: #f8f8f8;
13 | }
14 |
15 | .hljs-comment,
16 | .hljs-template_comment,
17 | .diff .hljs-header,
18 | .hljs-javadoc {
19 | color: #998;
20 | font-style: italic;
21 | }
22 |
23 | .hljs-keyword,
24 | .css .rule .hljs-keyword,
25 | .hljs-winutils,
26 | .javascript .hljs-title,
27 | .nginx .hljs-title,
28 | .hljs-subst,
29 | .hljs-request,
30 | .hljs-status {
31 | color: #333;
32 | font-weight: bold;
33 | }
34 |
35 | .hljs-number,
36 | .hljs-hexcolor,
37 | .ruby .hljs-constant {
38 | color: #099;
39 | }
40 |
41 | .hljs-string,
42 | .hljs-tag .hljs-value,
43 | .hljs-phpdoc,
44 | .tex .hljs-formula {
45 | color: #d14;
46 | }
47 |
48 | .hljs-title,
49 | .hljs-id,
50 | .coffeescript .hljs-params,
51 | .scss .hljs-preprocessor {
52 | color: #900;
53 | font-weight: bold;
54 | }
55 |
56 | .javascript .hljs-title,
57 | .lisp .hljs-title,
58 | .clojure .hljs-title,
59 | .hljs-subst {
60 | font-weight: normal;
61 | }
62 |
63 | .hljs-class .hljs-title,
64 | .haskell .hljs-type,
65 | .vhdl .hljs-literal,
66 | .tex .hljs-command {
67 | color: #458;
68 | font-weight: bold;
69 | }
70 |
71 | .hljs-tag,
72 | .hljs-tag .hljs-title,
73 | .hljs-rules .hljs-property,
74 | .django .hljs-tag .hljs-keyword {
75 | color: #000080;
76 | font-weight: normal;
77 | }
78 |
79 | .hljs-attribute,
80 | .hljs-variable,
81 | .lisp .hljs-body {
82 | color: #008080;
83 | }
84 |
85 | .hljs-regexp {
86 | color: #009926;
87 | }
88 |
89 | .hljs-symbol,
90 | .ruby .hljs-symbol .hljs-string,
91 | .lisp .hljs-keyword,
92 | .tex .hljs-special,
93 | .hljs-prompt {
94 | color: #990073;
95 | }
96 |
97 | .hljs-built_in,
98 | .lisp .hljs-title,
99 | .clojure .hljs-built_in {
100 | color: #0086b3;
101 | }
102 |
103 | .hljs-preprocessor,
104 | .hljs-pragma,
105 | .hljs-pi,
106 | .hljs-doctype,
107 | .hljs-shebang,
108 | .hljs-cdata {
109 | color: #999;
110 | font-weight: bold;
111 | }
112 |
113 | .hljs-deletion {
114 | background: #fdd;
115 | }
116 |
117 | .hljs-addition {
118 | background: #dfd;
119 | }
120 |
121 | .diff .hljs-change {
122 | background: #0086b3;
123 | }
124 |
125 | .hljs-chunk {
126 | color: #aaa;
127 | }
128 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # asm.js
2 |
3 | A Mozilla Research project to specify and develop the extremely optimizable subset of JS targeted by compilers like Emscripten, Mandreel, and LLJS.
4 |
5 | Discussion of the asm.js spec now takes place on Specifiction
6 | [here](http://discourse.specifiction.org/c/asm-js).
7 |
8 | As of this update, this repo hosts the source for
9 | [the current asm.js Working Draft](http://asmjs.org/spec/latest/).
10 |
11 | This repo also hosts JS source code which performs asm.js validation, however
12 | as of this update, this code is not up to date with the latest working draft and is
13 | not extensively tested. Patches to update it or fix bugs are welcome though.
14 |
15 | ## Example
16 |
17 | ```javascript
18 | function mymodule(stdlib, foreign, heap) {
19 | "use asm";
20 |
21 | // -------------------------------------------------------------------------
22 | // SECTION 1: globals
23 |
24 | var H32 = new stdlib.Int32Array(heap);
25 | var HU32 = new stdlib.Uint32Array(heap);
26 | var log = foreign.consoleDotLog;
27 |
28 | var g_i = 0; // int global
29 | var g_f = 0.0; // double global
30 |
31 | // -------------------------------------------------------------------------
32 | // SECTION 2: functions
33 |
34 | function f(x, y) {
35 | // SECTION A: parameter type declarations
36 | x = x|0; // int parameter
37 | y = +y; // double parameter
38 |
39 | // SECTION B: function body
40 | log(x|0); // call into FFI -- must force the sign
41 | log(y); // call into FFI -- already know it's a double
42 | x = (x+3)|0; // signed addition
43 |
44 | // SECTION C: unconditional return
45 | return ((((x+1)|0)>>>0)/(x>>>0))|0; // compound expression
46 | }
47 |
48 | function g() {
49 | g_f = +(g_i|0); // read/write globals
50 | return;
51 | }
52 |
53 | function g2() {
54 | return;
55 | }
56 |
57 | function h(i, x) {
58 | i = i|0;
59 | x = x|0;
60 | H32[i>>2] = x; // shifted by log2(byte count)
61 | ftable_2[(x-2)&1](); // dynamic call of functions in table 2
62 |
63 | // no return necessary when return type is void
64 | }
65 |
66 | // -------------------------------------------------------------------------
67 | // SECTION 3: function tables
68 |
69 | var ftable_1 = [f];
70 | var ftable_2 = [g, g2]; // all of the same type
71 |
72 | // -------------------------------------------------------------------------
73 | // SECTION 4: exports
74 |
75 | return { f_export: f, goop: g };
76 | }
77 | ```
78 |
79 | ## License
80 |
81 | [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0).
82 |
--------------------------------------------------------------------------------
/lib/asmAssert.js:
--------------------------------------------------------------------------------
1 | var asm = require('../lib/asm');
2 | var validate = asm.validate;
3 | var ValidationError = asm.ValidationError;
4 |
5 | function explode(test) {
6 | var __EMPTY__ = [];
7 | var __PURE__ = ["var imul = stdlib.Math.imul, sin = stdlib.Math.sin;"];
8 | var __ALL__ = __PURE__.concat(["var H32 = new stdlib.Int32Array(heap), HU32 = new stdlib.Uint32Array(heap), HF64 = new stdlib.Float64Array(heap);"]);
9 |
10 | var SEP = "\n ";
11 |
12 | return String(test).replace("__EMPTY__", __EMPTY__.join(SEP))
13 | .replace("__PURE__", __PURE__.join(SEP))
14 | .replace("__ALL__", __ALL__.join(SEP));
15 | }
16 |
17 | function asmAssert(msg, f, expect) {
18 | f = explode(f);
19 | var hasOwn = {}.hasOwnProperty;
20 |
21 | if (expect.pass) {
22 | return function(test) {
23 | var report;
24 | test.doesNotThrow(function() { report = validate(f); }, "validation threw");
25 | try {
26 | if (!report)
27 | return;
28 | var types = expect.types,
29 | singleExport = expect.export,
30 | exports = expect.exports;
31 | if (types) {
32 | for (var key in types) {
33 | if (!hasOwn.call(types, key))
34 | continue;
35 | var expectedType = types[key],
36 | actualType = report.getFunction(key);
37 | test.ok(actualType, msg + ": function " + key + " not found");
38 | test.ok(actualType.equals(expectedType), msg + ": " + key + " : " + actualType + ", expected " + expectedType);
39 | }
40 | }
41 | if (singleExport) {
42 | test.ok(report.isSingleExport(), msg + ": expected single export, got multiple");
43 | var actualExport = report.getExport();
44 | test.equal(actualExport, singleExport, msg + ": expected single export " + singleExport + ", got " + actualExport);
45 | }
46 | if (exports) {
47 | for (var key in exports) {
48 | if (!hasOwn.call(exports, key))
49 | continue;
50 | var actualExport = report.getExport(key);
51 | test.ok(actualExport, msg + ": function " + key + " not found");
52 | test.equal(actualExport, exports[key], msg + ": expected export " + key + " to map to " + exports[key] + ", got " + actualExport);
53 | }
54 | }
55 | } catch (e) {
56 | test.ok(false, msg + ": validation failed: " + e);
57 | } finally {
58 | test.done();
59 | }
60 | }
61 | } else {
62 | return function(test) {
63 | test.throws(function() { validate(f); },
64 | function(e) {
65 | return e instanceof ValidationError;
66 | },
67 | msg + ": should fail to validate");
68 | test.done();
69 | }
70 | }
71 | }
72 |
73 | asmAssert.one = function(msg, f, expect) {
74 | return asmAssert(msg,
75 | "function one(stdlib, foreign, heap) {\n 'use asm';\n __ALL__\n " + f + "\n return {};\n}",
76 | expect);
77 | };
78 |
79 | module.exports = asmAssert;
80 |
--------------------------------------------------------------------------------
/lib/tables.js:
--------------------------------------------------------------------------------
1 | var dict = require('dict');
2 | var ty = require('./types');
3 |
4 | exports.ROOT_NAMES = ['stdlib', 'foreign', 'heap'];
5 |
6 | exports.HEAP_VIEW_TYPES = dict({
7 | 'Int8Array': ty.View(1, ty.Intish),
8 | 'Uint8Array': ty.View(1, ty.Intish),
9 | 'Int16Array': ty.View(2, ty.Intish),
10 | 'Uint16Array': ty.View(2, ty.Intish),
11 | 'Int32Array': ty.View(4, ty.Intish),
12 | 'Uint32Array': ty.View(4, ty.Intish),
13 | 'Float32Array': ty.View(4, ty.Doublish),
14 | 'Float64Array': ty.View(8, ty.Doublish)
15 | });
16 |
17 | var DoublishToDouble = ty.Arrow([ty.Doublish], ty.Double);
18 |
19 | exports.STDLIB_TYPES = dict({
20 | 'Infinity': ty.Double,
21 | 'NaN': ty.Double
22 | });
23 |
24 | exports.STDLIB_MATH_TYPES = dict({
25 | 'acos': DoublishToDouble,
26 | 'asin': DoublishToDouble,
27 | 'atan': DoublishToDouble,
28 | 'cos': DoublishToDouble,
29 | 'sin': DoublishToDouble,
30 | 'tan': DoublishToDouble,
31 | 'ceil': DoublishToDouble,
32 | 'floor': DoublishToDouble,
33 | 'exp': DoublishToDouble,
34 | 'log': DoublishToDouble,
35 | 'sqrt': DoublishToDouble,
36 | 'abs': ty.Overloaded([
37 | ty.Arrow([ty.Signed], ty.Signed),
38 | DoublishToDouble
39 | ]),
40 | 'atan2': ty.Arrow([ty.Doublish, ty.Doublish], ty.Double),
41 | 'pow': ty.Arrow([ty.Doublish, ty.Doublish], ty.Double),
42 | 'imul': ty.Arrow([ty.Int, ty.Int], ty.Signed),
43 | // FIXME: In the asm.js spec, min and max are variadic.
44 | 'min': ty.Overloaded([
45 | ty.Arrow([ty.Int, ty.Int], ty.Signed),
46 | ty.Arrow([ty.Double, ty.Double], ty.Double)
47 | ]),
48 | 'max': ty.Overloaded([
49 | ty.Arrow([ty.Int, ty.Int], ty.Signed),
50 | ty.Arrow([ty.Double, ty.Double], ty.Double)
51 | ]),
52 | 'E': ty.Double,
53 | 'LN10': ty.Double,
54 | 'LN2': ty.Double,
55 | 'LOG2E': ty.Double,
56 | 'LOG10E': ty.Double,
57 | 'PI': ty.Double,
58 | 'SQRT1_2': ty.Double,
59 | 'SQRT2': ty.Double
60 | });
61 |
62 | var SignedBitwise = ty.Arrow([ty.Intish, ty.Intish], ty.Signed);
63 |
64 | var RelOp = ty.Overloaded([
65 | ty.Arrow([ty.Signed, ty.Signed], ty.Int),
66 | ty.Arrow([ty.Unsigned, ty.Unsigned], ty.Int),
67 | ty.Arrow([ty.Double, ty.Double], ty.Int)
68 | ]);
69 |
70 | exports.BINOPS = dict({
71 | '+': ty.Arrow([ty.Double, ty.Double], ty.Double),
72 | '-': ty.Arrow([ty.Doublish, ty.Doublish], ty.Double),
73 | '*': ty.Arrow([ty.Doublish, ty.Doublish], ty.Double),
74 | '/': ty.Overloaded([
75 | ty.Arrow([ty.Signed, ty.Signed], ty.Intish),
76 | ty.Arrow([ty.Unsigned, ty.Unsigned], ty.Intish),
77 | ty.Arrow([ty.Doublish, ty.Doublish], ty.Double)
78 | ]),
79 | '%': ty.Overloaded([
80 | ty.Arrow([ty.Signed, ty.Signed], ty.Intish),
81 | ty.Arrow([ty.Unsigned, ty.Unsigned], ty.Intish),
82 | ty.Arrow([ty.Doublish, ty.Doublish], ty.Double)
83 | ]),
84 | '|': SignedBitwise,
85 | '&': SignedBitwise,
86 | '^': SignedBitwise,
87 | '<<': SignedBitwise,
88 | '>>': SignedBitwise,
89 | '>>>': ty.Arrow([ty.Intish, ty.Intish], ty.Unsigned),
90 | '<': RelOp,
91 | '<=': RelOp,
92 | '>': RelOp,
93 | '>=': RelOp,
94 | '==': RelOp,
95 | '!=': RelOp
96 | });
97 |
98 | exports.UNOPS = dict({
99 | '+': ty.Overloaded([
100 | ty.Arrow([ty.Signed], ty.Double),
101 | ty.Arrow([ty.Unsigned], ty.Double),
102 | ty.Arrow([ty.Doublish], ty.Double)
103 | ]),
104 | '-': ty.Overloaded([
105 | ty.Arrow([ty.Int], ty.Intish),
106 | ty.Arrow([ty.Doublish], ty.Double)
107 | ]),
108 | '~': ty.Arrow([ty.Intish], ty.Signed),
109 | '!': ty.Arrow([ty.Int], ty.Int)
110 | });
111 |
--------------------------------------------------------------------------------
/lib/types.js:
--------------------------------------------------------------------------------
1 | function Type() {}
2 |
3 | // =============================================================================
4 | // Value Types
5 | // =============================================================================
6 |
7 | function ValueType(name, supertypes) {
8 | this._name = name;
9 | this._supertypes = supertypes;
10 | };
11 |
12 | ValueType.prototype = Object.create(Type.prototype);
13 |
14 | ValueType.prototype.equals = function equals(other) {
15 | return this === other;
16 | };
17 |
18 | ValueType.prototype.subtype = function subtype(other) {
19 | return this.equals(other) ||
20 | (this._supertypes && this._supertypes.some(function(sup) {
21 | return sup.subtype(other);
22 | }));
23 | };
24 |
25 | ValueType.prototype.toString = function toString() {
26 | return this._name;
27 | }
28 |
29 | var Extern = new ValueType("extern", null);
30 |
31 | var Intish = new ValueType("intish", null);
32 |
33 | var Doublish = new ValueType("doublish", null);
34 |
35 | var Unknown = new ValueType("unknown", [Intish, Doublish]);
36 |
37 | var Int = new ValueType("int", [Intish]);
38 |
39 | var Double = new ValueType("double", [Extern, Doublish]);
40 |
41 | var Signed = new ValueType("signed", [Extern, Int]);
42 |
43 | var Unsigned = new ValueType("unsigned", [Extern, Int]);
44 |
45 | var Fixnum = new ValueType("fixnum", [Signed, Unsigned]);
46 |
47 | var Void = new ValueType("void", null);
48 |
49 | // =============================================================================
50 | // Global Types
51 | // =============================================================================
52 |
53 | // ([ValueType], ValueType) -> Arrow
54 | function Arrow(params, result) {
55 | if (!(this instanceof Arrow))
56 | return new Arrow(params, result);
57 | this.params = params;
58 | this.result = result;
59 | }
60 |
61 | Arrow.prototype = Object.create(Type.prototype);
62 |
63 | Arrow.prototype.equals = function equals(other) {
64 | return other instanceof Arrow &&
65 | this.params.length === other.params.length &&
66 | this.params.every(function(p, i) { return p.equals(other.params[i]) }) &&
67 | this.result.equals(other.result);
68 | };
69 |
70 | Arrow.prototype.toString = function toString() {
71 | return "(" + this.params.join(", ") + ") -> " + this.result;
72 | };
73 |
74 | // ([Arrow]) -> Overloaded
75 | function Overloaded(alts) {
76 | if (!(this instanceof Overloaded))
77 | return new Overloaded(alts);
78 | this.alts = alts;
79 | }
80 |
81 | Overloaded.prototype = Object.create(Type.prototype);
82 |
83 | Overloaded.prototype.toString = function toString() {
84 | return this.alts.join(" ^ ");
85 | };
86 |
87 | // (1|2|4|8, ValueType) -> View
88 | function View(bytes, elementType) {
89 | if (!(this instanceof View))
90 | return new View(bytes, elementType);
91 | this.bytes = bytes;
92 | this.elementType = elementType;
93 | }
94 |
95 | View.prototype.toString = function toString() {
96 | return "View<" + this.bytes + ", " + this.elementType + ">";
97 | };
98 |
99 | // (Arrow, integer) -> Table
100 | function Table(type, length) {
101 | if (!(this instanceof Table))
102 | return new Table(type, length);
103 | this.type = type;
104 | this.length = length;
105 | }
106 |
107 | Table.prototype = Object.create(Type.prototype);
108 |
109 | Table.prototype.toString = function toString() {
110 | return "(" + this.type + ")[" + this.length + "]";
111 | };
112 |
113 | var Function = Object.create(Type.prototype);
114 |
115 | var Module = Object.create(Type.prototype);
116 |
117 | var ModuleParameter = Object.create(Type.prototype);
118 |
119 | Function.toString = function() {
120 | return "Function";
121 | };
122 |
123 | exports.ValueType = ValueType;
124 |
125 | exports.Extern = Extern;
126 | exports.Intish = Intish;
127 | exports.Doublish = Doublish;
128 | exports.Unknown = Unknown;
129 | exports.Int = Int;
130 | exports.Double = Double;
131 | exports.Signed = Signed;
132 | exports.Unsigned = Unsigned;
133 | exports.Fixnum = Fixnum;
134 | exports.Void = Void;
135 |
136 | exports.Arrow = Arrow;
137 | exports.Overloaded = Overloaded;
138 | exports.View = View;
139 | exports.Table = Table;
140 | exports.Function = Function;
141 | exports.Module = Module;
142 | exports.ModuleParameter = ModuleParameter;
143 |
--------------------------------------------------------------------------------
/test/index.js:
--------------------------------------------------------------------------------
1 | var ty = require('../lib/types');
2 | var asmAssert = require('../lib/asmAssert');
3 |
4 | exports.testModuloIntish1 = asmAssert.one(
5 | "% doesn't return int",
6 | function f() {
7 | var x = 0, y = 0;
8 | x = (x|0)%(y|0);
9 | },
10 | { pass: false });
11 |
12 | exports.testModuleIntish2 = asmAssert.one(
13 | "% returns intish",
14 | function f() {
15 | var x = 0, y = 0;
16 | x = ((x|0)%(y|0))|0;
17 | },
18 | { pass: true });
19 |
20 | exports.testIntCoercionRequiresDouble1 = asmAssert.one(
21 | "~~ requires double",
22 | function f() {
23 | var x = 0.0, y = 0;
24 | y = ~~HF64[0];
25 | },
26 | { pass: false });
27 |
28 | exports.testIntCoercionRequiresDouble2 = asmAssert.one(
29 | "~~ requires double",
30 | function f() {
31 | var x = 0.0, y = 0;
32 | y = ~~+HF64[0];
33 | },
34 | { pass: true });
35 |
36 | exports.testNot = asmAssert.one(
37 | "! operator",
38 | function f() {
39 | var x = 0;
40 | x = !((x|0) > 0);
41 | },
42 | { pass: true });
43 |
44 | exports.testParamTypes = asmAssert.one(
45 | "different parameter types",
46 | function f(x, y) {
47 | x = x|0;
48 | y = +y;
49 | }, {
50 | pass: true,
51 | types: {
52 | f: ty.Arrow([ty.Int, ty.Double], ty.Void)
53 | }
54 | });
55 |
56 | exports.testAdd = asmAssert.one(
57 | "addition",
58 | function add1(x) {
59 | x = x|0;
60 | return ((x|0)+1)|0;
61 | }, {
62 | pass: true,
63 | types: {
64 | add1: ty.Arrow([ty.Int], ty.Signed)
65 | }
66 | });
67 |
68 | exports.testImul = asmAssert.one(
69 | "Math.imul",
70 | function double(x) {
71 | x = x|0;
72 | return imul(x, 2)|0;
73 | }, {
74 | pass: true,
75 | double: ty.Arrow([ty.Int], ty.Signed)
76 | });
77 |
78 | exports.testLoad = asmAssert.one(
79 | "heap load",
80 | function get(i) {
81 | i = i|0;
82 | return H32[i>>2]|0;
83 | }, {
84 | pass: true,
85 | types: {
86 | get: ty.Arrow([ty.Int], ty.Signed)
87 | }
88 | });
89 |
90 | exports.testStore = asmAssert.one(
91 | "heap store",
92 | function set(i, x) {
93 | i = i|0;
94 | x = x|0;
95 | H32[i>>2] = x|0;
96 | }, {
97 | pass: true,
98 | types: {
99 | set: ty.Arrow([ty.Int, ty.Int], ty.Void)
100 | }
101 | });
102 |
103 | exports.testCall1 = asmAssert(
104 | "function call",
105 | function call(stdlib, foreign, heap) {
106 | "use asm";
107 | __ALL__
108 | function f(x) {
109 | x = +x;
110 | return +(x + 1.0);
111 | }
112 | function g() {
113 | var x = 0.0;
114 | x = +f(x);
115 | return +x;
116 | }
117 | return {};
118 | }, { pass: true });
119 |
120 | exports.testCall2 = asmAssert(
121 | "function call",
122 | function call(stdlib, foreign, heap) {
123 | "use asm";
124 | __ALL__
125 | function f(x) {
126 | x = x|0;
127 | return (x + 1)|0;
128 | }
129 | function g() {
130 | var x = 0.0;
131 | x = +f(x);
132 | return +x;
133 | }
134 | return {};
135 | }, { pass: false });
136 |
137 | exports.testVoid1 = asmAssert(
138 | "void function call in expression statement",
139 | function void_(stdlib) {
140 | "use asm";
141 | __PURE__
142 | function f() { }
143 | function g() {
144 | f();
145 | }
146 | return {}
147 | }, { pass: true });
148 |
149 | exports.testVoid2 = asmAssert(
150 | "void function call in comma expression",
151 | function void_(stdlib) {
152 | "use asm";
153 | __PURE__
154 | function f() { }
155 | function g() {
156 | var x = 0.0;
157 | x = (f(), f(), 1.0);
158 | }
159 | return {};
160 | }, { pass: true });
161 |
162 | exports.testEval1 = asmAssert(
163 | "module named eval",
164 | function eval() {
165 | "use asm";
166 | __PURE__
167 | function empty () { }
168 | return empty;
169 | }, { pass: false });
170 |
171 | exports.testEval2 = asmAssert(
172 | "function named eval",
173 | function m() {
174 | "use asm";
175 | __PURE__
176 | function eval() { }
177 | return eval;
178 | }, { pass: false });
179 |
180 | exports.testEval3 = asmAssert(
181 | "local named eval",
182 | function m() {
183 | "use asm";
184 | __PURE__
185 | function f() {
186 | var eval = 0;
187 | }
188 | return f;
189 | }, { pass: false });
190 |
191 | exports.testAbs = asmAssert(
192 | "abs returns signed",
193 | function call(stdlib, foreign, heap) {
194 | "use asm";
195 | __PURE__
196 | var abs = stdlib.Math.abs;
197 | function f() {
198 | return abs(1)|0;
199 | }
200 | return f;
201 | }, { pass: true });
202 |
203 | exports.testIf = asmAssert(
204 | "if condition is Int",
205 | function m(){
206 | "use asm";
207 | function f(x,y) {
208 | x = x|0;
209 | y = y|0;
210 | if (x) {
211 | y = 3;
212 | }
213 | }
214 | return f;
215 | }, { pass: true });
216 |
217 | exports.testEmpty = asmAssert(
218 | "empty statements",
219 | function m(){
220 | "use asm";
221 | function f() {
222 | ;
223 | ;
224 | ;
225 | {};
226 | if (0);
227 | if (0) {};
228 | }
229 | return f;
230 | }, { pass: true });
231 |
232 | exports.testMinMax = asmAssert(
233 | "min and max validate",
234 | function m(stdlib, foreign, heap) {
235 | "use asm";
236 | var max = stdlib.Math.max;
237 | var min = stdlib.Math.min;
238 | function f(i0, i1, d0, d1) {
239 | i0 = i0|0;
240 | i1 = i1|0;
241 | d0 = +d0;
242 | d1 = +d1;
243 | var ia = 0;
244 | var ib = 0;
245 | var da = 0.0;
246 | var db = 0.0;
247 | ia = max(i0, i1)|0;
248 | ib = min(i0, i1)|0;
249 | da = +max(d0, d1);
250 | db = +min(d0, d1);
251 | return +(+(+(ia + ib|0) + d0) + d1);
252 | }
253 | return f;
254 | }, { pass: true });
255 |
256 | exports.testMinWrongArgumentType = asmAssert(
257 | "min argument types don't match",
258 | function m(stdlib, foreign, heap) {
259 | "use asm";
260 | var min = stdlib.Math.min;
261 | function f(i0, d1) {
262 | i0 = i0|0;
263 | d1 = +d1;
264 | min(i0, d1)|0;
265 | }
266 | return f;
267 | }, { pass: false });
268 |
269 | exports.testMaxWrongArgumentType = asmAssert(
270 | "min argument types don't match",
271 | function m(stdlib, foreign, heap) {
272 | "use asm";
273 | var max = stdlib.Math.max;
274 | function f(d0, i1) {
275 | d0 = +d0;
276 | i1 = i1|0;
277 | +max(d0, i1);
278 | }
279 | return f;
280 | }, { pass: false });
281 |
282 | exports.testMaxWrongReturnType = asmAssert(
283 | "min argument types don't match",
284 | function m(stdlib, foreign, heap) {
285 | "use asm";
286 | var max = stdlib.Math.max;
287 | function f(i0, i1) {
288 | i0 = i0|0;
289 | i1 = i1|0;
290 | +max(i0, i1);
291 | }
292 | return f;
293 | }, { pass: false });
294 |
295 | exports.testFunctionTables = asmAssert(
296 | "function tables",
297 | function m(stdlib, foreign, heap) {
298 | "use asm"
299 | function f() {}
300 | function g() {}
301 | var x = [f], y = [g], z = [f, g]
302 | return f;
303 | }, { pass: true });
304 |
--------------------------------------------------------------------------------
/html/highlight.pack.js:
--------------------------------------------------------------------------------
1 | var hljs=new function(){function j(v){return v.replace(/&/gm,"&").replace(//gm,">")}function t(v){return v.nodeName.toLowerCase()}function h(w,x){var v=w&&w.exec(x);return v&&v.index==0}function r(w){var v=(w.className+" "+(w.parentNode?w.parentNode.className:"")).split(/\s+/);v=v.map(function(x){return x.replace(/^lang(uage)?-/,"")});return v.filter(function(x){return i(x)||x=="no-highlight"})[0]}function o(x,y){var v={};for(var w in x){v[w]=x[w]}if(y){for(var w in y){v[w]=y[w]}}return v}function u(x){var v=[];(function w(y,z){for(var A=y.firstChild;A;A=A.nextSibling){if(A.nodeType==3){z+=A.nodeValue.length}else{if(t(A)=="br"){z+=1}else{if(A.nodeType==1){v.push({event:"start",offset:z,node:A});z=w(A,z);v.push({event:"stop",offset:z,node:A})}}}}return z})(x,0);return v}function q(w,y,C){var x=0;var F="";var z=[];function B(){if(!w.length||!y.length){return w.length?w:y}if(w[0].offset!=y[0].offset){return(w[0].offset"}function E(G){F+=""+t(G)+">"}function v(G){(G.event=="start"?A:E)(G.node)}while(w.length||y.length){var D=B();F+=j(C.substr(x,D[0].offset-x));x=D[0].offset;if(D==w){z.reverse().forEach(E);do{v(D.splice(0,1)[0]);D=B()}while(D==w&&D.length&&D[0].offset==x);z.reverse().forEach(A)}else{if(D[0].event=="start"){z.push(D[0].node)}else{z.pop()}v(D.splice(0,1)[0])}}return F+j(C.substr(x))}function m(y){function v(z){return(z&&z.source)||z}function w(A,z){return RegExp(v(A),"m"+(y.cI?"i":"")+(z?"g":""))}function x(D,C){if(D.compiled){return}D.compiled=true;D.k=D.k||D.bK;if(D.k){var z={};var E=function(G,F){if(y.cI){F=F.toLowerCase()}F.split(" ").forEach(function(H){var I=H.split("|");z[I[0]]=[G,I[1]?Number(I[1]):1]})};if(typeof D.k=="string"){E("keyword",D.k)}else{Object.keys(D.k).forEach(function(F){E(F,D.k[F])})}D.k=z}D.lR=w(D.l||/\b[A-Za-z0-9_]+\b/,true);if(C){if(D.bK){D.b="\\b("+D.bK.split(" ").join("|")+")\\b"}if(!D.b){D.b=/\B|\b/}D.bR=w(D.b);if(!D.e&&!D.eW){D.e=/\B|\b/}if(D.e){D.eR=w(D.e)}D.tE=v(D.e)||"";if(D.eW&&C.tE){D.tE+=(D.e?"|":"")+C.tE}}if(D.i){D.iR=w(D.i)}if(D.r===undefined){D.r=1}if(!D.c){D.c=[]}var B=[];D.c.forEach(function(F){if(F.v){F.v.forEach(function(G){B.push(o(F,G))})}else{B.push(F=="self"?D:F)}});D.c=B;D.c.forEach(function(F){x(F,D)});if(D.starts){x(D.starts,C)}var A=D.c.map(function(F){return F.bK?"\\.?("+F.b+")\\.?":F.b}).concat([D.tE,D.i]).map(v).filter(Boolean);D.t=A.length?w(A.join("|"),true):{exec:function(F){return null}};D.continuation={}}x(y)}function c(S,L,J,R){function v(U,V){for(var T=0;T";U+=Z+'">';return U+X+Y}function N(){if(!I.k){return j(C)}var T="";var W=0;I.lR.lastIndex=0;var U=I.lR.exec(C);while(U){T+=j(C.substr(W,U.index-W));var V=E(I,U);if(V){H+=V[1];T+=w(V[0],j(U[0]))}else{T+=j(U[0])}W=I.lR.lastIndex;U=I.lR.exec(C)}return T+j(C.substr(W))}function F(){if(I.sL&&!f[I.sL]){return j(C)}var T=I.sL?c(I.sL,C,true,I.continuation.top):e(C);if(I.r>0){H+=T.r}if(I.subLanguageMode=="continuous"){I.continuation.top=T.top}return w(T.language,T.value,false,true)}function Q(){return I.sL!==undefined?F():N()}function P(V,U){var T=V.cN?w(V.cN,"",true):"";if(V.rB){D+=T;C=""}else{if(V.eB){D+=j(U)+T;C=""}else{D+=T;C=U}}I=Object.create(V,{parent:{value:I}})}function G(T,X){C+=T;if(X===undefined){D+=Q();return 0}var V=v(X,I);if(V){D+=Q();P(V,X);return V.rB?0:X.length}var W=z(I,X);if(W){var U=I;if(!(U.rE||U.eE)){C+=X}D+=Q();do{if(I.cN){D+=""}H+=I.r;I=I.parent}while(I!=W.parent);if(U.eE){D+=j(X)}C="";if(W.starts){P(W.starts,"")}return U.rE?0:X.length}if(A(X,I)){throw new Error('Illegal lexeme "'+X+'" for mode "'+(I.cN||"")+'"')}C+=X;return X.length||1}var M=i(S);if(!M){throw new Error('Unknown language: "'+S+'"')}m(M);var I=R||M;var D="";for(var K=I;K!=M;K=K.parent){if(K.cN){D+=w(K.cN,D,true)}}var C="";var H=0;try{var B,y,x=0;while(true){I.t.lastIndex=x;B=I.t.exec(L);if(!B){break}y=G(L.substr(x,B.index-x),B[0]);x=B.index+y}G(L.substr(x));for(var K=I;K.parent;K=K.parent){if(K.cN){D+=""}}return{r:H,value:D,language:S,top:I}}catch(O){if(O.message.indexOf("Illegal")!=-1){return{r:0,value:j(L)}}else{throw O}}}function e(y,x){x=x||b.languages||Object.keys(f);var v={r:0,value:j(y)};var w=v;x.forEach(function(z){if(!i(z)){return}var A=c(z,y,false);A.language=z;if(A.r>w.r){w=A}if(A.r>v.r){w=v;v=A}});if(w.language){v.second_best=w}return v}function g(v){if(b.tabReplace){v=v.replace(/^((<[^>]+>|\t)+)/gm,function(w,z,y,x){return z.replace(/\t/g,b.tabReplace)})}if(b.useBR){v=v.replace(/\n/g,"
")}return v}function p(z){var y=b.useBR?z.innerHTML.replace(/\n/g,"").replace(/
|
]*>/g,"\n").replace(/<[^>]*>/g,""):z.textContent;var A=r(z);if(A=="no-highlight"){return}var v=A?c(A,y,true):e(y);var w=u(z);if(w.length){var x=document.createElementNS("http://www.w3.org/1999/xhtml","pre");x.innerHTML=v.value;v.value=q(w,u(x),y)}v.value=g(v.value);z.innerHTML=v.value;z.className+=" hljs "+(!A&&v.language||"");z.result={language:v.language,re:v.r};if(v.second_best){z.second_best={language:v.second_best.language,re:v.second_best.r}}}var b={classPrefix:"hljs-",tabReplace:null,useBR:false,languages:undefined};function s(v){b=o(b,v)}function l(){if(l.called){return}l.called=true;var v=document.querySelectorAll("pre code");Array.prototype.forEach.call(v,p)}function a(){addEventListener("DOMContentLoaded",l,false);addEventListener("load",l,false)}var f={};var n={};function d(v,x){var w=f[v]=x(this);if(w.aliases){w.aliases.forEach(function(y){n[y]=v})}}function k(){return Object.keys(f)}function i(v){return f[v]||f[n[v]]}this.highlight=c;this.highlightAuto=e;this.fixMarkup=g;this.highlightBlock=p;this.configure=s;this.initHighlighting=l;this.initHighlightingOnLoad=a;this.registerLanguage=d;this.listLanguages=k;this.getLanguage=i;this.inherit=o;this.IR="[a-zA-Z][a-zA-Z0-9_]*";this.UIR="[a-zA-Z_][a-zA-Z0-9_]*";this.NR="\\b\\d+(\\.\\d+)?";this.CNR="(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)";this.BNR="\\b(0b[01]+)";this.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~";this.BE={b:"\\\\[\\s\\S]",r:0};this.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[this.BE]};this.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[this.BE]};this.PWM={b:/\b(a|an|the|are|I|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such)\b/};this.CLCM={cN:"comment",b:"//",e:"$",c:[this.PWM]};this.CBCM={cN:"comment",b:"/\\*",e:"\\*/",c:[this.PWM]};this.HCM={cN:"comment",b:"#",e:"$",c:[this.PWM]};this.NM={cN:"number",b:this.NR,r:0};this.CNM={cN:"number",b:this.CNR,r:0};this.BNM={cN:"number",b:this.BNR,r:0};this.CSSNM={cN:"number",b:this.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",r:0};this.RM={cN:"regexp",b:/\//,e:/\/[gim]*/,i:/\n/,c:[this.BE,{b:/\[/,e:/\]/,r:0,c:[this.BE]}]};this.TM={cN:"title",b:this.IR,r:0};this.UTM={cN:"title",b:this.UIR,r:0}}();hljs.registerLanguage("javascript",function(a){return{aliases:["js"],k:{keyword:"in if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const class",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document"},c:[{cN:"pi",b:/^\s*('|")use strict('|")/,r:10},a.ASM,a.QSM,a.CLCM,a.CBCM,a.CNM,{b:"("+a.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[a.CLCM,a.CBCM,a.RM,{b:/,e:/>;/,r:0,sL:"xml"}],r:0},{cN:"function",bK:"function",e:/\{/,eE:true,c:[a.inherit(a.TM,{b:/[A-Za-z$_][0-9A-Za-z$_]*/}),{cN:"params",b:/\(/,e:/\)/,c:[a.CLCM,a.CBCM],i:/["'\(]/}],i:/\[|%/},{b:/\$[(.]/},{b:"\\."+a.IR,r:0}]}});
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/html/whatwg.css:
--------------------------------------------------------------------------------
1 | /* WHATWG Green: sRGB #3c790a, rgb(60, 121, 10) */
2 |
3 | html { margin: 0; padding: 0; color: black; background: white; }
4 | body { margin: 0; padding: 0 1em 2em 8.5em; line-height: 1.35; color: black; background: white top left repeat-y; }
5 |
6 | @media screen {
7 | html { background: #eeeeee; }
8 | body { margin-bottom: 30%; border-bottom: thin solid #3c790a; }
9 | }
10 |
11 | :link { color: #00C; background: transparent }
12 | :visited { color: #609; background: transparent }
13 | :link:active, :visited:active { color: #C00; background: transparent }
14 | :link:hover, :visited:hover { background: #ffa; }
15 | code :link, code :visited { color: inherit; }
16 |
17 | body, th, td { font-family: sans-serif, Droid Sans Fallback; }
18 |
19 | h1, h2, h3, h4, h5, h6 { text-align: left; text-rendering: optimiseLegibility; }
20 | h1, h2, h3 { color: #3c790a; background: transparent; }
21 | h1 { font: 900 200% sans-serif, Droid Sans Fallback; }
22 | h1.allcaps { font: 900 350% sans-serif, Droid Sans Fallback; letter-spacing: 2px; }
23 | h2 { font: 800 140% sans-serif, Droid Sans Fallback; }
24 | h3 { font: 800 125% sans-serif, Droid Sans Fallback; }
25 | h4 { font: 800 110% sans-serif, Droid Sans Fallback; }
26 | h5 { font: 800 100% sans-serif, Droid Sans Fallback; }
27 | h6 { font: 600 italic 100% sans-serif, Droid Sans Fallback; }
28 |
29 | pre { margin-left: 2em; white-space: pre-wrap; }
30 | h2 { margin: 3em 0 1em 0; }
31 | h3 { margin: 2.5em 0 1em 0; }
32 | h4 { margin: 2.5em 0 0.75em 0; }
33 | h5, h6 { margin: 2.5em 0 1em; }
34 | h1 + h2, h2 + h3, h3 + h4, h4 + h5, h5 + h6, h1 + div + h2, h2 + div + h3, h3 + div + h4, h4 + div + h5, h5 + div + h6 { margin-top: 0.5em; }
35 | p { margin: 1em 0; }
36 | hr { display: block; background: none; border: none; padding: 0; margin: 2em 0; height: auto; }
37 | dl, dd { margin-top: 0; margin-bottom: 0; }
38 | dt { margin-top: 0.75em; margin-bottom: 0.25em; clear: left; }
39 | dt + dt { margin-top: 0; }
40 | dd dt { margin-top: 0.25em; margin-bottom: 0; }
41 | dd p, dd ol, dd ol.brief { margin-top: 0; }
42 | dd dl + p { margin-top: 1em; }
43 | dd table + p { margin-top: 1em; }
44 | p + * > li, dd li { margin: 1em 0; }
45 | dt, dfn { font-weight: bold; font-style: normal; }
46 | i, em, dt dfn { font-style: italic; }
47 | pre, code { font-size: inherit; font-family: monospace, Droid Sans Fallback, sans-serif; font-variant: normal; }
48 | pre strong { color: black; font: inherit; font-weight: bold; background: #B7EDEA; }
49 | pre em { font-weight: bolder; font-style: normal; }
50 | @media screen { code { color: orangered; } }
51 | var sub { vertical-align: bottom; font-size: smaller; position: relative; top: 0.1em; }
52 | table { border-collapse: collapse; border-style: hidden hidden none hidden; }
53 | table thead, table tbody { border-bottom: solid; }
54 | table tbody th { text-align: left; }
55 | table tbody th:first-child { border-left: solid; }
56 | table td, table th { border-left: solid; border-right: solid; border-bottom: solid thin; vertical-align: top; padding: 0.2em; }
57 | blockquote { margin: 0 0 0 2em; border: 0; padding: 0; font-style: italic; }
58 | ins { background: green; color: white; /* color: green; border: solid thin lime; padding: 0.3em; line-height: 1.6em; */ text-decoration: none; }
59 | del { background: maroon; color: white; /* color: maroon; border: solid thin red; padding: 0.3em; line-height: 1.6em; */ text-decoration: line-through; }
60 | body ins, body del { display: block; }
61 | body * ins, body * del { display: inline; }
62 |
63 | .toc dfn, h1 dfn, h2 dfn, h3 dfn, h4 dfn, h5 dfn, h6 dfn { font: inherit; }
64 | img.extra, p.overview { float: right; }
65 | hr.bookmark { border: dashed 2em black; background: yellow; }
66 | pre::before { font: bold 0.8em sans-serif; padding: 0.5em; position: absolute; top: auto; margin: -0.703125em 0 0 -3.75em /* 1em/0.8 + 1.5em + 0.5em*2 */ ; width: 1.5em; background: inherit; border: 0.078125em; border-style: solid none solid solid; border-radius: 1em 0 0 1em; }
67 | pre.idl { border: solid 0.0625em; background: #EEEEEE; color: black; padding: 0.5em 1em; }
68 | pre.idl :link, pre.idl :visited { color: inherit; background: transparent; }
69 | pre.idl::before { content: 'IDL'; }
70 | pre.asn { border: solid 0.0625em; background: #EEEEEE; color: black; padding: 0.5em 1em; }
71 | pre.asn :link, pre.asn :visited { color: inherit; background: transparent; }
72 | pre.asn::before { content: 'ASN'; }
73 | pre.css { border: solid 0.0625em; background: #FFFFEE; color: black; padding: 0.5em 1em; }
74 | pre.css:first-line { color: #AAAA50; }
75 | pre.css::before { content: 'CSS'; }
76 | dl.domintro { color: green; margin: 2em 0 2em 0; padding: 0.5em 1em 0.5em 2em; border: none; background: #DDFFDD; }
77 | hr + dl.domintro, div.impl + dl.domintro { margin-top: 2.5em; margin-bottom: 1.5em; }
78 | dl.domintro dt, dl.domintro dt * { color: black; text-decoration: none; }
79 | dl.domintro dd { margin: 0.5em 0 1em 2em; padding: 0; }
80 | dl.domintro dd p { margin: 0.5em 0; }
81 | dl.domintro:before { display: table; margin: -1em -0.5em -0.5em auto; width: auto; content: 'This box is non-normative. Implementation requirements are given below this box.'; color: black; font-style: italic; border: solid 2px; background: white; padding: 0 0.25em; }
82 | dl.switch { padding-left: 2em; }
83 | dl.switch > dt { text-indent: -1.5em; }
84 | dl.switch > dt:before { content: '\21AA'; padding: 0 0.5em 0 0; display: inline-block; width: 1em; text-align: right; line-height: 0.5em; }
85 | dl.triple { padding: 0 0 0 1em; }
86 | dl.triple dt, dl.triple dd { margin: 0; display: inline }
87 | dl.triple dt:after { content: ':'; }
88 | dl.triple dd:after { content: '\A'; white-space: pre; }
89 | .diff-old { text-decoration: line-through; color: silver; background: transparent; }
90 | .diff-chg, .diff-new { text-decoration: underline; color: green; background: transparent; }
91 | a .diff-new { border-bottom: 1px blue solid; }
92 | tr.rare { background: #EEEEEE; color: #333333; }
93 |
94 | figure.diagrams { border: double black; background: white; padding: 1em; }
95 | figure.diagrams img { display: block; margin: 1em auto; }
96 |
97 | h2 { page-break-before: always; }
98 | h1, h2, h3, h4, h5, h6, dt { page-break-after: avoid; }
99 | h1 + h2, hr + h2.no-toc { page-break-before: auto; }
100 |
101 | p > span:not([title=""]):not([class="XXX"]):not([class="impl"]):not([class="note"]),
102 | li > span:not([title=""]):not([class="XXX"]):not([class="impl"]):not([class="note"]) { border-bottom: solid #99CC99; }
103 |
104 | .head { margin: 0 0 1em; padding: 1em 0 0 0; display: block; }
105 | .head p { margin: 0; }
106 | .head h1 { margin: 0; }
107 | .head h2 { margin-top: 0; }
108 | .head .logo { float: right; margin: 0 1em; }
109 | .head .logo img { display: block; margin: 0 0 0 auto; border: none } /* remove border from top image */
110 | .head dl { margin: 1em 0; }
111 | p.copyright { font-size: 0.6em; font-style: oblique; margin: 0; }
112 |
113 | body > .toc > li { margin-top: 1em; margin-bottom: 1em; }
114 | body > .toc.brief > li { margin-top: 0.35em; margin-bottom: 0.35em; }
115 | body > .toc > li > * { margin-bottom: 0.5em; }
116 | body > .toc > li > * > li > * { margin-bottom: 0.25em; }
117 | .toc, .toc li { list-style: none; }
118 |
119 | .brief { margin-top: 1em; margin-bottom: 1em; line-height: 1.1; }
120 | .brief > li { margin: 0; padding: 0; }
121 | .brief > li > p { margin: 0; padding: 0; }
122 |
123 | .category-list { margin-top: -0.75em; margin-bottom: 1em; line-height: 1.5; }
124 | .category-list::before { content: '\21D2\A0'; font-size: 1.2em; font-weight: 900; }
125 | .category-list li { display: inline; }
126 | .category-list li:not(:last-child)::after { content: ', '; }
127 | .category-list li > span, .category-list li > a { text-transform: lowercase; }
128 | .category-list li * { text-transform: none; } /* don't affect nested in */
129 |
130 | [title=WIP], [title=TBW] { background: red; color: yellow; padding: 0.1em 0.3em; border: dotted white; margin: 0 0.7em 0 0.2em; }
131 | [title=SCS] { background: green; color: white; padding: 0.1em 0.3em; border-style: none dashed; margin: 0 0.7em 0 0.2em; }
132 | [title=WIP] :link, [title=WIP] :visited,
133 | [title=TBW] :link, [title=TBW] :visited,
134 | [title=SCS] :link, [title=SCS] :visited { background: transparent; color: inherit; }
135 |
136 | .big-issue, .XXX { color: #E50000; background: white; border: solid red; padding: 0.5em; margin: 1em 0; }
137 | .big-issue > :first-child, .XXX > :first-child { margin-top: 0; }
138 | p .big-issue, p .XXX { line-height: 3em; }
139 | .note { color: green; background: transparent; font-family: sans-serif, Droid Sans Fallback; }
140 | .warning { color: red; background: transparent; }
141 | .note, .warning { font-weight: bolder; font-style: italic; }
142 | .note em, .warning em, .note i, .warning i, .note var, .warning var { font-style: normal; }
143 | p.note, div.note { padding: 0.5em 2em; }
144 | span.note { padding: 0 2em; }
145 | .note p:first-child, .warning p:first-child { margin-top: 0; }
146 | .note p:last-child, .warning p:last-child { margin-bottom: 0; }
147 | dd > .note:first-child { margin-bottom: 0; }
148 | .warning:before { font-style: normal; }
149 |
150 | .tablenote { margin: 0.25em 0; }
151 | .tablenote small { font-size: 0.9em; }
152 |
153 | .XXX:before, .XXX:after { content: " ** "; position: absolute; left: 0; width: 8em; text-align: right; }
154 | p.note:before { content: 'Note: '; }
155 | p.warning:before { content: '\26A0 Warning! '; }
156 |
157 | .bookkeeping:before { display: block; content: 'Bookkeeping details'; font-weight: bolder; font-style: italic; }
158 | .bookkeeping { font-size: 0.8em; margin: 2em 0; }
159 | .bookkeeping p { margin: 0.5em 2em; display: list-item; list-style: square; }
160 | .bookkeeping dt { margin: 0.5em 2em 0; }
161 | .bookkeeping dd { margin: 0 3em 0.5em; }
162 |
163 | .critical { margin: 1em; border: double thick red; padding: 1em; background: #FFFFCC; }
164 | .critical > :first-child { margin-top: 0; }
165 |
166 | h4 { position: relative; z-index: 3; }
167 | h4 + .element, h4 + div + .element { margin-top: -2.5em; padding-top: 2em; }
168 | .element { background: #EEFFEE; color: black; margin: 0 0 1em 0.15em; padding: 0 1em 0.25em 0.75em; border-left: solid #99FF99 0.25em; position: relative; z-index: 1; }
169 | .element:before { position: absolute; z-index: 2; top: 0; left: -1.15em; height: 2em; width: 0.9em; background: #EEFFEE; content: ' '; border-style: none none solid solid; border-color: #99FF99; border-width: 0.25em; }
170 | .element:not(:hover) > dt > :link, .element:not(:hover) > dt > :visited { color: inherit; text-decoration: none; }
171 |
172 | table.css-property caption { text-align: left; font: inherit; font-weight: bold; }
173 | table.css-property th { font: inherit; font-style: italic; text-align: left; padding-left: 2em; }
174 |
175 | .example { display: block; color: #222222; background: #FCFCFC; border-left: double; margin-left: 2em; padding-left: 1em; }
176 | td > .example:only-child { margin: 0 0 0 0.1em; }
177 |
178 | td.non-rectangular-cell-continuation { border-left-style: hidden; }
179 | td.non-rectangular-cell-indentation { border-top-style: hidden; min-width: 2em; }
180 |
181 | .hide { display: none }
182 |
183 | body.dfnEnabled dfn { cursor: pointer; }
184 | .dfnPanel {
185 | display: inline;
186 | position: absolute;
187 | z-index: 10;
188 | height: auto;
189 | width: auto;
190 | padding: 0.5em 0.75em;
191 | font: small sans-serif, Droid Sans Fallback;
192 | background: #DDDDDD;
193 | color: black;
194 | border: outset 0.2em;
195 | }
196 | .dfnPanel * { margin: 0; padding: 0; font: inherit; text-indent: 0; }
197 | .dfnPanel :link, .dfnPanel :visited { color: black; }
198 | .dfnPanel p { font-weight: bolder; }
199 | .dfnPanel * + p { margin-top: 0.25em; }
200 | .dfnPanel li { list-style-position: inside; }
201 |
202 | @media aural {
203 | h1, h2, h3 { stress: 20; richness: 90 }
204 | .hide { speak: none }
205 | p.copyright { volume: x-soft; speech-rate: x-fast }
206 | dt { pause-before: 20% }
207 | code, pre { speak-punctuation: code }
208 | }
209 |
210 | @media print {
211 | html { font-size: 8pt; }
212 | @page { margin: 1cm 1cm 1cm 1cm; }
213 | @page :left {
214 | @bottom-left {
215 | font: 6pt sans-serif, Droid Sans Fallback;
216 | content: counter(page);
217 | padding-top: 0em;
218 | vertical-align: top;
219 | }
220 | }
221 | @page :right {
222 | @bottom-right {
223 | font: 6pt sans-serif, Droid Sans Fallback;
224 | content: counter(page);
225 | text-align: right;
226 | vertical-align: top;
227 | padding-top: 0em;
228 | }
229 | }
230 | a[href^="#"]::after { font-size: 0.6em; vertical-align: super; padding: 0 0.15em 0 0.15em; content: "p" target-counter(attr(href), page); }
231 | .toc a::after { font: inherit; vertical-align: baseline; padding: 0; content: leader('.') target-counter(attr(href), page); }
232 | pre a[href^="#"]::after, blockquote a[href^="#"]::after { content: ""; padding: 0; }
233 | table { font-size: smaller; }
234 | :link, :visited { text-decoration: none; color: inherit; background: transparent; }
235 | }
236 |
237 | ul.domTree, ul.domTree ul { padding: 0 0 0 1em; margin: 0; }
238 | ul.domTree li { padding: 0; margin: 0; list-style: none; position: relative; }
239 | ul.domTree li li { list-style: none; }
240 | ul.domTree li:first-child::before { position: absolute; top: 0; height: 0.6em; left: -0.75em; width: 0.5em; border-style: none none solid solid; content: ''; border-width: 0.1em; }
241 | ul.domTree li:not(:last-child)::after { position: absolute; top: 0; bottom: -0.6em; left: -0.75em; width: 0.5em; border-style: none none solid solid; content: ''; border-width: 0.1em; }
242 | ul.domTree span { font-style: italic; font-family: serif, Droid Sans Fallback; }
243 | ul.domTree .t1 code { color: purple; font-weight: bold; }
244 | ul.domTree .t2 { font-style: normal; font-family: monospace, Droid Sans Fallback; }
245 | ul.domTree .t2 .name { color: black; font-weight: bold; }
246 | ul.domTree .t2 .value { color: blue; font-weight: normal; }
247 | ul.domTree .t3 code, .domTree .t4 code, .domTree .t5 code { color: gray; }
248 | ul.domTree .t7 code, .domTree .t8 code { color: green; }
249 | ul.domTree .t10 code { color: teal; }
250 |
251 | :target {
252 | background: #ffa;
253 | -moz-box-shadow: 0 0 25px #ffa;
254 | -webkit-box-shadow: 0 0 150px #ffa;
255 | box-shadow: 0 0 25px #ffa;
256 | }
257 |
258 | /*body:not(.statusEnabled) .head, body:not(.dfnEnabled) .head { background: bottom right url(http://hixie.ch/resources/images/spinner) no-repeat; }*/
259 |
260 | div.compilation:before {
261 | content: "Compilation";
262 | font: bold small sans-serif;
263 | /*float: left;*/
264 | position: absolute;
265 | top: -0.9em;
266 | left: -2.5em;
267 | width: 7.5em;
268 | text-align: center;
269 | line-height: 1em;
270 | color: #F8FFDD;
271 | background: #060;
272 | padding: 0.1em;
273 | border: thin solid #999;
274 | /*margin: -1.3em 0 0.3em -2.5em;*/
275 | }
276 | div.compilation, pre.compilation {
277 | background: #F8FFDD;
278 | padding: 0.5em;
279 | margin: 1em 0;
280 | border: thin solid #999;
281 | position: relative;
282 | }
283 | pre.compilation {
284 | padding-top: 1.5em;
285 | }
286 | div.compilation { color: #060 }
287 | pre.compilation { color: #060 }
288 |
--------------------------------------------------------------------------------
/historic/subtypes.graffle:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ActiveLayerIndex
6 | 0
7 | ApplicationVersion
8 |
9 | com.omnigroup.OmniGraffle
10 | 139.16.0.171715
11 |
12 | AutoAdjust
13 |
14 | BackgroundGraphic
15 |
16 | Bounds
17 | {{0, 0}, {576, 733}}
18 | Class
19 | SolidGraphic
20 | ID
21 | 2
22 | Style
23 |
24 | shadow
25 |
26 | Draws
27 | NO
28 |
29 | stroke
30 |
31 | Draws
32 | NO
33 |
34 |
35 |
36 | BaseZoom
37 | 0
38 | CanvasOrigin
39 | {0, 0}
40 | ColumnAlign
41 | 1
42 | ColumnSpacing
43 | 36
44 | CreationDate
45 | 2012-10-24 05:05:27 +0000
46 | Creator
47 | David Herman
48 | DisplayScale
49 | 1 0/72 in = 1.0000 in
50 | GraphDocumentVersion
51 | 8
52 | GraphicsList
53 |
54 |
55 | Class
56 | LineGraphic
57 | Head
58 |
59 | ID
60 | 107
61 |
62 | ID
63 | 109
64 | Points
65 |
66 | {163.5, 443}
67 | {103, 319}
68 |
69 | Style
70 |
71 | stroke
72 |
73 | HeadArrow
74 | FilledArrow
75 | Legacy
76 |
77 | LineType
78 | 1
79 | TailArrow
80 | 0
81 |
82 |
83 | Tail
84 |
85 | ID
86 | 57
87 | Info
88 | 1
89 |
90 |
91 |
92 | Class
93 | LineGraphic
94 | Head
95 |
96 | ID
97 | 107
98 | Info
99 | 1
100 |
101 | ID
102 | 113
103 | Points
104 |
105 | {195.5, 346}
106 | {103, 319}
107 |
108 | Style
109 |
110 | stroke
111 |
112 | HeadArrow
113 | FilledArrow
114 | Legacy
115 |
116 | LineType
117 | 1
118 | TailArrow
119 | 0
120 |
121 |
122 | Tail
123 |
124 | ID
125 | 7
126 | Info
127 | 1
128 |
129 |
130 |
131 | Bounds
132 | {{68, 249}, {70, 70}}
133 | Class
134 | ShapedGraphic
135 | ID
136 | 107
137 | Magnets
138 |
139 | {0, 0.5}
140 |
141 | Shape
142 | Rectangle
143 | Style
144 |
145 | fill
146 |
147 | Color
148 |
149 | b
150 | 0.901961
151 | g
152 | 0.901961
153 | r
154 | 0.901961
155 |
156 |
157 |
158 | Text
159 |
160 | Text
161 | {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
162 | \cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Menlo-Regular;}
163 | {\colortbl;\red255\green255\blue255;}
164 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
165 |
166 | \f0\fs24 \cf0 doublish}
167 |
168 |
169 |
170 | Bounds
171 | {{438, 346}, {70, 70}}
172 | Class
173 | ShapedGraphic
174 | ID
175 | 104
176 | Magnets
177 |
178 | {0, -0.5}
179 |
180 | Shape
181 | Rectangle
182 | Style
183 |
184 | fill
185 |
186 | Color
187 |
188 | b
189 | 0.901961
190 | g
191 | 0.901961
192 | r
193 | 0.901961
194 |
195 |
196 |
197 | Text
198 |
199 | Text
200 | {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
201 | \cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Menlo-Regular;}
202 | {\colortbl;\red255\green255\blue255;}
203 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
204 |
205 | \f0\fs24 \cf0 void}
206 |
207 |
208 |
209 | Class
210 | LineGraphic
211 | Head
212 |
213 | ID
214 | 60
215 | Position
216 | 0.95704245567321777
217 |
218 | ID
219 | 103
220 | Points
221 |
222 | {328.5, 443}
223 | {294.29327151179314, 417.15985208749771}
224 |
225 | Style
226 |
227 | stroke
228 |
229 | HeadArrow
230 | FilledArrow
231 | Legacy
232 |
233 | LineType
234 | 1
235 | TailArrow
236 | 0
237 |
238 |
239 | Tail
240 |
241 | ID
242 | 3
243 | Info
244 | 1
245 |
246 |
247 |
248 | Class
249 | LineGraphic
250 | Head
251 |
252 | ID
253 | 4
254 | Info
255 | 2
256 |
257 | ID
258 | 93
259 | Points
260 |
261 | {381.5, 535}
262 | {434.5, 513}
263 |
264 | Style
265 |
266 | stroke
267 |
268 | HeadArrow
269 | FilledArrow
270 | Legacy
271 |
272 | LineType
273 | 1
274 | TailArrow
275 | 0
276 |
277 |
278 | Tail
279 |
280 | ID
281 | 91
282 |
283 |
284 |
285 | Class
286 | LineGraphic
287 | Head
288 |
289 | ID
290 | 3
291 | Info
292 | 2
293 |
294 | ID
295 | 92
296 | Points
297 |
298 | {381.5, 535}
299 | {328.5, 513}
300 |
301 | Style
302 |
303 | stroke
304 |
305 | HeadArrow
306 | FilledArrow
307 | Legacy
308 |
309 | LineType
310 | 1
311 | TailArrow
312 | 0
313 |
314 |
315 | Tail
316 |
317 | ID
318 | 91
319 | Info
320 | 1
321 |
322 |
323 |
324 | Bounds
325 | {{346.5, 535}, {70, 70}}
326 | Class
327 | ShapedGraphic
328 | ID
329 | 91
330 | Magnets
331 |
332 | {0, -0.5}
333 | {0, 0.5}
334 |
335 | Shape
336 | Rectangle
337 | Text
338 |
339 | Text
340 | {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
341 | \cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Menlo-Regular;}
342 | {\colortbl;\red255\green255\blue255;}
343 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
344 |
345 | \f0\fs24 \cf0 fixnum}
346 |
347 |
348 |
349 | Class
350 | LineGraphic
351 | Head
352 |
353 | ID
354 | 71
355 |
356 | ID
357 | 112
358 | Points
359 |
360 | {195.5, 346}
361 | {288, 319}
362 |
363 | Style
364 |
365 | stroke
366 |
367 | HeadArrow
368 | FilledArrow
369 | Legacy
370 |
371 | LineType
372 | 1
373 | TailArrow
374 | 0
375 |
376 |
377 | Tail
378 |
379 | ID
380 | 7
381 | Info
382 | 1
383 |
384 |
385 |
386 | Class
387 | LineGraphic
388 | Head
389 |
390 | ID
391 | 71
392 | Info
393 | 1
394 |
395 | ID
396 | 72
397 | Points
398 |
399 | {380.5, 346}
400 | {288, 319}
401 |
402 | Style
403 |
404 | stroke
405 |
406 | HeadArrow
407 | FilledArrow
408 | Legacy
409 |
410 | LineType
411 | 1
412 | TailArrow
413 | 0
414 |
415 |
416 | Tail
417 |
418 | ID
419 | 5
420 |
421 |
422 |
423 | Bounds
424 | {{253, 249}, {70, 70}}
425 | Class
426 | ShapedGraphic
427 | ID
428 | 71
429 | Magnets
430 |
431 | {0, 0.5}
432 |
433 | Shape
434 | Rectangle
435 | Style
436 |
437 | fill
438 |
439 | Color
440 |
441 | b
442 | 0.901961
443 | g
444 | 0.901961
445 | r
446 | 0.901961
447 |
448 |
449 |
450 | Text
451 |
452 | Text
453 | {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
454 | \cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Menlo-Regular;}
455 | {\colortbl;\red255\green255\blue255;}
456 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
457 |
458 | \f0\fs24 \cf0 intish}
459 |
460 |
461 |
462 | Class
463 | LineGraphic
464 | Head
465 |
466 | ID
467 | 11
468 |
469 | ID
470 | 60
471 | Points
472 |
473 | {434.5, 443}
474 | {288, 416}
475 |
476 | Style
477 |
478 | stroke
479 |
480 | HeadArrow
481 | FilledArrow
482 | Legacy
483 |
484 | LineType
485 | 1
486 | TailArrow
487 | 0
488 |
489 |
490 | Tail
491 |
492 | ID
493 | 4
494 | Info
495 | 1
496 |
497 |
498 |
499 | Class
500 | LineGraphic
501 | Head
502 |
503 | ID
504 | 11
505 |
506 | ID
507 | 58
508 | Points
509 |
510 | {163.5, 443}
511 | {288, 416}
512 |
513 | Style
514 |
515 | stroke
516 |
517 | HeadArrow
518 | FilledArrow
519 | Legacy
520 |
521 | LineType
522 | 1
523 | TailArrow
524 | 0
525 |
526 |
527 | Tail
528 |
529 | ID
530 | 57
531 | Info
532 | 1
533 |
534 |
535 |
536 | Bounds
537 | {{128.5, 443}, {70, 70}}
538 | Class
539 | ShapedGraphic
540 | ID
541 | 57
542 | Magnets
543 |
544 | {0, -0.5}
545 |
546 | Shape
547 | Rectangle
548 | Text
549 |
550 | Text
551 | {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
552 | \cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Menlo-Regular;}
553 | {\colortbl;\red255\green255\blue255;}
554 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
555 |
556 | \f0\fs24 \cf0 double}
557 |
558 |
559 |
560 | Class
561 | LineGraphic
562 | Head
563 |
564 | ID
565 | 5
566 |
567 | ID
568 | 20
569 | Points
570 |
571 | {434.5, 443}
572 | {380.5, 416}
573 |
574 | Style
575 |
576 | stroke
577 |
578 | HeadArrow
579 | FilledArrow
580 | Legacy
581 |
582 | LineType
583 | 1
584 | TailArrow
585 | 0
586 |
587 |
588 | Tail
589 |
590 | ID
591 | 4
592 | Info
593 | 1
594 |
595 |
596 |
597 | Class
598 | LineGraphic
599 | Head
600 |
601 | ID
602 | 5
603 | Info
604 | 2
605 |
606 | ID
607 | 18
608 | Points
609 |
610 | {328.5, 443}
611 | {380.5, 416}
612 |
613 | Style
614 |
615 | stroke
616 |
617 | HeadArrow
618 | FilledArrow
619 | Legacy
620 |
621 | LineType
622 | 1
623 | TailArrow
624 | 0
625 |
626 |
627 | Tail
628 |
629 | ID
630 | 3
631 | Info
632 | 1
633 |
634 |
635 |
636 | Bounds
637 | {{253, 346}, {70, 70}}
638 | Class
639 | ShapedGraphic
640 | ID
641 | 11
642 | Magnets
643 |
644 | {0, 0.5}
645 | {0, -0.5}
646 |
647 | Shape
648 | Rectangle
649 | Text
650 |
651 | Text
652 | {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
653 | \cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Menlo-Regular;}
654 | {\colortbl;\red255\green255\blue255;}
655 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
656 |
657 | \f0\fs24 \cf0 extern}
658 |
659 |
660 |
661 | Bounds
662 | {{160.5, 346}, {70, 70}}
663 | Class
664 | ShapedGraphic
665 | ID
666 | 7
667 | Magnets
668 |
669 | {0, -0.5}
670 | {0, 0.49999999999999956}
671 |
672 | Shape
673 | Rectangle
674 | Style
675 |
676 | fill
677 |
678 | Color
679 |
680 | b
681 | 0.901961
682 | g
683 | 0.901961
684 | r
685 | 0.901961
686 |
687 |
688 |
689 | Text
690 |
691 | Text
692 | {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
693 | \cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Menlo-Regular;}
694 | {\colortbl;\red255\green255\blue255;}
695 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
696 |
697 | \f0\fs24 \cf0 unknown}
698 |
699 |
700 |
701 | Bounds
702 | {{345.5, 346}, {70, 70}}
703 | Class
704 | ShapedGraphic
705 | ID
706 | 5
707 | Magnets
708 |
709 | {0, -0.5}
710 | {0, 0.5}
711 |
712 | Shape
713 | Rectangle
714 | Style
715 |
716 | fill
717 |
718 | Color
719 |
720 | b
721 | 0.901961
722 | g
723 | 0.901961
724 | r
725 | 0.901961
726 |
727 |
728 |
729 | Text
730 |
731 | Text
732 | {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
733 | \cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Menlo-Regular;}
734 | {\colortbl;\red255\green255\blue255;}
735 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
736 |
737 | \f0\fs24 \cf0 int}
738 |
739 |
740 |
741 | Bounds
742 | {{399.5, 443}, {70, 70}}
743 | Class
744 | ShapedGraphic
745 | ID
746 | 4
747 | Magnets
748 |
749 | {0, -0.5}
750 | {0, 0.5}
751 |
752 | Shape
753 | Rectangle
754 | Text
755 |
756 | Text
757 | {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
758 | \cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Menlo-Regular;}
759 | {\colortbl;\red255\green255\blue255;}
760 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
761 |
762 | \f0\fs24 \cf0 unsigned}
763 |
764 |
765 |
766 | Bounds
767 | {{293.5, 443}, {70, 70}}
768 | Class
769 | ShapedGraphic
770 | ID
771 | 3
772 | Magnets
773 |
774 | {0, -0.5}
775 | {0, 0.5}
776 |
777 | Shape
778 | Rectangle
779 | Text
780 |
781 | Text
782 | {\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
783 | \cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Menlo-Regular;}
784 | {\colortbl;\red255\green255\blue255;}
785 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
786 |
787 | \f0\fs24 \cf0 signed}
788 |
789 |
790 |
791 | GridInfo
792 |
793 | GuidesLocked
794 | NO
795 | GuidesVisible
796 | YES
797 | HPages
798 | 1
799 | ImageCounter
800 | 1
801 | KeepToScale
802 |
803 | Layers
804 |
805 |
806 | Lock
807 | NO
808 | Name
809 | Layer 1
810 | Print
811 | YES
812 | View
813 | YES
814 |
815 |
816 | LayoutInfo
817 |
818 | Animate
819 | NO
820 | circoMinDist
821 | 18
822 | circoSeparation
823 | 0.0
824 | layoutEngine
825 | dot
826 | neatoSeparation
827 | 0.0
828 | twopiSeparation
829 | 0.0
830 |
831 | LinksVisible
832 | NO
833 | MagnetsVisible
834 | NO
835 | MasterSheets
836 |
837 | ModificationDate
838 | 2013-01-15 05:36:58 +0000
839 | Modifier
840 | David Herman
841 | NotesVisible
842 | NO
843 | Orientation
844 | 2
845 | OriginVisible
846 | NO
847 | PageBreaks
848 | YES
849 | PrintInfo
850 |
851 | NSBottomMargin
852 |
853 | float
854 | 41
855 |
856 | NSHorizonalPagination
857 |
858 | coded
859 | BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG
860 |
861 | NSLeftMargin
862 |
863 | float
864 | 18
865 |
866 | NSPaperSize
867 |
868 | size
869 | {612, 792}
870 |
871 | NSPrintReverseOrientation
872 |
873 | int
874 | 0
875 |
876 | NSPrinter
877 |
878 | coded
879 | BAtzdHJlYW10eXBlZIHoA4QBQISEhAlOU1ByaW50ZXIAhIQITlNPYmplY3QAhZKEhIQITlNTdHJpbmcBlIQBKw1NVFYyLUh5cGVyaW9uhoY=
880 |
881 | NSPrinterName
882 |
883 | string
884 | MTV2-Hyperion
885 |
886 | NSRightMargin
887 |
888 | float
889 | 18
890 |
891 | NSTopMargin
892 |
893 | float
894 | 18
895 |
896 |
897 | PrintOnePage
898 |
899 | ReadOnly
900 | NO
901 | RowAlign
902 | 1
903 | RowSpacing
904 | 36
905 | SheetTitle
906 | Canvas 1
907 | SmartAlignmentGuidesActive
908 | YES
909 | SmartDistanceGuidesActive
910 | YES
911 | UniqueID
912 | 1
913 | UseEntirePage
914 |
915 | VPages
916 | 1
917 | WindowInfo
918 |
919 | CurrentSheet
920 | 0
921 | ExpandedCanvases
922 |
923 |
924 | name
925 | Canvas 1
926 |
927 |
928 | Frame
929 | {{40, 73}, {1005, 673}}
930 | ListView
931 |
932 | OutlineWidth
933 | 142
934 | RightSidebar
935 |
936 | ShowRuler
937 |
938 | Sidebar
939 |
940 | SidebarWidth
941 | 120
942 | VisibleRegion
943 | {{-147, 138}, {870, 534}}
944 | Zoom
945 | 1
946 | ZoomValues
947 |
948 |
949 | Canvas 1
950 | 1
951 | 0.5
952 |
953 |
954 |
955 |
956 |
957 |
--------------------------------------------------------------------------------
/lib/validate.js:
--------------------------------------------------------------------------------
1 | var esprima = require('esprima');
2 | var dict = require('dict');
3 | var match = require('pattern-match');
4 | var array = require('array-extended');
5 | var env = require('./env');
6 | var ty = require('./types');
7 | var fail = require('./fail');
8 | var tables = require('./tables');
9 | var Report = require('./report');
10 |
11 | // -----------------------------------------------------------------------------
12 | // utilities
13 | // -----------------------------------------------------------------------------
14 |
15 | var log = Math.log;
16 |
17 | var LOG2 = log(2);
18 |
19 | // (number) -> number
20 | function log2(x) {
21 | return log(x) / LOG2;
22 | }
23 |
24 | // (number) -> boolean
25 | function powerOf2(x) {
26 | return (x & (x - 1)) === 0;
27 | }
28 |
29 | // (Statement) -> boolean
30 | function nonEmpty(s) {
31 | return s.type !== 'EmptyStatement';
32 | }
33 |
34 | // ([AST], [{ name: string, type: string }]) -> { string: AST, ... }
35 | function split(nodes, filters) {
36 | var result = {};
37 | var nNodes = nodes.length, nFilters = filters.length;
38 | var iNode = 0;
39 | for (var iFilter = 0; iFilter < nFilters; iFilter++) {
40 | var filter = filters[iFilter];
41 | var next = [];
42 | while (iNode < nNodes && nodes[iNode].type === filter.type) {
43 | next.push(nodes[iNode]);
44 | iNode++;
45 | }
46 | result[filter.name] = next;
47 | }
48 | return result;
49 | }
50 |
51 | // (string) -> boolean
52 | function hasDot(s) {
53 | return s.indexOf(".") !== -1;
54 | }
55 |
56 | // (string) -> boolean
57 | function dotless(s) {
58 | return !hasDot(s);
59 | }
60 |
61 | // (Expression, Expression) -> [Expression]
62 | function flattenAdditive(left, right) {
63 | var result = [];
64 |
65 | // Since .pop is faster than .shift we'll pop tasks from the end.
66 | var todo = [right, left];
67 | while (todo.length > 0) {
68 | match(todo.pop(), function(when) {
69 | when({
70 | type: 'BinaryExpression',
71 | operator: match.some('+', '-'),
72 | left: match.var('left'),
73 | right: match.var('right')
74 | }, function(vars) {
75 | todo.push(vars.right, vars.left);
76 | });
77 |
78 | when(match.var('operand'), function(vars) {
79 | result.push(vars.operand);
80 | });
81 | });
82 | }
83 |
84 | return result;
85 | }
86 |
87 | // -----------------------------------------------------------------------------
88 | // main methods
89 | // -----------------------------------------------------------------------------
90 |
91 | function Validator() {
92 | this._roots = {
93 | stdlib: null,
94 | foreign: null,
95 | heap: null
96 | };
97 | this._globals = env(this);
98 | this._locals = null;
99 | this._src = null;
100 | this._result = null;
101 | }
102 |
103 | var Vp = Validator.prototype;
104 |
105 | // (AST, string[, Function]) -> any
106 | // Delegates to pattern-match library, converting MatchErrors to validation errors.
107 | Vp.match = function(node, desc, body) {
108 | var self = this;
109 | if (body) {
110 | try {
111 | return match(node, body, this);
112 | } catch (e) {
113 | failWithLocation(e);
114 | }
115 | }
116 |
117 | var delayed = match(node);
118 |
119 | return {
120 | when: function(pattern, template) {
121 | try {
122 | return delayed.when(pattern, template, self);
123 | } catch (e) {
124 | failWithLocation(e);
125 | }
126 | }
127 | };
128 |
129 | function failWithLocation(e) {
130 | if (e instanceof match.MatchError) {
131 | var loc = e && e.actual ? e.actual.loc : null;
132 | self.fail("invalid " + desc, loc);
133 | } else {
134 | throw e;
135 | }
136 | }
137 | };
138 |
139 | // (string) -> Report
140 | Vp.validate = function validate(src) {
141 | this._src = src;
142 | var module = esprima.parse("(" + src + ")", { raw: true, loc: true }).body[0].expression;
143 | var vars = this.match(module, "asm.js module declaration").when({
144 | type: 'FunctionExpression',
145 | id: match.var('id', { type: 'Identifier' }),
146 | params: match.var('params', { length: match.range(0, 4) }),
147 | body: { loc: match.var('loc'), body: match.var('body') }
148 | });
149 | return this.module(vars.params, vars.body.filter(nonEmpty), vars.loc);
150 | };
151 |
152 | // (string, Loc) -/->
153 | Vp.fail = function fail_(msg, loc) {
154 | fail(msg, this._src, loc);
155 | };
156 |
157 | // ([Statement], Loc) -> {
158 | // imports: [VariableDeclaration],
159 | // functions: [FunctionDeclaration],
160 | // tables: [VariableDeclaration],
161 | // exports: Expression
162 | // }
163 | Vp.splitModule = function splitModule(body, loc) {
164 | var sections = split(body, [
165 | { name: 'directive', type: 'ExpressionStatement' },
166 | { name: 'globals', type: 'VariableDeclaration' },
167 | { name: 'functions', type: 'FunctionDeclaration' },
168 | { name: 'tables', type: 'VariableDeclaration' },
169 | { name: 'exports', type: 'ReturnStatement' }
170 | ]);
171 | if (sections.directive.length !== 1)
172 | this.fail("expected single \"use asm\" directive, got " + sections.directive.length + " ExpressionStatement nodes", loc);
173 | this.match(sections.directive, "\"use asm\" directive").when([{
174 | type: 'ExpressionStatement',
175 | expression: { type: 'Literal', value: "use asm" }
176 | }]);
177 | if (sections.exports.length !== 1)
178 | this.fail("expected single exports declaration, got " + sections.exports.length + " ReturnStatement nodes", loc);
179 | return {
180 | globals: sections.globals,
181 | functions: sections.functions,
182 | tables: sections.tables,
183 | exports: sections.exports[0].argument
184 | };
185 | };
186 |
187 | // (Identifier, Statement) -> Type
188 | Vp.paramType = function paramType(id, stmt) {
189 | return this.match(stmt, "parameter annotation").when({
190 | type: 'ExpressionStatement',
191 | expression: {
192 | type: 'AssignmentExpression',
193 | left: { type: 'Identifier', name: id.name },
194 | right: match.var('right')
195 | }
196 | }, function(vars) {
197 | return this.match(vars.right, "parameter annotation type", function(when) {
198 | when({
199 | type: 'UnaryExpression',
200 | operator: '+',
201 | argument: { type: 'Identifier', name: id.name }
202 | }, function() {
203 | return ty.Double;
204 | });
205 |
206 | when({
207 | type: 'BinaryExpression',
208 | operator: '|',
209 | left: { type: 'Identifier', name: id.name },
210 | right: { type: 'Literal', value: 0 }
211 | }, function() {
212 | return ty.Int;
213 | });
214 | });
215 | });
216 | };
217 |
218 | // (Statement) -> Type
219 | Vp.returnType = function returnType(stmt) {
220 | if (stmt.type !== 'ReturnStatement')
221 | return ty.Void;
222 |
223 | return this.match(stmt.argument, "return type annotation", function(when) {
224 | when(null, function() {
225 | return ty.Void;
226 | });
227 |
228 | when({
229 | type: 'UnaryExpression',
230 | operator: '+'
231 | }, function() {
232 | return ty.Double;
233 | });
234 |
235 | when({
236 | type: 'BinaryExpression',
237 | operator: '|',
238 | right: { type: 'Literal', value: 0 }
239 | }, function() {
240 | return ty.Signed;
241 | });
242 |
243 | when({
244 | type: 'Literal',
245 | value: match.number,
246 | raw: hasDot
247 | }, function() {
248 | return ty.Double;
249 | });
250 |
251 | when({
252 | type: 'Literal',
253 | value: match.all(match.number,
254 | match.range(-0x80000000, 0x100000000)),
255 | raw: dotless
256 | }, function() {
257 | return ty.Signed;
258 | });
259 | });
260 | };
261 |
262 | // (FunctionDeclaration) -> Type
263 | Vp.functionType = function functionType(funDecl) {
264 | var params = funDecl.params;
265 | var n = params.length;
266 | var body = funDecl.body.body.filter(nonEmpty);
267 | if (body.length < n)
268 | this.fail("not enough annotations for parameters to " + funDecl.id.name, funDecl.body.loc);
269 | var paramTypes = array.zip(params, body.slice(0, n)).map(function(pair) {
270 | return this.paramType(pair[0], pair[1]);
271 | }, this);
272 | var returnType = body.length > 0 ? this.returnType(body[body.length - 1]) : ty.Void;
273 | return ty.Arrow(paramTypes, returnType);
274 | };
275 |
276 | // (string, Loc) -> Type
277 | Vp.lookup = function lookup(x, loc) {
278 | if (this._locals) {
279 | var t = this._locals.lookup(x);
280 | if (t)
281 | return t;
282 | }
283 |
284 | var mt = this._globals.lookup(x);
285 | if (!mt)
286 | this.fail("unbound variable " + x, loc);
287 |
288 | return mt.type;
289 | };
290 |
291 | // (string, Loc) -> ValueType
292 | Vp.lookupValueType = function lookupValueType(x, loc) {
293 | var t = this.lookup(x, loc);
294 | if (!(t instanceof ty.ValueType))
295 | this.fail("expected value type, got " + t, loc);
296 | return t;
297 | };
298 |
299 | // (string, Expression, Loc) -> { mutable: boolean, type: Type }
300 | Vp.global = function global(x, rhs, loc) {
301 | if (!rhs)
302 | this.fail("global variable missing initializer expression", loc);
303 |
304 | return this.match(rhs, "global declaration", function(when) {
305 | when({
306 | type: 'Literal',
307 | value: match.var('f', match.number),
308 | raw: match.var('src', hasDot)
309 | }, function(vars) {
310 | return { mutable: true, type: ty.Double };
311 | }, this);
312 |
313 | when({
314 | type: 'Literal',
315 | value: match.var('n', match.all(match.integer,
316 | match.range(-0x80000000, 0x100000000))),
317 | raw: match.var('src')
318 | }, function(vars) {
319 | return { mutable: true, type: ty.Int };
320 | }, this);
321 |
322 | when({
323 | type: 'MemberExpression',
324 | object: {
325 | type: 'MemberExpression',
326 | object: {
327 | type: 'Identifier',
328 | name: this._roots.stdlib
329 | },
330 | property: {
331 | type: 'Identifier',
332 | name: 'Math'
333 | }
334 | },
335 | property: {
336 | type: 'Identifier',
337 | name: match.var('x')
338 | }
339 | }, function(vars) {
340 | if (!tables.STDLIB_MATH_TYPES.has(vars.x))
341 | this.fail("unknown library: Math." + vars.x, loc);
342 | return { mutable: false, type: tables.STDLIB_MATH_TYPES.get(vars.x) };
343 | }, this);
344 |
345 | when({
346 | type: 'MemberExpression',
347 | object: {
348 | type: 'Identifier',
349 | name: this._roots.stdlib
350 | },
351 | property: match.var('x')
352 | }, function(vars) {
353 | if (!tables.STDLIB_TYPES.has(vars.x))
354 | this.fail("unknown library: " + vars.x, loc);
355 | return { mutable: false, type: tables.STDLIB_TYPES.get(vars.x) };
356 | }, this);
357 |
358 | when({
359 | type: 'MemberExpression',
360 | object: {
361 | type: 'Identifier',
362 | name: this._roots.foreign
363 | },
364 | property: match.var('x')
365 | }, function(vars) {
366 | return { mutable: false, type: ty.Function };
367 | }, this);
368 |
369 | when({
370 | type: 'BinaryExpression',
371 | operator: '|',
372 | left: {
373 | type: 'MemberExpression',
374 | object: {
375 | type: 'Identifier',
376 | name: this._roots.foreign
377 | },
378 | property: match.var('x')
379 | },
380 | right: {
381 | type: 'Literal',
382 | value: 0
383 | }
384 | }, function(vars) {
385 | return { mutable: false, type: ty.Int };
386 | }, this);
387 |
388 | when({
389 | type: 'UnaryExpression',
390 | operator: '+',
391 | argument: {
392 | type: 'MemberExpression',
393 | object: {
394 | type: 'Identifier',
395 | name: this._roots.foreign
396 | },
397 | property: match.var('x')
398 | }
399 | }, function(vars) {
400 | return { mutable: false, type: ty.Double };
401 | }, this);
402 |
403 | when({
404 | type: 'NewExpression',
405 | callee: {
406 | type: 'MemberExpression',
407 | object: {
408 | type: 'Identifier',
409 | name: this._roots.stdlib
410 | },
411 | property: {
412 | type: 'Identifier',
413 | name: match.var('view'),
414 | loc: match.var('loc')
415 | }
416 | },
417 | arguments: match.var('args', [{ type: 'Identifier', name: this._roots.heap }])
418 | }, function(vars) {
419 | if (vars.args.length !== 1)
420 | this.fail("heap view constructor expects 1 argument, got " + vars.args.length, vars.args[1].loc);
421 | if (!tables.HEAP_VIEW_TYPES.has(vars.view))
422 | this.fail("unknown typed array type: " + vars.view, vars.loc);
423 | return { mutable: false, type: tables.HEAP_VIEW_TYPES.get(vars.view) };
424 | }, this);
425 | }, this);
426 | };
427 |
428 | // (string, Expression, Loc) -> Table
429 | Vp.table = function table(x, rhs, loc) {
430 | this.match(rhs, "function table").when({
431 | type: 'ArrayExpression',
432 | elements: match.var('elements')
433 | }, function(vars) {
434 | var fs = vars.elements.map(function(element) {
435 | return this.match(element, "function table entry").when(match.var('f', { type: 'Identifier' }),
436 | function(vars) { return vars.f; },
437 | this);
438 | }, this);
439 |
440 | if (fs.length === 0)
441 | this.fail("empty function table", loc);
442 | if (!powerOf2(fs.length))
443 | this.fail("function table length must be a power of 2, got " + fs.length, loc);
444 |
445 | var fts = fs.map(function(f) {
446 | var ft = this.lookup(f.name, f.loc);
447 | if (!(ft instanceof ty.Arrow))
448 | this.fail("non-function " + f.name + " in function table", f.loc);
449 | return ft;
450 | }, this);
451 |
452 | var ft = fts[0];
453 |
454 | for (var i = 1, n = fts.length; i < n; i++) {
455 | if (!ft.equals(fts[i]))
456 | this.fail("unexpected function type " + fs[i].name + " : " + fts[i] + " in function table", fs[i].loc);
457 | }
458 |
459 | return new ty.Table(ft, fs.length);
460 | });
461 | };
462 |
463 | // (string, Expression) -> Type
464 | Vp.local = function local(x, rhs) {
465 | return this.match(rhs, "declaration of local " + x, function(when) {
466 | when({
467 | type: 'Literal',
468 | value: match.number,
469 | raw: hasDot
470 | }, function(vars) {
471 | return ty.Double;
472 | }, this);
473 |
474 | when({
475 | type: 'Literal',
476 | value: match.all(match.integer, match.range(-0x80000000, 0x100000000))
477 | }, function(vars) {
478 | return ty.Int;
479 | }, this);
480 | });
481 | };
482 |
483 | // (FunctionDeclaration) -> void
484 | Vp.function = function function_(decl) {
485 | var f = decl.id.name;
486 | var ft = this._globals.lookup(f).type;
487 | var params = decl.params.map(function(id) { return id.name; });
488 | var paramTypes = ft.params;
489 | var resultType = ft.result;
490 | var body = decl.body.body.filter(nonEmpty);
491 |
492 | try {
493 | this._locals = env(this);
494 | this._result = resultType;
495 |
496 | // Bind the parameters.
497 | params.forEach(function(x, i) {
498 | this._locals.bind(x, paramTypes[i]);
499 | }, this);
500 |
501 | // Bind the locals.
502 | var i = params.length, n = body.length;
503 | while (i < n && body[i].type === 'VariableDeclaration') {
504 | body[i].declarations.forEach(function(dtor) {
505 | var x = dtor.id.name;
506 | this._locals.bind(x, this.local(x, dtor.init));
507 | }, this);
508 | i++;
509 | }
510 |
511 | // Check the body.
512 | this.statements(body.slice(i));
513 | } finally {
514 | this._locals = null;
515 | this._result = null;
516 | }
517 | };
518 |
519 | // (Expression) -> { type: 'single', export: { name: string, type: Arrow } }
520 | // | { type: 'multiple', exports: dict<{ name: string, type: Arrow }> }
521 | Vp.exports = function exports(expr) {
522 | return this.match(expr, "exports declaration", function(when) {
523 | when({
524 | type: 'Identifier',
525 | name: match.var('f'),
526 | loc: match.var('loc')
527 | }, function(vars) {
528 | var t = this.lookup(vars.f, vars.loc);
529 | if (!(t instanceof ty.Arrow))
530 | this.fail("expected exported function, got definition of type " + t, vars.loc);
531 | return { type: 'single', export: { name: vars.f, type: t } };
532 | }, this);
533 |
534 | when({
535 | type: 'ObjectExpression',
536 | properties: match.var('props')
537 | }, function(vars) {
538 | var table = dict();
539 |
540 | var self = this;
541 |
542 | function add(internal, external, loc) {
543 | var t = self.lookup(internal, loc);
544 | if (!(t instanceof ty.Arrow))
545 | self.fail("expected exported function, got definition of type " + t, loc);
546 | table.set(external, {
547 | name: internal,
548 | type: t
549 | });
550 | }
551 |
552 | vars.props.forEach(function(prop) {
553 | return this.match(prop, "export declaration", function(when) {
554 | when({
555 | key: {
556 | type: 'Literal',
557 | value: match.var('external', match.string)
558 | },
559 | value: {
560 | type: 'Identifier',
561 | name: match.var('internal'),
562 | loc: match.var('loc')
563 | },
564 | kind: 'init'
565 | }, function(vars) {
566 | add(vars.internal, vars.external, vars.loc);
567 | }, this);
568 |
569 | when({
570 | key: {
571 | type: 'Identifier',
572 | name: match.var('external')
573 | },
574 | value: {
575 | type: 'Identifier',
576 | name: match.var('internal'),
577 | loc: match.var('loc')
578 | },
579 | kind: 'init'
580 | }, function(vars) {
581 | add(vars.internal, vars.external, vars.loc);
582 | }, this);
583 | });
584 | }, this);
585 |
586 | return { type: 'multiple', exports: table };
587 | }, this);
588 | });
589 | };
590 |
591 | // ([Identifier], [Statement], Loc) -> Report
592 | Vp.module = function module(params, body, loc) {
593 | var sections = this.splitModule(body, loc);
594 |
595 | // Bind module parameters.
596 | params.forEach(function(id, i) {
597 | this._roots[tables.ROOT_NAMES[i]] = id.name;
598 | this._globals.bind(id.name, { mutable: false, type: ty.ModuleParameter }, id.loc);
599 | }, this);
600 |
601 | // Bind and check globals.
602 | sections.globals.forEach(function(varDecl) {
603 | varDecl.declarations.forEach(function(decl) {
604 | var x = decl.id.name;
605 | var mt = this.global(x, decl.init, decl.loc);
606 | this._globals.bind(x, mt, decl.id.loc);
607 | }, this);
608 | }, this);
609 |
610 | // Bind function types.
611 | sections.functions.forEach(function(funDecl) {
612 | var id = funDecl.id, f = id.name;
613 | var t = this.functionType(funDecl);
614 | this._globals.bind(f, { mutable: false, type: t }, id.loc);
615 | }, this);
616 |
617 | // Bind and check function tables.
618 | sections.tables.forEach(function(varDecl) {
619 | varDecl.declarations.forEach(function(decl) {
620 | var x = decl.id.name;
621 | var t = this.table(x, decl.init, decl.loc);
622 | this._globals.bind(x, { mutable: false, type: t }, decl.id.loc);
623 | }, this);
624 | }, this);
625 |
626 | // Check functions.
627 | sections.functions.forEach(this.function, this);
628 |
629 | // Check exports.
630 | var exports = this.exports(sections.exports);
631 |
632 | return new Report(this._globals, exports);
633 | };
634 |
635 | // -----------------------------------------------------------------------------
636 | // statements
637 | // -----------------------------------------------------------------------------
638 |
639 | // ([Statement]) -> void
640 | Vp.statements = function statements(ss) {
641 | ss.forEach(this.statement, this);
642 | };
643 |
644 | // (Statement) -> void
645 | Vp.statement = function statement(s) {
646 | switch (s.type) {
647 | case 'BlockStatement':
648 | return this.statements(s.body);
649 |
650 | case 'ExpressionStatement':
651 | return (s.expression.type === 'CallExpression')
652 | ? this.call(s.expression, ty.Void)
653 | : this.expression(s.expression);
654 |
655 | case 'IfStatement':
656 | return this.ifStatement(s.test, s.consequent, s.alternate);
657 |
658 | case 'ReturnStatement':
659 | return this.returnStatement(s.argument, s.loc);
660 |
661 | case 'WhileStatement':
662 | return this.whileStatement(s.test, s.body);
663 |
664 | case 'DoWhileStatement':
665 | return this.doWhileStatement(s.body, s.test);
666 |
667 | case 'ForStatement':
668 | return this.forStatement(s.init, s.test, s.update, s.body, s.loc);
669 |
670 | case 'BreakStatement':
671 | case 'ContinueStatement':
672 | case "EmptyStatement":
673 | return;
674 |
675 | case 'LabeledStatement':
676 | return this.statement(s.body);
677 |
678 | case 'SwitchStatement':
679 | return this.switchStatement(s.discriminant, s.cases);
680 |
681 | default:
682 | this.fail("illegal " + s.type + " node", s.loc);
683 | }
684 | };
685 |
686 | // (Type, Type, string, Loc) -> void
687 | Vp.checkSubtype = function checkSubtype(actual, expected, msg, loc) {
688 | if (!(actual instanceof ty.ValueType) || !actual.subtype(expected))
689 | this.fail("expected " + expected + " in " + msg + ", got " + actual, loc);
690 | };
691 |
692 | Vp.checkSameType = function checkSameType(actual, expected, msg, loc) {
693 | if (!(actual instanceof ty.ValueType) || !actual.equals(expected))
694 | this.fail("expected " + expected + " in " + msg + ", got " + actual, loc);
695 | };
696 |
697 | // ([Type], Type, string, [Loc], Loc) -> Type
698 | Vp.checkArguments = function checkArguments(ts, expected, msg, locs, loc) {
699 | if (expected instanceof ty.Arrow) {
700 | ts.forEach(function(t, i) {
701 | this.checkSubtype(t, expected.params[i], "argument", locs[i]);
702 | }, this);
703 | return expected.result;
704 | } else if (expected instanceof ty.Overloaded) {
705 | var t;
706 | expected.alts.some(function(alt) {
707 | var ss = alt.params;
708 | if (ss.length === ts.length && ss.every(function(s, i) { return ts[i].subtype(s) })) {
709 | t = alt.result;
710 | return true;
711 | }
712 | }, this);
713 | if (!t)
714 | this.fail(msg + ": argument types do not match any overloading", loc);
715 | return t;
716 | } else {
717 | this.fail("expected function type, got " + expected, loc);
718 | }
719 | };
720 |
721 | // (Expression, Statement, Statement | null) -> void
722 | Vp.ifStatement = function ifStatement(test, cons, alt) {
723 | this.checkSubtype(this.expression(test), ty.Int, "if test", test.loc);
724 | this.statement(cons);
725 | if (alt)
726 | this.statement(alt);
727 | };
728 |
729 | // (Expression | null, Loc) -> void
730 | Vp.returnStatement = function returnStatement(arg, loc) {
731 | this.checkSubtype(this.optExpression(arg) || ty.Void, this._result, "return argument", loc);
732 | };
733 |
734 | // (Expression, Statement) -> void
735 | Vp.whileStatement = function whileStatement(test, body, labels) {
736 | this.checkSubtype(this.expression(test), ty.Int, "while loop condition", test.loc);
737 | this.statement(body);
738 | };
739 |
740 | // (Statement, Expression) -> void
741 | Vp.doWhileStatement = function doWhileStatement(body, test) {
742 | this.statement(body);
743 | this.checkSubtype(this.expression(test), ty.Int, "do-while loop condition", test.loc);
744 | };
745 |
746 | // (VariableDeclaration | Expression | null, Expression | null, Expression | null, Statement, Loc) -> void
747 | Vp.forStatement = function forStatement(init, test, update, body, loc) {
748 | if (init.type === 'VariableDeclaration')
749 | this.fail("illegal variable declaration in for-head", init.loc);
750 | this.optExpression(init);
751 | this.checkSubtype(this.optExpression(test) || ty.Int, ty.Int, "for loop condition", loc);
752 | this.optExpression(update);
753 | this.statement(body);
754 | };
755 |
756 | // (Expression, [SwitchCase], labels) -> void
757 | Vp.switchStatement = function switchStatement(disc, cases) {
758 | var s = this.expression(disc);
759 | cases.forEach(function(c) {
760 | this.case(c, s);
761 | }, this);
762 | };
763 |
764 | // (SwitchCase, Type) -> void
765 | Vp.case = function case_(c, s) {
766 | if (c.test)
767 | this.checkSubtype(this.literal(c.test), s, "case clause expression", c.test.loc);
768 | this.statements(c.consequent);
769 | };
770 |
771 | // -----------------------------------------------------------------------------
772 | // expressions
773 | // -----------------------------------------------------------------------------
774 |
775 | // (Expression | null) -> ValueType | null
776 | Vp.optExpression = function optExpression(expr) {
777 | return expr ? this.expression(expr) : null;
778 | };
779 |
780 | // (Expression) -> ValueType
781 | Vp.expression = function expression(e) {
782 | return this.match(e, "expression", function(when) {
783 | when({ type: 'Literal', raw: hasDot }, function() {
784 | return ty.Double;
785 | });
786 |
787 | when({ type: 'Literal', value: match.range(-0x80000000, 0xffffffff) }, function() {
788 | return ty.Fixnum;
789 | });
790 |
791 | when({ type: 'Identifier' }, function() {
792 | return this.lookupValueType(e.name, e.loc);
793 | }, this);
794 |
795 | when({
796 | type: 'AssignmentExpression',
797 | left: match.var('left', { type: match.some('Identifier', 'MemberExpression') }),
798 | right: match.var('right')
799 | }, function(vars) {
800 | var s = this.expression(vars.left);
801 | var t = this.expression(vars.right);
802 | this.checkSubtype(t, s, "assignment", e.loc);
803 | return t;
804 | }, this);
805 |
806 | when({
807 | type: 'MemberExpression',
808 | object: { type: 'Identifier', name: match.var('x'), loc: match.var('loc') },
809 | property: { type: 'Literal', value: match.range(0, 0x100000000), raw: dotless }
810 | }, function(vars) {
811 | var t = this.lookup(vars.x, vars.loc);
812 | if (!(t instanceof ty.View))
813 | this.fail("expected view type, got " + t);
814 | return t.elementType;
815 | }, this);
816 |
817 | when({
818 | type: 'MemberExpression',
819 | object: { type: 'Identifier', name: match.var('x'), loc: match.var('loc') },
820 | property: {
821 | type: 'BinaryExpression',
822 | operator: '>>',
823 | left: match.var('e'),
824 | right: match.var('n', {
825 | type: 'Literal',
826 | value: match.var('shift', match.number),
827 | raw: dotless
828 | })
829 | },
830 | computed: true
831 | }, function(vars) {
832 | var t = this.lookup(vars.x, vars.loc);
833 | if (!(t instanceof ty.View))
834 | this.fail("expected view type, got " + t, vars.loc);
835 | this.checkSubtype(this.expression(vars.e), ty.Intish, "heap address" , vars.e.loc);
836 | var expectedShift = log2(t.bytes);
837 | if (vars.shift !== expectedShift)
838 | this.fail("expected shift of " + expectedShift + " bits for view type " + t + ", got " + vars.shift, vars.n.loc);
839 | return t.elementType;
840 | }, this);
841 |
842 | when({
843 | type: 'MemberExpression',
844 | object: { type: 'Identifier', name: match.var('x'), loc: match.var('loc') },
845 | property: match.var('e'),
846 | computed: true
847 | }, function(vars) {
848 | var t = this.lookup(vars.x, vars.loc);
849 | if (!(t instanceof ty.View))
850 | this.fail("expected view type, got " + t, vars.loc);
851 | if (t.bytes !== 1)
852 | this.fail("expected view type with element size 1, got " + t, vars.loc);
853 | if (t.elementType !== ty.Intish)
854 | this.fail("expected view type with intish elements, got " + t, vars.loc);
855 | this.checkSubtype(this.expression(vars.e), ty.Int, "heap address", vars.e.loc);
856 | return t.Intish;
857 | }, this);
858 |
859 | when({
860 | type: 'ConditionalExpression',
861 | test: match.var('test'),
862 | consequent: match.var('cons'),
863 | alternate: match.var('alt')
864 | }, function(vars) {
865 | this.checkSubtype(this.expression(vars.test), ty.Int, "conditional test", vars.test.loc);
866 | var t1 = this.expression(vars.cons);
867 | var t2 = this.expression(vars.alt);
868 | if (t1 !== t2)
869 | this.fail("type mismatch between conditional branches", e.loc);
870 | if (t1 !== ty.Int && t1 !== ty.Double)
871 | this.fail("expected int or double in conditional branch, got " + t1, vars.cons.loc);
872 | return t1;
873 | }, this);
874 |
875 | when({
876 | type: 'SequenceExpression',
877 | expressions: match.var('es')
878 | }, function(vars) {
879 | var last = vars.es.pop();
880 | vars.es.forEach(function(e) {
881 | if (e.type === 'CallExpression')
882 | this.call(e, ty.Void);
883 | else
884 | this.expression(e);
885 | }, this);
886 | return this.expression(last);
887 | }, this);
888 |
889 | when({
890 | type: 'UnaryExpression',
891 | operator: '~',
892 | argument: {
893 | type: 'UnaryExpression',
894 | operator: '~',
895 | argument: match.var('e')
896 | }
897 | }, function(vars) {
898 | this.checkSubtype(this.expression(vars.e), ty.Double, "double->signed coercion", e.loc);
899 | return ty.Signed;
900 | }, this);
901 |
902 | when({
903 | type: 'UnaryExpression',
904 | operator: '+',
905 | argument: match.var('e', { type: 'CallExpression' })
906 | }, function(vars) {
907 | this.call(vars.e, ty.Double);
908 | return ty.Double;
909 | }, this);
910 |
911 | when({
912 | type: 'UnaryExpression',
913 | operator: match.var('op'),
914 | argument: match.var('arg')
915 | }, function(vars) {
916 | var t = tables.UNOPS.get(vars.op);
917 | if (!t)
918 | this.fail("unknown unary operator " + vars.op, e.loc);
919 | return this.checkArguments([this.expression(vars.arg)], t, "unary expression", [vars.op.loc], e.loc);
920 | }, this);
921 |
922 | when({
923 | type: 'BinaryExpression',
924 | operator: '|',
925 | left: match.var('e', { type: 'CallExpression' }),
926 | right: { type: 'Literal', value: 0, raw: dotless }
927 | }, function(vars) {
928 | this.call(vars.e, ty.Signed);
929 | return ty.Signed;
930 | }, this);
931 |
932 | when({
933 | type: 'BinaryExpression',
934 | operator: match.some('+', '-'),
935 | left: match.var('left'),
936 | right: match.var('right')
937 | }, function(vars) {
938 | var operands = flattenAdditive(vars.left, vars.right);
939 | var n = operands.length;
940 | var t = this.expression(operands[0]);
941 | if (t.subtype(ty.Double)) {
942 | for (var i = 1; i < n; i++) {
943 | var operand = operands[i];
944 | this.checkSubtype(this.expression(operand), ty.Double, "additive operand", operand.loc);
945 | }
946 | return ty.Double;
947 | } else if (t.subtype(ty.Int)) {
948 | if (n > 0x100000)
949 | this.fail("too many additive operations without coercion: " + n + " > maximum 2^20", e.loc);
950 | for (var i = 1; i < n; i++) {
951 | var operand = operands[i];
952 | this.checkSubtype(this.expression(operand), ty.Int, "additive operand", operand.loc);
953 | }
954 | return ty.Intish;
955 | }
956 | this.fail("expected type int or double, got " + t, operands[0].loc);
957 | }, this);
958 |
959 | when({
960 | type: 'BinaryExpression',
961 | operator: match.var('op'),
962 | left: match.var('left'),
963 | right: match.var('right')
964 | }, function(vars) {
965 | var t = tables.BINOPS.get(vars.op);
966 | if (!t)
967 | this.fail("unknown binary operator " + vars.op, e.loc);
968 | return this.checkArguments([this.expression(vars.left), this.expression(vars.right)],
969 | t, "operator " + vars.op,
970 | [vars.left.loc, vars.right.loc],
971 | e.loc);
972 | }, this);
973 | });
974 | };
975 |
976 | // -----------------------------------------------------------------------------
977 | // call expressions
978 | // -----------------------------------------------------------------------------
979 |
980 | // (CallExpression, ValueType) -> void
981 | Vp.call = function call(e, t) {
982 | return this.match(e, "function call", function(when) {
983 | when({
984 | type: 'CallExpression',
985 | callee: { type: 'Identifier', name: match.var('f'), loc: match.var('loc') },
986 | arguments: match.var('args')
987 | }, function(vars) {
988 | var formalReturnType = this.checkArguments(vars.args.map(this.expression, this),
989 | this.lookup(vars.f, vars.loc),
990 | "function call",
991 | vars.args.map(function(arg) { return arg.loc; }),
992 | e.loc);
993 | this.checkSameType(formalReturnType, t, "function call", e.loc);
994 | }, this);
995 |
996 | when({
997 | type: 'CallExpression',
998 | callee: {
999 | type: 'MemberExpression',
1000 | object: { type: 'Identifier', name: match.var('f'), loc: match.var('loc') },
1001 | property: {
1002 | type: 'BinaryExpression',
1003 | operator: '&',
1004 | left: match.var('index'),
1005 | right: {
1006 | type: 'Literal',
1007 | value: match.var('n', match.number),
1008 | raw: dotless,
1009 | loc: match.var('nloc')
1010 | }
1011 | },
1012 | computed: true
1013 | },
1014 | arguments: match.var('args')
1015 | }, function(vars) {
1016 | var t = this.lookup(vars.f, vars.loc);
1017 | if (!(t instanceof ty.Table))
1018 | this.fail("expected function table, got " + vars.f, vars.loc);
1019 | this.checkSubtype(this.expression(vars.index), ty.Intish, "function pointer", vars.index.loc);
1020 | if (t.length !== vars.n + 1)
1021 | this.fail("function table mask should be " + (t.length - 1) + ", got " + vars.n, vars.nloc);
1022 | var formalReturnType = this.checkArguments(vars.args.map(this.expression, this),
1023 | t.type, "function pointer call",
1024 | vars.args.map(function(arg) { return arg.loc; }),
1025 | e.loc);
1026 | this.checkSameType(formalReturnType, t, "function call", e.loc);
1027 | }, this);
1028 | });
1029 | };
1030 |
1031 | // -----------------------------------------------------------------------------
1032 | // front end
1033 | // -----------------------------------------------------------------------------
1034 |
1035 | // (string) -> Report
1036 | module.exports = function validate(src) {
1037 | return (new Validator).validate(src);
1038 | };
1039 |
--------------------------------------------------------------------------------
/html/subtypes.graffle:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ActiveLayerIndex
6 | 0
7 | ApplicationVersion
8 |
9 | com.omnigroup.OmniGraffle
10 | 139.18.0.187838
11 |
12 | AutoAdjust
13 |
14 | BackgroundGraphic
15 |
16 | Bounds
17 | {{0, 0}, {1152, 733}}
18 | Class
19 | SolidGraphic
20 | ID
21 | 2
22 | Style
23 |
24 | shadow
25 |
26 | Draws
27 | NO
28 |
29 | stroke
30 |
31 | Draws
32 | NO
33 |
34 |
35 |
36 | BaseZoom
37 | 0
38 | CanvasOrigin
39 | {0, 0}
40 | ColumnAlign
41 | 1
42 | ColumnSpacing
43 | 36
44 | CreationDate
45 | 2013-06-07 22:05:55 +0000
46 | Creator
47 | Michael Bebenita
48 | DisplayScale
49 | 1 0/72 in = 1.0000 in
50 | GraphDocumentVersion
51 | 8
52 | GraphicsList
53 |
54 |
55 | Class
56 | LineGraphic
57 | ID
58 | 32
59 | Points
60 |
61 | {140.2999963760376, 271.59995756244513}
62 | {140.2999963760376, 223.19999408721924}
63 |
64 | Style
65 |
66 | stroke
67 |
68 | Color
69 |
70 | b
71 | 0.398864
72 | g
73 | 0.398857
74 | r
75 | 0.398869
76 |
77 | HeadArrow
78 | FilledArrow
79 | Legacy
80 |
81 | LineType
82 | 1
83 | TailArrow
84 | 0
85 | Width
86 | 3
87 |
88 |
89 |
90 |
91 | Bounds
92 | {{79.199997901916504, 180.00000508721922}, {122.40000000000001, 43.199989000000002}}
93 | Class
94 | ShapedGraphic
95 | ID
96 | 30
97 | Shape
98 | Rectangle
99 | Style
100 |
101 | fill
102 |
103 | Color
104 |
105 | b
106 | 0.901961
107 | g
108 | 0.901961
109 | r
110 | 0.901961
111 |
112 | FillType
113 | 2
114 | GradientAngle
115 | 90
116 | GradientColor
117 |
118 | b
119 | 0.6
120 | g
121 | 0.6
122 | r
123 | 0.6
124 |
125 |
126 | shadow
127 |
128 | Draws
129 | NO
130 |
131 | stroke
132 |
133 | Color
134 |
135 | b
136 | 0.4
137 | g
138 | 0.4
139 | r
140 | 0.4
141 |
142 | CornerRadius
143 | 5
144 | Width
145 | 2
146 |
147 |
148 | Text
149 |
150 | Text
151 | {\rtf1\ansi\ansicpg1252\cocoartf1265\cocoasubrtf200
152 | \cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Calibri;}
153 | {\colortbl;\red255\green255\blue255;}
154 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
155 |
156 | \f0\b\fs28 \cf0 floatish}
157 |
158 |
159 |
160 | Class
161 | LineGraphic
162 | Head
163 |
164 | ID
165 | 27
166 |
167 | ID
168 | 29
169 | Points
170 |
171 | {140.21845543143303, 366.19997937971277}
172 | {139.82966014768195, 317.79966534952058}
173 |
174 | Style
175 |
176 | stroke
177 |
178 | Color
179 |
180 | b
181 | 0.398864
182 | g
183 | 0.398857
184 | r
185 | 0.398869
186 |
187 | HeadArrow
188 | FilledArrow
189 | Legacy
190 |
191 | LineType
192 | 1
193 | TailArrow
194 | 0
195 | Width
196 | 3
197 |
198 |
199 | Tail
200 |
201 | ID
202 | 28
203 |
204 |
205 |
206 | Bounds
207 | {{79.19999885559082, 367.19994713897705}, {122.40000000000001, 43.199989000000002}}
208 | Class
209 | ShapedGraphic
210 | FontInfo
211 |
212 | Color
213 |
214 | b
215 | 0.298039
216 | g
217 | 0.298039
218 | r
219 | 0.298039
220 |
221 |
222 | ID
223 | 28
224 | Shape
225 | Rectangle
226 | Style
227 |
228 | fill
229 |
230 | Color
231 |
232 | b
233 | 0.901961
234 | g
235 | 0.901961
236 | r
237 | 0.901961
238 |
239 | FillType
240 | 2
241 | GradientAngle
242 | 90
243 | GradientColor
244 |
245 | b
246 | 0.6
247 | g
248 | 0.6
249 | r
250 | 0.6
251 |
252 |
253 | shadow
254 |
255 | Draws
256 | NO
257 |
258 | stroke
259 |
260 | Color
261 |
262 | b
263 | 0.4
264 | g
265 | 0.4
266 | r
267 | 0.4
268 |
269 | CornerRadius
270 | 5
271 | Width
272 | 2
273 |
274 |
275 | Text
276 |
277 | Text
278 | {\rtf1\ansi\ansicpg1252\cocoartf1265\cocoasubrtf200
279 | \cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Calibri;}
280 | {\colortbl;\red255\green255\blue255;\red0\green0\blue0;}
281 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
282 |
283 | \f0\b\fs28 \cf2 float}
284 |
285 |
286 |
287 | Bounds
288 | {{79.19999885559082, 273.59999465942383}, {122.40000000000001, 43.199989000000002}}
289 | Class
290 | ShapedGraphic
291 | ID
292 | 27
293 | Shape
294 | Rectangle
295 | Style
296 |
297 | fill
298 |
299 | Color
300 |
301 | b
302 | 0.901961
303 | g
304 | 0.901961
305 | r
306 | 0.901961
307 |
308 | FillType
309 | 2
310 | GradientAngle
311 | 90
312 | GradientColor
313 |
314 | b
315 | 0.6
316 | g
317 | 0.6
318 | r
319 | 0.6
320 |
321 |
322 | shadow
323 |
324 | Draws
325 | NO
326 |
327 | stroke
328 |
329 | Color
330 |
331 | b
332 | 0.4
333 | g
334 | 0.4
335 | r
336 | 0.4
337 |
338 | CornerRadius
339 | 5
340 | Width
341 | 2
342 |
343 |
344 | Text
345 |
346 | Text
347 | {\rtf1\ansi\ansicpg1252\cocoartf1265\cocoasubrtf200
348 | \cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Calibri;}
349 | {\colortbl;\red255\green255\blue255;}
350 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
351 |
352 | \f0\b\fs28 \cf0 float\cf0 ?}
353 |
354 |
355 |
356 | Class
357 | LineGraphic
358 | Head
359 |
360 | ID
361 | 8
362 |
363 | ID
364 | 26
365 | Points
366 |
367 | {578.18522311685604, 273.09125784684301}
368 | {494.61476306844685, 223.70871543111116}
369 |
370 | Style
371 |
372 | stroke
373 |
374 | Color
375 |
376 | b
377 | 0.398864
378 | g
379 | 0.398857
380 | r
381 | 0.398869
382 |
383 | HeadArrow
384 | FilledArrow
385 | Legacy
386 |
387 | LineType
388 | 1
389 | TailArrow
390 | 0
391 | Width
392 | 3
393 |
394 |
395 | Tail
396 |
397 | ID
398 | 11
399 |
400 |
401 |
402 | Class
403 | LineGraphic
404 | Head
405 |
406 | ID
407 | 10
408 |
409 | ID
410 | 25
411 | Points
412 |
413 | {517.47714205273303, 460.0366604156489}
414 | {476.12283413256966, 411.16332286230505}
415 |
416 | Style
417 |
418 | stroke
419 |
420 | Color
421 |
422 | b
423 | 0.398864
424 | g
425 | 0.398857
426 | r
427 | 0.398869
428 |
429 | HeadArrow
430 | FilledArrow
431 | Legacy
432 |
433 | LineType
434 | 1
435 | TailArrow
436 | 0
437 | Width
438 | 3
439 |
440 |
441 | Tail
442 |
443 | ID
444 | 15
445 |
446 |
447 |
448 | Class
449 | LineGraphic
450 | Head
451 |
452 | ID
453 | 12
454 |
455 | ID
456 | 24
457 | Points
458 |
459 | {555.32281413256976, 460.0366604156489}
460 | {596.67712205273301, 411.16332286230511}
461 |
462 | Style
463 |
464 | stroke
465 |
466 | Color
467 |
468 | b
469 | 0.398864
470 | g
471 | 0.398857
472 | r
473 | 0.398869
474 |
475 | HeadArrow
476 | FilledArrow
477 | Legacy
478 |
479 | LineType
480 | 1
481 | TailArrow
482 | 0
483 | Width
484 | 3
485 |
486 |
487 | Tail
488 |
489 | ID
490 | 15
491 |
492 |
493 |
494 | Class
495 | LineGraphic
496 | Head
497 |
498 | ID
499 | 11
500 |
501 | ID
502 | 22
503 | Points
504 |
505 | {615.59997809265133, 366.19994713914173}
506 | {615.59997809265133, 317.79997613881233}
507 |
508 | Style
509 |
510 | stroke
511 |
512 | Color
513 |
514 | b
515 | 0.398864
516 | g
517 | 0.398857
518 | r
519 | 0.398869
520 |
521 | HeadArrow
522 | FilledArrow
523 | Legacy
524 |
525 | LineType
526 | 1
527 | TailArrow
528 | 0
529 | Width
530 | 3
531 |
532 |
533 | Tail
534 |
535 | ID
536 | 12
537 |
538 |
539 |
540 | Class
541 | LineGraphic
542 | Head
543 |
544 | ID
545 | 11
546 |
547 | ID
548 | 21
549 | Points
550 |
551 | {494.61477487940653, 366.69121795377214}
552 | {578.18521130589625, 317.30870532418186}
553 |
554 | Style
555 |
556 | stroke
557 |
558 | Color
559 |
560 | b
561 | 0.398864
562 | g
563 | 0.398857
564 | r
565 | 0.398869
566 |
567 | HeadArrow
568 | FilledArrow
569 | Legacy
570 |
571 | LineType
572 | 1
573 | TailArrow
574 | 0
575 | Width
576 | 3
577 |
578 |
579 | Tail
580 |
581 | ID
582 | 10
583 |
584 |
585 |
586 | Class
587 | LineGraphic
588 | Head
589 |
590 | ID
591 | 9
592 |
593 | ID
594 | 20
595 | Points
596 |
597 | {457.20000809265139, 366.19994713914173}
598 | {457.20000809265139, 317.79997613881233}
599 |
600 | Style
601 |
602 | stroke
603 |
604 | Color
605 |
606 | b
607 | 0.398864
608 | g
609 | 0.398857
610 | r
611 | 0.398869
612 |
613 | HeadArrow
614 | FilledArrow
615 | Legacy
616 |
617 | LineType
618 | 1
619 | TailArrow
620 | 0
621 | Width
622 | 3
623 |
624 |
625 | Tail
626 |
627 | ID
628 | 10
629 |
630 |
631 |
632 | Class
633 | LineGraphic
634 | Head
635 |
636 | ID
637 | 9
638 |
639 | ID
640 | 19
641 | Points
642 |
643 | {336.21477455286674, 366.69121799294936}
644 | {419.78521819920854, 317.30870528500463}
645 |
646 | Style
647 |
648 | stroke
649 |
650 | Color
651 |
652 | b
653 | 0.398864
654 | g
655 | 0.398857
656 | r
657 | 0.398869
658 |
659 | HeadArrow
660 | FilledArrow
661 | Legacy
662 |
663 | LineType
664 | 1
665 | TailArrow
666 | 0
667 | Width
668 | 3
669 |
670 |
671 | Tail
672 |
673 | ID
674 | 6
675 |
676 |
677 |
678 | Class
679 | LineGraphic
680 | Head
681 |
682 | ID
683 | 5
684 |
685 | ID
686 | 16
687 | Points
688 |
689 | {298.79999165942382, 366.19994713698696}
690 | {298.79999165942382, 317.79998366176108}
691 |
692 | Style
693 |
694 | stroke
695 |
696 | Color
697 |
698 | b
699 | 0.398864
700 | g
701 | 0.398857
702 | r
703 | 0.398869
704 |
705 | HeadArrow
706 | FilledArrow
707 | Legacy
708 |
709 | LineType
710 | 1
711 | TailArrow
712 | 0
713 | Width
714 | 3
715 |
716 |
717 | Tail
718 |
719 | ID
720 | 6
721 |
722 |
723 |
724 | Bounds
725 | {{475.19997809265135, 460.80004713897705}, {122.40000000000001, 43.199989000000002}}
726 | Class
727 | ShapedGraphic
728 | FontInfo
729 |
730 | Color
731 |
732 | b
733 | 0.298039
734 | g
735 | 0.298039
736 | r
737 | 0.298039
738 |
739 |
740 | ID
741 | 15
742 | Shape
743 | Rectangle
744 | Style
745 |
746 | fill
747 |
748 | Color
749 |
750 | b
751 | 0.901961
752 | g
753 | 0.901961
754 | r
755 | 0.901961
756 |
757 |
758 | shadow
759 |
760 | Draws
761 | NO
762 |
763 | stroke
764 |
765 | Color
766 |
767 | b
768 | 0.4
769 | g
770 | 0.4
771 | r
772 | 0.4
773 |
774 | CornerRadius
775 | 5
776 | Width
777 | 2
778 |
779 |
780 | Text
781 |
782 | Text
783 | {\rtf1\ansi\ansicpg1252\cocoartf1265\cocoasubrtf200
784 | \cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Calibri;}
785 | {\colortbl;\red255\green255\blue255;\red76\green76\blue76;}
786 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
787 |
788 | \f0\b\fs28 \cf2 fixnum}
789 |
790 |
791 |
792 | Bounds
793 | {{712.79998809265135, 273.59998713897704}, {122.40000000000001, 43.199989000000002}}
794 | Class
795 | ShapedGraphic
796 | ID
797 | 13
798 | Shape
799 | Rectangle
800 | Style
801 |
802 | fill
803 |
804 | Color
805 |
806 | b
807 | 0.901961
808 | g
809 | 0.901961
810 | r
811 | 0.901961
812 |
813 | FillType
814 | 2
815 | GradientAngle
816 | 90
817 | GradientColor
818 |
819 | b
820 | 0.6
821 | g
822 | 0.6
823 | r
824 | 0.6
825 |
826 |
827 | shadow
828 |
829 | Draws
830 | NO
831 |
832 | stroke
833 |
834 | Color
835 |
836 | b
837 | 0.4
838 | g
839 | 0.4
840 | r
841 | 0.4
842 |
843 | CornerRadius
844 | 5
845 | Width
846 | 2
847 |
848 |
849 | Text
850 |
851 | Text
852 | {\rtf1\ansi\ansicpg1252\cocoartf1265\cocoasubrtf200
853 | \cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Calibri;}
854 | {\colortbl;\red255\green255\blue255;}
855 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
856 |
857 | \f0\b\fs28 \cf0 void}
858 |
859 |
860 |
861 | Bounds
862 | {{554.39995809265133, 367.19994713897705}, {122.40000000000001, 43.199989000000002}}
863 | Class
864 | ShapedGraphic
865 | ID
866 | 12
867 | Shape
868 | Rectangle
869 | Style
870 |
871 | fill
872 |
873 | Color
874 |
875 | b
876 | 0.901961
877 | g
878 | 0.901961
879 | r
880 | 0.901961
881 |
882 | FillType
883 | 2
884 | GradientAngle
885 | 90
886 | GradientColor
887 |
888 | b
889 | 0.6
890 | g
891 | 0.6
892 | r
893 | 0.6
894 |
895 |
896 | shadow
897 |
898 | Draws
899 | NO
900 |
901 | stroke
902 |
903 | Color
904 |
905 | b
906 | 0.4
907 | g
908 | 0.4
909 | r
910 | 0.4
911 |
912 | CornerRadius
913 | 5
914 | Width
915 | 2
916 |
917 |
918 | Text
919 |
920 | Text
921 | {\rtf1\ansi\ansicpg1252\cocoartf1265\cocoasubrtf200
922 | \cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Calibri;}
923 | {\colortbl;\red255\green255\blue255;}
924 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
925 |
926 | \f0\b\fs28 \cf0 unsigned}
927 |
928 |
929 |
930 | Bounds
931 | {{554.39998809265137, 273.59998713897704}, {122.40000000000001, 43.199989000000002}}
932 | Class
933 | ShapedGraphic
934 | ID
935 | 11
936 | Shape
937 | Rectangle
938 | Style
939 |
940 | fill
941 |
942 | Color
943 |
944 | b
945 | 0.901961
946 | g
947 | 0.901961
948 | r
949 | 0.901961
950 |
951 | FillType
952 | 2
953 | GradientAngle
954 | 90
955 | GradientColor
956 |
957 | b
958 | 0.6
959 | g
960 | 0.6
961 | r
962 | 0.6
963 |
964 |
965 | shadow
966 |
967 | Draws
968 | NO
969 |
970 | stroke
971 |
972 | Color
973 |
974 | b
975 | 0.4
976 | g
977 | 0.4
978 | r
979 | 0.4
980 |
981 | CornerRadius
982 | 5
983 | Width
984 | 2
985 |
986 |
987 | Text
988 |
989 | Text
990 | {\rtf1\ansi\ansicpg1252\cocoartf1265\cocoasubrtf200
991 | \cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Calibri;}
992 | {\colortbl;\red255\green255\blue255;}
993 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
994 |
995 | \f0\b\fs28 \cf0 int}
996 |
997 |
998 |
999 | Bounds
1000 | {{395.99999809265137, 367.19994713897705}, {122.40000000000001, 43.199989000000002}}
1001 | Class
1002 | ShapedGraphic
1003 | FontInfo
1004 |
1005 | Color
1006 |
1007 | b
1008 | 0.298039
1009 | g
1010 | 0.298039
1011 | r
1012 | 0.298039
1013 |
1014 |
1015 | ID
1016 | 10
1017 | Shape
1018 | Rectangle
1019 | Style
1020 |
1021 | fill
1022 |
1023 | Color
1024 |
1025 | b
1026 | 0.901961
1027 | g
1028 | 0.901961
1029 | r
1030 | 0.901961
1031 |
1032 |
1033 | shadow
1034 |
1035 | Draws
1036 | NO
1037 |
1038 | stroke
1039 |
1040 | Color
1041 |
1042 | b
1043 | 0.4
1044 | g
1045 | 0.4
1046 | r
1047 | 0.4
1048 |
1049 | CornerRadius
1050 | 5
1051 | Width
1052 | 2
1053 |
1054 |
1055 | Text
1056 |
1057 | Text
1058 | {\rtf1\ansi\ansicpg1252\cocoartf1265\cocoasubrtf200
1059 | \cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Calibri;}
1060 | {\colortbl;\red255\green255\blue255;\red76\green76\blue76;}
1061 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
1062 |
1063 | \f0\b\fs28 \cf2 signed}
1064 |
1065 |
1066 |
1067 | Bounds
1068 | {{395.99999809265137, 273.59998713897704}, {122.40000000000001, 43.199989000000002}}
1069 | Class
1070 | ShapedGraphic
1071 | FontInfo
1072 |
1073 | Color
1074 |
1075 | b
1076 | 0.298039
1077 | g
1078 | 0.298039
1079 | r
1080 | 0.298039
1081 |
1082 |
1083 | ID
1084 | 9
1085 | Shape
1086 | Rectangle
1087 | Style
1088 |
1089 | fill
1090 |
1091 | Color
1092 |
1093 | b
1094 | 0.901961
1095 | g
1096 | 0.901961
1097 | r
1098 | 0.901961
1099 |
1100 |
1101 | shadow
1102 |
1103 | Draws
1104 | NO
1105 |
1106 | stroke
1107 |
1108 | Color
1109 |
1110 | b
1111 | 0.4
1112 | g
1113 | 0.4
1114 | r
1115 | 0.4
1116 |
1117 | CornerRadius
1118 | 5
1119 | Width
1120 | 2
1121 |
1122 |
1123 | Text
1124 |
1125 | Text
1126 | {\rtf1\ansi\ansicpg1252\cocoartf1265\cocoasubrtf200
1127 | \cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Calibri;}
1128 | {\colortbl;\red255\green255\blue255;\red76\green76\blue76;}
1129 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
1130 |
1131 | \f0\b\fs28 \cf2 extern}
1132 |
1133 |
1134 |
1135 | Bounds
1136 | {{395.99999809265137, 179.99999713897705}, {122.40000000000001, 43.199989000000002}}
1137 | Class
1138 | ShapedGraphic
1139 | ID
1140 | 8
1141 | Shape
1142 | Rectangle
1143 | Style
1144 |
1145 | fill
1146 |
1147 | Color
1148 |
1149 | b
1150 | 0.901961
1151 | g
1152 | 0.901961
1153 | r
1154 | 0.901961
1155 |
1156 | FillType
1157 | 2
1158 | GradientAngle
1159 | 90
1160 | GradientColor
1161 |
1162 | b
1163 | 0.6
1164 | g
1165 | 0.6
1166 | r
1167 | 0.6
1168 |
1169 |
1170 | shadow
1171 |
1172 | Draws
1173 | NO
1174 |
1175 | stroke
1176 |
1177 | Color
1178 |
1179 | b
1180 | 0.4
1181 | g
1182 | 0.4
1183 | r
1184 | 0.4
1185 |
1186 | CornerRadius
1187 | 5
1188 | Width
1189 | 2
1190 |
1191 |
1192 | Text
1193 |
1194 | Text
1195 | {\rtf1\ansi\ansicpg1252\cocoartf1265\cocoasubrtf200
1196 | \cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Calibri;}
1197 | {\colortbl;\red255\green255\blue255;}
1198 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
1199 |
1200 | \f0\b\fs28 \cf0 intish}
1201 |
1202 |
1203 |
1204 | Bounds
1205 | {{237.59999465942383, 367.19994713897705}, {122.40000000000001, 43.199989000000002}}
1206 | Class
1207 | ShapedGraphic
1208 | FontInfo
1209 |
1210 | Color
1211 |
1212 | b
1213 | 0.298039
1214 | g
1215 | 0.298039
1216 | r
1217 | 0.298039
1218 |
1219 |
1220 | ID
1221 | 6
1222 | Shape
1223 | Rectangle
1224 | Style
1225 |
1226 | fill
1227 |
1228 | Color
1229 |
1230 | b
1231 | 0.901961
1232 | g
1233 | 0.901961
1234 | r
1235 | 0.901961
1236 |
1237 |
1238 | shadow
1239 |
1240 | Draws
1241 | NO
1242 |
1243 | stroke
1244 |
1245 | Color
1246 |
1247 | b
1248 | 0.4
1249 | g
1250 | 0.4
1251 | r
1252 | 0.4
1253 |
1254 | CornerRadius
1255 | 5
1256 | Width
1257 | 2
1258 |
1259 |
1260 | Text
1261 |
1262 | Text
1263 | {\rtf1\ansi\ansicpg1252\cocoartf1265\cocoasubrtf200
1264 | \cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Calibri;}
1265 | {\colortbl;\red255\green255\blue255;\red76\green76\blue76;}
1266 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
1267 |
1268 | \f0\b\fs28 \cf2 double}
1269 |
1270 |
1271 |
1272 | Bounds
1273 | {{237.59999465942383, 273.59999465942383}, {122.40000000000001, 43.199989000000002}}
1274 | Class
1275 | ShapedGraphic
1276 | ID
1277 | 5
1278 | Shape
1279 | Rectangle
1280 | Style
1281 |
1282 | fill
1283 |
1284 | Color
1285 |
1286 | b
1287 | 0.901961
1288 | g
1289 | 0.901961
1290 | r
1291 | 0.901961
1292 |
1293 | FillType
1294 | 2
1295 | GradientAngle
1296 | 90
1297 | GradientColor
1298 |
1299 | b
1300 | 0.6
1301 | g
1302 | 0.6
1303 | r
1304 | 0.6
1305 |
1306 |
1307 | shadow
1308 |
1309 | Draws
1310 | NO
1311 |
1312 | stroke
1313 |
1314 | Color
1315 |
1316 | b
1317 | 0.4
1318 | g
1319 | 0.4
1320 | r
1321 | 0.4
1322 |
1323 | CornerRadius
1324 | 5
1325 | Width
1326 | 2
1327 |
1328 |
1329 | Text
1330 |
1331 | Text
1332 | {\rtf1\ansi\ansicpg1252\cocoartf1265\cocoasubrtf200
1333 | \cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Calibri;}
1334 | {\colortbl;\red255\green255\blue255;}
1335 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
1336 |
1337 | \f0\b\fs28 \cf0 double?}
1338 |
1339 |
1340 |
1341 | GridInfo
1342 |
1343 | GridSpacing
1344 | 7.1999998092651367
1345 | MajorGridSpacing
1346 | 10
1347 | ShowsGrid
1348 | YES
1349 | SnapsToGrid
1350 | YES
1351 |
1352 | GuidesLocked
1353 | NO
1354 | GuidesVisible
1355 | YES
1356 | HPages
1357 | 2
1358 | ImageCounter
1359 | 1
1360 | KeepToScale
1361 |
1362 | Layers
1363 |
1364 |
1365 | Lock
1366 | NO
1367 | Name
1368 | Layer 1
1369 | Print
1370 | YES
1371 | View
1372 | YES
1373 |
1374 |
1375 | LayoutInfo
1376 |
1377 | Animate
1378 | NO
1379 | circoMinDist
1380 | 18
1381 | circoSeparation
1382 | 0.0
1383 | layoutEngine
1384 | dot
1385 | neatoSeparation
1386 | 0.0
1387 | twopiSeparation
1388 | 0.0
1389 |
1390 | LinksVisible
1391 | NO
1392 | MagnetsVisible
1393 | NO
1394 | MasterSheets
1395 |
1396 | ModificationDate
1397 | 2014-06-30 23:06:41 +0000
1398 | Modifier
1399 | David Herman
1400 | NotesVisible
1401 | NO
1402 | Orientation
1403 | 2
1404 | OriginVisible
1405 | NO
1406 | PageBreaks
1407 | YES
1408 | PrintInfo
1409 |
1410 | NSBottomMargin
1411 |
1412 | float
1413 | 41
1414 |
1415 | NSHorizonalPagination
1416 |
1417 | int
1418 | 0
1419 |
1420 | NSLeftMargin
1421 |
1422 | float
1423 | 18
1424 |
1425 | NSPaperSize
1426 |
1427 | size
1428 | {612, 792}
1429 |
1430 | NSPrintReverseOrientation
1431 |
1432 | int
1433 | 0
1434 |
1435 | NSRightMargin
1436 |
1437 | float
1438 | 18
1439 |
1440 | NSTopMargin
1441 |
1442 | float
1443 | 18
1444 |
1445 |
1446 | PrintOnePage
1447 |
1448 | ReadOnly
1449 | NO
1450 | RowAlign
1451 | 1
1452 | RowSpacing
1453 | 36
1454 | SheetTitle
1455 | Canvas 1
1456 | SmartAlignmentGuidesActive
1457 | YES
1458 | SmartDistanceGuidesActive
1459 | YES
1460 | UniqueID
1461 | 1
1462 | UseEntirePage
1463 |
1464 | VPages
1465 | 1
1466 | WindowInfo
1467 |
1468 | CurrentSheet
1469 | 0
1470 | ExpandedCanvases
1471 |
1472 |
1473 | name
1474 | Canvas 1
1475 |
1476 |
1477 | Frame
1478 | {{40, 4}, {1175, 742}}
1479 | ListView
1480 |
1481 | OutlineWidth
1482 | 142
1483 | RightSidebar
1484 |
1485 | ShowRuler
1486 |
1487 | Sidebar
1488 |
1489 | SidebarWidth
1490 | 120
1491 | VisibleRegion
1492 | {{0, 0}, {1040, 603}}
1493 | Zoom
1494 | 1
1495 | ZoomValues
1496 |
1497 |
1498 | Canvas 1
1499 | 1
1500 | 2
1501 |
1502 |
1503 |
1504 |
1505 |
1506 |
--------------------------------------------------------------------------------
/historic/def.tex:
--------------------------------------------------------------------------------
1 | \documentclass{article}
2 |
3 | \usepackage{mathpartir}
4 | \usepackage{amssymb}
5 | \usepackage{graphicx}
6 | \RequirePackage{algorithm}
7 | \RequirePackage[noend]{algpseudocode}
8 |
9 | \newcommand{\mod}{\mathrel{\mathrm{mod}}}
10 | \newcommand{\imm}{\mathtt{imm}}
11 | \newcommand{\mut}{\mathtt{mut}}
12 | \newcommand{\funcall}[2]{{#1}\mathjs{(}{#2}\mathjs{)}}
13 | \newcommand{\paren}[1]{\mathjs{(}{#1}\mathjs{)}}
14 | \newcommand{\dom}{\mathit{dom}}
15 | \newcommand{\funtype}{\mathit{fun}\mbox{-}\mathit{type}}
16 | \newcommand{\vartype}{\mathit{var}\mbox{-}\mathit{type}}
17 | \newcommand{\rettype}{\mathit{return}\mbox{-}\mathit{type}}
18 | \newcommand{\imptype}{\mathit{import}\mbox{-}\mathit{type}}
19 | \newcommand{\stdtype}{\mathit{std}\mbox{-}\mathit{type}}
20 | \newcommand{\funty}[2]{({#1}) \rightarrow {#2}}
21 | \newcommand{\seq}[1]{\overline{{#1}}}
22 | \newcommand{\mathjs}[1]{\mbox{\texttt{{#1}}}}
23 | \newcommand{\mathjssm}[1]{\mbox{\texttt{\scriptsize {#1}}}}
24 | \newcommand{\return}[1]{\mathjs{return }{#1}\mathjs{;}}
25 | \newcommand{\fun}[3]{\mathjs{function }{#1}\mathjs{(}{#2}\mathjs{) \char123{} }{#3}\mathjs{ \char125{}}}
26 | \newcommand{\ternary}[3]{{#1}\,\mathjs{?}\,{#2}\,\mathjs{:}{#3}}
27 | \newcommand{\afun}[2]{\mathjs{function}\mathjs{(}{#1}\mathjs{) \char123{} }{#2}\mathjs{ \char125{}}}
28 | \newcommand{\var}[1]{\mathjs{var }{#1}\mathjs{;}}
29 | \newcommand{\rel}[1]{\scriptsize [\textsc{#1}]}
30 | \newcommand\defeq{\stackrel{\mbox{\tiny def}}{=}}
31 | \newcommand{\while}[2]{\mathjs{while (}{#1}\mathjs{) }{#2}}
32 | \newcommand{\dowhile}[2]{\mathjs{do }{#1}\mathjs{ while (}{#2}\mathjs{);}}
33 | \newcommand{\for}[4]{\mathjs{for (}{#1}\mathjs{; }{#2}\mathjs{; }{#3}\mathjs{) }{#4}}
34 | \newcommand{\switch}[2]{\mathjs{switch (}{#1}\mathjs{) \char123{} }{#2}\mathjs{ \char125{}}}
35 | \newcommand{\switchdef}[3]{\mathjs{switch (}{#1}\mathjs{) \char123{} }{#2}\mathjs{ default:}\,{#3}\mathjs{ \char125{}}}
36 | \newcommand{\brk}{\mathjs{break;}}
37 | \newcommand{\brkl}[1]{\mathjs{break }{#1}\mathjs{;}}
38 | \newcommand{\cont}{\mathjs{continue;}}
39 | \newcommand{\contl}[1]{\mathjs{continue }{#1}\mathjs{;}}
40 | \newcommand{\lab}[2]{{#1}\mathjs{:}\,{#2}}
41 | \newcommand{\ifone}[2]{\mathjs{if (}{#1}\mathjs{) }{#2}}
42 | \newcommand{\iftwo}[3]{\mathjs{if (}{#1}\mathjs{) }{#2}\mathjs{ else }{#3}}
43 | \newcommand{\block}[1]{\mathjs{\char123{} }{#1}\mathjs{ \char125{}}}
44 | \newcommand{\ok}{\mathrm{\mathbf{ok}}}
45 | \newcommand{\rulebreak}{\vspace{.1in}\\}
46 | \newcommand{\bit}{\mathtt{bit}}
47 | \newcommand{\unsigned}{\mathtt{unsigned}}
48 | \newcommand{\intsm}{\mathjssm{intish}}
49 | \newcommand{\doublesm}{\mathjssm{doublish}}
50 | \newcommand{\signed}{\mathtt{signed}}
51 | \newcommand{\fixnum}{\mathtt{fixnum}}
52 | \newcommand{\double}{\mathtt{double}}
53 | \newcommand{\view}[2]{\mathtt{view}^{#1}_{#2}}
54 | \newcommand{\extern}{\mathtt{extern}}
55 | \newcommand{\unk}{\mathtt{unknown}}
56 | \newcommand{\str}{\mathtt{string}}
57 | \newcommand{\undef}{\mathtt{undefined}}
58 | \newcommand{\void}{\mathtt{void}}
59 | \newcommand{\nul}{\mathtt{null}}
60 | \newcommand{\num}{\mathtt{number}}
61 | \newcommand{\obj}{\mathtt{object}}
62 | \newcommand{\mustret}{\mathsf{return}}
63 | \newcommand{\seqcomp}{\mathrel{;}}
64 | \newcommand{\getprop}[2]{{#1}\mathjs{[}{#2}\mathjs{]}}
65 | \newcommand{\getpropsm}[2]{{#1}\mathjssm{[}{#2}\mathjssm{]}}
66 | \newcommand{\longlong}[2]{\mathjs{[}{#1},{#2}\mathjs{]}}
67 | \newcommand{\toint}[1]{\mathjs{\~{}\~{}}{#1}}
68 | \newcommand{\todouble}[1]{\mathjs{+}{#1}}
69 | \renewcommand{\int}{\mathtt{int}}
70 | \newcommand{\dword}{\mathtt{bits64}}
71 | \newcommand{\function}{\mathtt{function}}
72 | \newcommand{\union}[2]{{#1}\mathrel{|}{#2}}
73 | \newcommand{\boolish}{\mathtt{boolish}}
74 | \newcommand{\floor}{\mathtt{floor}}
75 | \newcommand{\imul}{\mathtt{imul}}
76 | \newcommand{\intish}{\mathtt{intish}}
77 | \newcommand{\doublish}{\mathtt{doublish}}
78 | \newcommand{\Fun}{\mathtt{Function}}
79 |
80 | \newcommand{\progjudge}[1]{\vdash {#1}\ \ok}
81 | \newcommand{\impjudge}[5]{{#1};{#2};{#3};{#4} \vdash {#5}\ \ok}
82 | \newcommand{\iejudge}[4]{{#1};{#2} \vdash {#3} : {#4}}
83 | \newcommand{\fnjudge}[2]{{#1} \vdash {#2}\ \ok}
84 | \newcommand{\expjudge}[2]{{#1} \vdash {#2}\ \ok}
85 | \newcommand{\stmtjudge}[5]{{#1};{#2} \vdash {#3} : {#4} / {#5}}
86 | \newcommand{\exprjudge}[4]{{#1};{#2} \vdash {#3} : {#4}}
87 | \newcommand{\stmtretjudge}[2]{\vdash {#1} \hookrightarrow {#2}}
88 | \newcommand{\sjudge}[4]{{#1};{#2};{#3} \vdash {#4}\ \ok}
89 |
90 | \newcommand{\returns}{\mathit{returns}}
91 | \newcommand{\breaks}{\mathit{breaks}}
92 |
93 | \begin{document}
94 |
95 | \title{\texttt{asm.js}: a High-Performance Subset of JavaScript}
96 | \author{Dave Herman, Luke Wagner, and Alon Zakai}
97 | \maketitle
98 |
99 | \section{Introduction}
100 |
101 | This document describes a formal definition of a subset of the
102 | JavaScript programming language that can be used as a high-performance
103 | compiler target language. This sublanguage or dialect, which we call
104 | $\mathjs{asm.js}$, effectively describes a safe virtual machine for
105 | memory-unsafe languages such as C and C++.
106 |
107 | Because $\mathjs{asm.js}$ is a proper subset of JavaScript, both
108 | syntactically and semantically, the language is fully defined by a
109 | static {\it validation} judgment, which yields a predicate that
110 | determines whether a given JavaScript program is or is not in the
111 | subset. No specification of a dynamic semantics is needed, since the
112 | behavior of an $\mathjs{asm.js}$ program is simply defined by its
113 | behavior as a JavaScript program.
114 |
115 | \subsection{Overview}
116 |
117 | The unit of compilation/validation of $\mathjs{asm.js}$ is the
118 | $\mathjs{asm.js}$ {\it module}, which takes the form of a closed
119 | JavaScript function beginning with the {\it prologue
120 | directive}~\cite{es5}:
121 | \[
122 | \mathjs{"use asm";}
123 | \]
124 | The presence of this directive serves two purposes. First, it allows
125 | JavaScript engines that wish to provide specialized optimizations for
126 | $\mathjs{asm.js}$ to efficiently recognize that the module should be
127 | validated as an $\mathjs{asm.js}$, without the need for complex,
128 | heuristic or concurrent recognition logic. (Since validation requires
129 | a non-trivial traversal of the body of the module, it is likely too
130 | expensive to speculatively validate {\it all} JavaScript code during
131 | JIT compilation.) Second, by requiring the programmer or code
132 | generator to state the intention explicitly that the code should be
133 | recognized as $\mathjs{asm.js}$, it allows user agents to report
134 | validation errors or performance faults to developer consoles.
135 |
136 | An $\mathjs{asm.js}$ module takes three optional parameters: a global
137 | object, containing standard ECMAScript libraries, an {\it FFI object},
138 | containing custom imported functions and constants from external
139 | JavaScript, and a JavaScript $\mathjs{ArrayBuffer}$ representing a
140 | virtualized memory. The module can provide different views of the
141 | buffer by using typed array wrappers imported from the environment:
142 | \begin{verbatim}
143 | function mod(global, foreign, buffer) {
144 | "use asm";
145 |
146 | var HEAP_I32 = new global.Int32Array(buffer);
147 | var HEAP_F64 = new global.Float64Array(buffer);
148 | // ...
149 | }
150 | \end{verbatim}
151 |
152 | The body of an $\mathjs{asm.js}$ module consists of any number of
153 | function definitions, followed by an {\it export clause}:
154 | \[
155 | \return{\mathjs{\char123{} foo:\,f, bar:\,g \char125{}}}
156 | \]
157 | If a module only exports a single function, it can do so directly,
158 | without the object literal:
159 | \[
160 | \return{\mathjs{foo}}
161 | \]
162 |
163 | \subsection{Types}
164 |
165 | The $\mathjs{asm.js}$ language is statically typed: every function,
166 | variable, and expression has a statically predictable type, according
167 | to a type hierarchy covering a subset of JavaScript values (see
168 | Section~\ref{sec:types}). Variables, parameters, and functions are
169 | provided with an explicit type bound through a stylized use of
170 | JavaScript coercions. This technique was pioneered by the Emscripten
171 | compiler~\cite{emscripten}, and is now used by a number of compilers
172 | that target JavaScript~\cite{mandreel,lljs}.
173 |
174 | For example, the following is a simple function from integers to
175 | integers:
176 | \begin{verbatim}
177 | function id(x) {
178 | x = x|0;
179 | return x|0;
180 | }
181 | \end{verbatim}
182 | Even though JavaScript provides only double-precision floating-point
183 | numbers (doubles) in its data model, the $\mathjs{asm.js}$ type system
184 | enforces that 32-bit integer values---a strict subset of
185 | doubles---never overflow to larger doubles. This allows optimizing
186 | compilers to represent these values as unboxed integers in 32-bit
187 | registers or memory.
188 |
189 | Again following the practice established by Emscripten, it is possible
190 | to do integer operations such as arithmetic and conditionals by means
191 | of coercions:
192 | \begin{verbatim}
193 | function add1(x) {
194 | x = x|0;
195 | return ((x|0)+1)|0;
196 | }
197 | \end{verbatim}
198 | While the JavaScript semantics dictates that the addition may overflow
199 | to a larger number than a 32-bit integer, the outer coercion ensures
200 | that the entire expression results in a 32-bit integer---the same
201 | integer that would be produced by a signed, 32-bit addition in a
202 | typical assembly language. The $\mathjs{asm.js}$ type system thus
203 | ensures that integer operations can be efficiently compiled by
204 | optimizing JavaScript engines to predictable machine instructions.
205 |
206 | \subsection{Validation, linking, and execution}
207 |
208 | The $\mathjs{asm.js}$ validator is defined as a static type system,
209 | which can be performed by an optimizing JavaScript engine at the time
210 | the module is parsed by the JavaScript engine. (If compilation time is
211 | a concern, it can be delayed to runtime by hiding the source code in a
212 | string and passed to $\mathjs{eval}$ or the $\mathjs{Function}$
213 | constructor.) During this phase, any static validation errors can be
214 | reported to a developer console.
215 |
216 | After a $\mathjs{asm.js}$ module is compiled, its evaluation produces
217 | a closure with an empty lexical environment. The module can be {\it
218 | linked} by calling the function with an object representing the
219 | imported environment and an optional buffer:
220 | \begin{verbatim}
221 | function mod(global, foreign, buffer) {
222 | "use asm";
223 | // ...
224 | return { f: foo, g: bar };
225 | }
226 |
227 | var foreign = {
228 | consoleDotLog: console.log,
229 | // ...
230 | };
231 |
232 | var buffer = new ArrayBuffer(0x100000);
233 |
234 | // link the module
235 | var m = mod(window, foreign, buffer);
236 | \end{verbatim}
237 |
238 | This linking phase may need to perform additional, dynamic
239 | validation. In particular, dynamic validation can fail if, for
240 | example, the $\mathjs{Int32Array}$ function passed in through the
241 | environment does not turn out to construct a proper typed array
242 | (thereby defeating typed array-based optimizations).
243 |
244 | The resulting module object provides access to the exported
245 | $\mathjs{asm.js}$ functions, which have been fully validated (both
246 | statically and dynamically) and optimized.
247 |
248 | \subsection{Notation conventions}
249 |
250 | The following notation conventions are used in this document. Optional
251 | items in a grammar are presented in $[\mbox{square
252 | brackets}]$. Sequences are presented with a $\seq{\mbox{horizontal
253 | overbar}}$. The empty sequence is denoted by $\epsilon$. Integers and
254 | integer literals are ranged over by the metavariables $i, j$;
255 | these may also serve as sequence indices, in which case they are
256 | natural numbers. Natural numbers are otherwise ranged over by the
257 | metavariables $m, n$. Floating-point literals are ranged over by the
258 | metavariable $r$.
259 |
260 | \subsection{Document outline}
261 |
262 | The remainder of this document proceeds as follows.
263 | %% FIXME: outline
264 |
265 | \section{Abstract syntax}
266 |
267 | This section specifies the abstract syntax of $\mathjs{asm.js}$. The
268 | grammar is presented with concrete syntax for conciseness and
269 | readability, but should be read as describing the subset of abstract
270 | syntax trees produced by a standard JavaScript parser.
271 |
272 | We make the following assumptions about canonicalization of
273 | $\mathjs{asm.js}$ abstract syntax trees:
274 | \begin{enumerate}
275 | \item Parentheses are ignored in the AST. This allows parentheses to
276 | be left out of any of the formal definitions of this spec.
277 |
278 | \item Empty statements ($\mathjs{;}$) are ignored in the AST. This
279 | allows empty statements to be left out of any of the formal
280 | definitions of this spec.
281 |
282 | \item The identifiers $\mathjs{arguments}$ and $\mathjs{eval}$ do not
283 | appear in $\mathjs{asm.js}$ programs. If either of these identifiers
284 | appears anywhere, static validation must fail.
285 | \end{enumerate}
286 |
287 | In various places in this document, the meta-variables $f$, $g$, $x$,
288 | $y$, and $z$ are used to range over JavaScript identifiers.
289 |
290 | We syntactically distinguish integer literals $i, j$ from
291 | floating-point literals $r$. A floating-point literal is a JavaScript
292 | number literal that contains a $\mathjs{.}$ character.
293 |
294 | \subsection{Modules}
295 |
296 | An $\mathjs{asm.js}$ module has the following syntax:
297 | \[
298 | \begin{array}{rcl}
299 | \mathit{mod} & ::= & \mathjs{function }[f]\mathjs{(}[\mathit{global}[, \mathit{foreign}[, \mathit{buffer}]]]\mathjs{) \char123{}} \\
300 | & & \qquad\mathjs{"use asm";} \\
301 | & & \qquad\seq{\var{\seq{x \mathjs{ = } \mathit{imp}}}} \\
302 | & & \qquad\seq{\mathit{fn}_g} \\
303 | & & \qquad\seq{\var{\seq{y \mathjs{ = } v}}} \\
304 | & & \qquad\mathit{exp} \\
305 | & & \mathjs{\char125{}} \\
306 | %% \fun{[m]}{[g[, e[, b]]]}{\mathjs{"use asm"; } \seq{\mathit{imp}_x}\ \seq{\mathit{fn}_f}\ \seq{\var{\seq{y \mathjs{ = } v}}}\ \mathit{exp}}
307 | \end{array}
308 | \]
309 | The syntax consists of:
310 | \begin{enumerate}
311 | \item an optional module name;
312 | \item up to three optional parameters;
313 | \item a $\mathjs{"use asm";}$ prologue directive;
314 | \item a sequence of import statements;
315 | \item a sequence of function declarations;
316 | \item a sequence of global variable declarations; and
317 | \item a single export statement.
318 | \end{enumerate}
319 |
320 | An import expression is either an FFI function binding, a
321 | type-annotated (coerced) FFI value, or a heap view:
322 | \[
323 | \begin{array}{rcl}
324 | \mathit{imp} & ::= & \mathit{global}\mathjs{.}x \\
325 | & | & \mathit{global}\mathjs{.Math.}x \\
326 | & | & \mathjs{new }\funcall{\mathit{global}\mathjs{.}x}{\mathit{buffer}} \\
327 | & | & \mathit{foreign}\mathjs{.}x\mathjs{|0} \\
328 | & | & \mathjs{+}\mathit{foreign}\mathjs{.}x \\
329 | & | & \mathit{foreign}\mathjs{.}x \\
330 | \end{array}
331 | \]
332 | (We assume that the metavariables $\mathit{global}$,
333 | $\mathit{foreign}$, and $\mathit{buffer}$ stand for fixed variables
334 | names used consistently throughout the imports.)
335 |
336 | A function declaration has the following syntax:
337 | \[
338 | \mathit{fn}_f ::= \fun{f}{\seq{x}}{\seq{x\mathjs{ = }\mathit{ann}_x\mathjs{;}}\ \seq{\var{\seq{y\mathjs{ = }v}}}\ \mathit{ss}}
339 | \]
340 | The syntax consists of type annotations for the parameters, a sequence
341 | of local variable declarations, and a sequence of statements.
342 |
343 | Type annotations are either $\int$ or $\double$ coercions:
344 | \[
345 | \mathit{ann}_x ::= x\mathjs{|0} ~|~ \todouble{x}
346 | \]
347 |
348 | An export statement returns either a single function or an object
349 | literal containing multiple functions:
350 | \[
351 | \begin{array}{rcl}
352 | \mathit{exp} & ::= & \return{f} \\
353 | & | & \return{\mathjs{\char123{} } \seq{x \mathjs{:} f} \mathjs{ \char125{}}} \\
354 | \end{array}
355 | \]
356 |
357 | \subsection{Statements}
358 |
359 | The set of legal statements in $\mathjs{asm.js}$ includes blocks,
360 | expression statements, conditionals, returns, loops, $\mathjs{switch}$
361 | blocks, $\mathjs{break}$ and $\mathjs{continue}$, and labeled
362 | statements:
363 | \[
364 | \begin{array}{rcl}
365 | s & ::= & \block{\mathit{ss}} \\
366 | & | & e\mathjs{;} \\
367 | & | & \ifone{e}{s} \\
368 | & | & \iftwo{e}{s}{s} \\
369 | & | & \return{[\mathit{re}]} \\
370 | & | & \while{e}{s} \\
371 | & | & \dowhile{s}{e} \\
372 | & | & \for{[e]}{[e]}{[e]}{s} \\
373 | & | & \switch{e}{\seq{c}\ [d]} \\
374 | & | & \brkl{[\mathit{lab}]} \\
375 | & | & \contl{[\mathit{lab}]} \\
376 | & | & \lab{\mathit{lab}}{s} \\
377 | \\
378 | \mathit{ss} & ::= & \seq{s} \\
379 | \end{array}
380 | \]
381 |
382 | Return arguments always have their type explicitly manifest: either a
383 | $\signed$ or $\double$ coercion or a literal:
384 | \[
385 | \mathit{re} ::= e\mathjs{|0} ~|~ \todouble{e} ~|~ v
386 | \]
387 |
388 | The contents of $\mathjs{switch}$ blocks are restricted: in addition
389 | to requiring the (optional) $\mathjs{default}$ clause to be the last
390 | clause, each $\mathjs{case}$ clause is syntactically restricted to
391 | contain only literal values:
392 | \[
393 | \begin{array}{rcl}
394 | c & ::= & \mathjs{case }v\mathjs{:}\,\mathit{ss} \\
395 | d & ::= & \mathjs{default:}\,\mathit{ss} \\
396 | \mathit{cd} & ::= & c ~|~ d \\
397 | \end{array}
398 | \]
399 |
400 | \subsection{Expressions}
401 |
402 | Expressions include literals, lvalues, assignments, function calls,
403 | unary expressions, binary expressions, and sequence expressions:
404 | \[
405 | \begin{array}{rcl}
406 | e & ::= & v \\
407 | & | & \mathit{lval} \\
408 | & | & \mathit{lval}\mathjs{ = }e \\
409 | & | & \funcall{f}{\seq{e}} \\
410 | & | & \mathit{unop}\ e \\
411 | & | & e\ \mathit{binop}\ e \\
412 | & | & \ternary{e}{e}{e} \\
413 | & | & \paren{\seq{e}} \\
414 | \\
415 | \mathit{unop} & ::= & \mathjs{+} ~|~ \mathjs{\~{}} ~|~ \mathjs{!} \\
416 | \\
417 | \mathit{binop} & ::= & \mathjs{+} ~|~ \mathjs{-} ~|~ \mathjs{*} ~|~ \mathjs{/} ~|~ \mathjs{\%} \\
418 | & | & \mathjs{|} ~|~ \mathjs{\&} ~|~ \mathjs{\^{}} ~|~ \mathjs{<<} ~|~ \mathjs{>>} ~|~ \mathjs{>>>} \\
419 | & | & \mathjs{<} ~|~ \mathjs{<=} ~|~ \mathjs{>} ~|~ \mathjs{>=} ~|~ \mathjs{!=} ~|~ \mathjs{==} \\
420 | \end{array}
421 | \]
422 |
423 | Literals are either doubles or integers:
424 | \[
425 | v ::= r ~|~ i
426 | \]
427 |
428 | Lvalues are either variables or typed array dereference
429 | expressions. The latter requires a mask to force the byte offset into
430 | a valid range and a shift to convert the offset into a proper index
431 | for the size of the typed array.
432 | \[
433 | \mathit{lval} ::= x ~|~ \getprop{x}{i} ~|~ \getprop{x}{e\mathjs{ \& }\mathit{mask}} ~|~ \getprop{x}{\paren{e\mathjs{ \& }\mathit{mask}}\mathjs{ >> }i}
434 | \]
435 | The $\mathit{mask}$ is a non-negative integer $2^k - 1$ where $k \in
436 | [3, 31]$. The same $\mathit{mask}$ must be used consistently
437 | throughout the program.
438 |
439 | \section{Types}
440 | \label{sec:types}
441 |
442 | The $\mathjs{asm.js}$ validator relies on a static type system that
443 | classifies and constraints the syntax beyond the grammar.
444 |
445 | \subsection{Expression types}
446 |
447 | The set of {\it expression types} classifies the results of expression
448 | evaluation and constrains the allowable values of variables.
449 | \[
450 | \begin{array}{rcl}
451 | \sigma, \tau & ::= & \fixnum ~|~ \signed ~|~ \unsigned ~|~ \int ~|~ \intish \\
452 | & | & \double ~|~ \doublish ~|~ \extern ~|~ \unk ~|~ \void \\
453 | %% \sigma, \tau & ::= & \double ~|~ \signed ~|~ \unsigned ~|~ \fixnum ~|~ \extern \\
454 | %% & | & \bit ~|~ \int ~|~ \boolish ~|~ \intish ~|~ \void ~|~ \unk \\
455 | \end{array}
456 | \]
457 |
458 | These types are arranged in a subtyping hierarchy, defined by:
459 | \[
460 | \begin{array}{rcl}
461 | \fixnum & <: & \signed, \unsigned \\
462 | \signed, \unsigned & <: & \int, \extern \\
463 | \double & <: & \extern, \doublish \\
464 | \unk & <: & \intish, \doublish \\
465 | \int & <: & \intish \\
466 | \end{array}
467 | \]
468 |
469 | Figure~\ref{fig:subtypes} depicts this subtyping hierarchy
470 | visually. Note that some types are presented in white boxes and others
471 | in gray boxes. The white boxes represent types that may escape into
472 | external JavaScript; the gray types are internal to the
473 | $\mathjs{asm.js}$ module and cannot escape. This allows an optimizing
474 | implementation to use unboxed representations that would otherwise be
475 | illegal. What follows is an explanation of each type.
476 |
477 | \begin{figure}[tb]
478 | \centering
479 | \includegraphics[scale=0.5]{subtypes}
480 | \caption{The hierarchy of expression types.}
481 | \label{fig:subtypes}
482 | \end{figure}
483 |
484 | \subsubsection*{The $\extern$ type}
485 |
486 | This abstract type represents the root of all types that can escape
487 | back into ordinary JavaScript. Any type that is a subtype of $\extern$
488 | must carry enough information in its internal representation in an
489 | optimizing virtual machine to faithfully convert back into a dynamic
490 | JavaScript value.
491 |
492 | \subsubsection*{The $\double$ type}
493 |
494 | This is the type of double-precision floating-point values. An
495 | optimizing engine can represent these as unboxed 64-bit floats. If
496 | they escape into external JavaScript they must of course be wrapped
497 | back up as JavaScript values according to the JavaScript engine's
498 | value representation.
499 |
500 | \subsubsection*{The $\signed$ and $\unsigned$ types}
501 |
502 | These are the types of signed and unsigned 32-bit integers,
503 | respectively. For an optimizing engine, their representation can be
504 | the same: an unboxed 32-bit integer. If a value escapes into external
505 | JavaScript, the sign is used to determine which JavaScript value it
506 | represents. For example, the bit pattern $\mathjs{0xffffffff}$
507 | represents either the JavaScript value $\mathjs{-1}$ or
508 | $\mathjs{4294967295}$, depending on the signedness of the type.
509 |
510 | \subsubsection*{The $\fixnum$ type}
511 |
512 | This type represents integers in the range $[0, 2^{31})$, which are
513 | both valid signed and unsigned integers. Literals in this range are
514 | given the type $\fixnum$ rather than $\signed$ or $\unsigned$, since
515 | either way they have the same representation as an unboxed 32-bit
516 | integer.
517 |
518 | \subsubsection*{The $\int$ type}
519 |
520 | This is the type of 32-bit integers whose sign is not known. Again,
521 | optimizing engines can represent them as unboxed 32-bit integers. But
522 | because the sign is not known, they cannot be allowed to escape to
523 | external JavaScript, as it is impossible to determine exactly which
524 | JavaScript value they represent. While this might not seem like a very
525 | useful type, the JavaScript bitwise coercions can be used to force an
526 | $\int$ value back to $\signed$ or $\unsigned$ without any loss of
527 | data.
528 |
529 | The conditional operators also produce the $\int$ type, even though,
530 | according to the JavaScript semantics, they produce boolean
531 | values. Since boolean values convert to the integer values
532 | $\mathjs{0}$ and $\mathjs{1}$, it is sound to represent the boolean
533 | values in an optimizing engine as integers, even while allowing them
534 | to be stored in integer values and passed to integer
535 | arithmetic. Similarly, integer values can be treated as ``boolish'' in
536 | JavaScript when used in conditional contexts, so it is safe to store
537 | boolean values as unboxed integers even when being used in the test
538 | expression of an $\mathjs{if}$ statement and the like.
539 |
540 | \subsubsection*{The $\intish$ type}
541 |
542 | The JavaScript arithmetic operations can be performed on 32-bit
543 | integer values, but their results may produce non-integer values. For
544 | example, addition and subtraction can overflow to large numbers that
545 | exceed the 32-bit integer range, and integer division can produce a
546 | non-integer value. However, if the result is coerced back to an
547 | integer, the resulting arithmetic operation behaves identically to the
548 | typical corresponding machine operation (i.e., integer addition,
549 | subtraction, or division). The $\intish$ type represents the result of
550 | a JavaScript integer artihmetic operation that must be coerced back to
551 | integer with an explicit coercion. Because this type can only be used
552 | as an argument to a coercion (or silently ignored in an expression
553 | statement), $\mathjs{asm.js}$ integer arithmetic can always be
554 | implemented in an optimizing engine by the machine integer artithmetic
555 | operations.
556 |
557 | The one arithmetic operation that does not quite fit into this story
558 | is multiplication. Multiplying two large integers can results in a
559 | large enough double that some lower bits of precision are lost, so
560 | that coercing the result back to integer does {\it not} behave
561 | identically to the machine operation. The use of the proposed ES6
562 | $\mathjs{Math.imul}$ function~\cite{imul} as an FFI function is
563 | recommended as the proper means of implementing integer
564 | multiplication.
565 |
566 | In short:
567 |
568 | \begin{quote}
569 | The $\intish$ type represents the result of integer operations that
570 | must be dropped or immediately coerced via $\mathit{ToInt32}$ or
571 | $\mathit{ToUint32}$.
572 | \end{quote}
573 |
574 | \subsubsection*{The $\doublish$ type}
575 |
576 | Similarly, the $\doublish$ type represents operations that are
577 | expected to produce a $\double$ but may produce additional junk that
578 | must be coerced back to a number via $\mathit{ToNumber}$. In
579 | particular, reading from the typed array may produce
580 | $\mathjs{undefined}$, and calling FFI functions may produce an
581 | arbitrary JavaScript value. Thus:
582 |
583 | \begin{quote}
584 | The $\doublish$ type represents the result of numeric operations that
585 | must be dropped or immediately coerced via $\mathit{ToNumber}$.
586 | \end{quote}
587 |
588 | \subsubsection*{The $\unk$ type}
589 |
590 | Calling an external JavaScript function through the FFI results in an
591 | arbitrary JavaScript value. Because $\mathjs{asm.js}$ is designed to
592 | avoid dealing with general values, the result must be coerced to one
593 | of the other types before it can be used. The $\unk$ type represents
594 | one of these result values before being coerced to an integer or
595 | double.
596 |
597 | \subsubsection*{The $\void$ type}
598 |
599 | A function that returns $\mathjs{undefined}$ is considered to have the
600 | $\void$ result type. The $\mathjs{undefined}$ value is not actually a
601 | first-class value in $\mathjs{asm.js}$. It can only be ignored via an
602 | expression statement. This avoids having to represent it at all as
603 | data.
604 |
605 | \subsection{Global types}
606 |
607 | Validation tracks the types not only of expressions and local
608 | variables but also global variables, FFI imports, and functions. In
609 | addition to variables of expression type, globals may also be typed
610 | array views on the module's buffer, imported FFI constants and
611 | functions, and functions defined in the $\mathjs{asm.js}$ module.
612 | \[
613 | \gamma ::= \tau ~|~ \view{n}{\tau} ~|~ (\funty{\seq{\sigma}}{\tau}) \land \cdots \land (\funty{\seq{\sigma'}}{\tau'}) ~|~ \Fun
614 | \]
615 |
616 | The type of a typed array tracks the number of bytes per element and
617 | the elements' value type ($\intish$ or $\doublish$). A function type
618 | may be overloaded to allow different parameter types, potentially
619 | providing different result types for each overloading.
620 |
621 | \subsection{Operator types}
622 |
623 | Every operator, unary or binary, has an overloaded function type.
624 | This overloading corresponds to the different machine operations used
625 | in an optimizing engine to implement the various cases. Whereas
626 | JavaScript generally needs to choose the behavior of operators
627 | dynamically, $\mathjs{asm.js}$ makes it possible to resolve the
628 | overloaded operators statically based on the types of the operands.
629 |
630 | The types of the arithmetic operators are as follows:
631 | \[
632 | \begin{array}{rcc@{\ }l}
633 | \mathjs{+} & : & & \funty{\double, \double}{\double} \\
634 | % & & \land & \funty{\int, \int}{\intish} \\
635 | \mathjs{-} & : & & \funty{\doublish, \doublish}{\double} \\
636 | % & & \land & \funty{\int, \int}{\intish} \\
637 | \mathjs{*} & : & & \funty{\doublish, \doublish}{\double} \\
638 | \mathjs{/} & : & & \funty{\doublish, \doublish}{\double} \\
639 | & & \land & \funty{\signed, \signed}{\intish} \\
640 | & & \land & \funty{\unsigned, \unsigned}{\intish} \\
641 | \mathjs{\%} & : & & \funty{\doublish, \doublish}{\double} \\
642 | & & \land & \funty{\signed, \signed}{\int} \\
643 | & & \land & \funty{\unsigned, \unsigned}{\int} \\
644 | \end{array}
645 | \]
646 | %% Note that some operations produce the type $\intish$, indicating that
647 | %% their result must be immediately coerced back to an integer. Note also
648 | %% that some operations accept $\doublish$ arguments, because they coerce
649 | %% them immediately with $\mathit{ToNumber}$. (This is not the case for
650 | %% the binary $\mathjs{+}$ operator, which therefore requires its
651 | %% argument to be a true $\double$.)
652 | The type of addition and subtraction only deals with floating-point
653 | arithmetic; for integer addition and subtraction see
654 | Section~\ref{sec:exprjudge}. Similarly, the $\mathjs{*}$ operator
655 | provides only floating-point multiplication; integer multiplication
656 | can be implemented via the $\imul$ function. The $\mathjs{/}$ operator
657 | does provide both floating-point and integer division; for the latter
658 | it produces the type $\intish$, which requires a coercion via the
659 | bitwise operators to produce the proper integer result. The
660 | $\mathjs{\%}$ operator works as either a floating-point or integer
661 | operator and produces the correct result without any need for a
662 | coercion.
663 |
664 | The bitwise operators are one of only two places in the language that
665 | can consume an $\intish$ expression. Every one of these operators can
666 | be composed with the arithmetic operators to produce the correct
667 | behavior of integer arithmetic.
668 | \[
669 | \begin{array}{rcc@{\ }l}
670 | \mathjs{|}, \mathjs{\&}, \mathjs{\^{}}, \mathjs{<<}, \mathjs{>>}
671 | & : & & \funty{\intish, \intish}{\signed} \\
672 | \mathjs{>>>} & : & & \funty{\intish, \intish}{\unsigned} \\
673 | \end{array}
674 | \]
675 |
676 | The conditional operators rely on the sign of their input and produce
677 | a boolean result:
678 | \[
679 | \begin{array}{rcc@{\ }l}
680 | \mathjs{<}, \mathjs{<=}, \mathjs{>}, \mathjs{>=}, \mathjs{==}, \mathjs{!=}
681 | & : & & \funty{\signed, \signed}{\int} \\
682 | & & \land & \funty{\unsigned, \unsigned}{\int} \\
683 | & & \land & \funty{\double, \double}{\int} \\
684 | \end{array}
685 | \]
686 |
687 | Finally, the unary operators have function types as well; unary
688 | operations can also serve as coercions: the $\mathjs{+}$ operator
689 | converts integers and the results of typed array reads and FFI calls
690 | to $\double$, and the $\mathjs{\~{}}$ operator can be used to coerce
691 | $\intish$ expressions, similar to the two-argument bitwise operators.
692 | \[
693 | \begin{array}{rcc@{\ }l}
694 | \mathjs{+} & : & & \funty{\signed}{\double} \\
695 | & & \land & \funty{\unsigned}{\double} \\
696 | & & \land & \funty{\doublish}{\double} \\
697 | \mathjs{-} & : & & \funty{\int}{\intish} \\
698 | & & \land & \funty{\doublish}{\double} \\
699 | \mathjs{\~{}} & : & & \funty{\intish}{\signed} \\
700 | \end{array}
701 | \]
702 |
703 | \section{Validation}
704 |
705 | This section describes the $\mathjs{asm.js}$ validation process, which
706 | is essentially a static type system.
707 |
708 | \subsection{Standard libraries}
709 |
710 | The JavaScript $\mathjs{Math}$ API is recognized as a typed standard
711 | library; most of its functions are allowed as imports with the same
712 | name and are given appropriate function types. These functions must be
713 | passed into the import environment under their respective names (e.g.,
714 | $\mathjs{Math.sin}$ under the name $g\mathjs{.Math.sin}$). Building in
715 | support for these standard functions allows optimizing engines to
716 | build special support for them---particularly the $\imul$ operation,
717 | which can be implemented with hardware multiplication instructions.
718 | \[
719 | \begin{array}{rcl}
720 | M(\mathtt{acos}), M(\mathtt{asin}), M(\mathtt{atan}) & = & \funty{\doublish}{\double} \\
721 | M(\mathtt{cos}), M(\mathtt{sin}), M(\mathtt{tan}) & = & \funty{\doublish}{\double} \\
722 | M(\mathtt{ceil}), M(\mathtt{floor}) & = & \funty{\doublish}{\double} \\
723 | M(\mathtt{exp}), M(\mathtt{log}), M(\mathtt{sqrt}) & = & \funty{\doublish}{\double} \\
724 | M(\mathtt{abs}) & = & \funty{\signed}{\unsigned} \\
725 | & \land & \funty{\doublish}{\double} \\
726 | M(\mathtt{atan2}), M(\mathtt{pow}) & = & \funty{\doublish, \doublish}{\double} \\
727 | M(\imul) & = & \funty{\int, \int}{\signed} \\
728 | M(\mathtt{random}) & = & \funty{}{\double} \\
729 | M(\mathtt{E}) & = & \double \\
730 | M(\mathtt{LN10}), M(\mathtt{LN2}), M(\mathtt{LOG2E}), M(\mathtt{LOG10E}) & = & \double \\
731 | M(\mathtt{PI}) & = & \double \\
732 | M(\mathtt{SQRT1\_2}), M(\mathtt{SQRT2}) & = & \double \\
733 | \end{array}
734 | \]
735 |
736 | \subsection{View types}
737 |
738 | The typed array constructors are also recognized as imports in the
739 | import environment, each under its standard name. Calling the various
740 | typed arrays constructors on the buffer produces typed array views of
741 | various types.
742 | \[
743 | \begin{array}{rcl}
744 | V(\mathtt{Uint8Array}), V(\mathtt{Int8Array}) & = & \view{1}{\intsm} \\
745 | V(\mathtt{Uint16Array}), V(\mathtt{Int16Array}) & = & \view{2}{\intsm} \\
746 | V(\mathtt{Uint32Array}), V(\mathtt{Int32Array}) & = & \view{4}{\intsm} \\
747 | V(\mathtt{Float32Array}) & = & \view{4}{\doublesm} \\
748 | V(\mathtt{Float64Array}) & = & \view{8}{\doublesm} \\
749 | \end{array}
750 | \]
751 |
752 | \subsection{Global constants}
753 |
754 | \[
755 | \begin{array}{rcl}
756 | G(\mathtt{Infinity}), G(\mathtt{NaN}) & = & \double \\
757 | \end{array}
758 | \]
759 |
760 | \subsection{Annotations}
761 |
762 | Type annotations are provided in the form of explicit
763 | coercions. Variables in $\mathjs{asm.js}$ are always taken to have the
764 | type $\double$ or $\int$, never $\signed$ or $\unsigned$. This is
765 | because they are intended to be representable as unboxed 32-bit words
766 | in memory or registers, which are agnostic about what sign to
767 | interpret the bits with.
768 |
769 | \[
770 | \begin{array}{rcl}
771 | \vartype(\todouble{x}), \vartype(r) & = & \double \\
772 | \vartype(x\mathjs{|0}), \vartype(i) & = & \int \mbox{ $(-2^{31} \leq i < 2^{32})$}
773 | \end{array}
774 | \]
775 |
776 | Function return types are determined by explicit coercions in their
777 | return statements. Function return types are always explicit about
778 | their sign so that they can be exported to external JavaScript.
779 |
780 | \[
781 | \begin{array}{rcl}
782 | \rettype(\todouble{e}), \rettype(r) & = & \double \\
783 | \rettype(e\mathjs{|0}), \rettype(i) & = & \signed \mbox{ $(-2^{31} \leq i < 2^{31})$} \\
784 | \rettype(\epsilon) & = & \void \\
785 | \end{array}
786 | \]
787 |
788 | The type of a function can be extracted by looking at its parameter
789 | annotations and return statements.
790 |
791 | \[
792 | \begin{array}{l}
793 | \funtype(\fun{f}{\seq{x}}{\seq{x\mathjs{ = }\mathit{ann}_x\mathjs{;}}\ \seq{\var{\seq{y\mathjs{ = }v}}}\ \mathit{ss}\ \return{[\mathit{re}]}}) = \funty{\seq{\sigma}}{\tau} \\
794 | \qquad \mbox{where } \forall i . \vartype(\mathit{ann}_{x_i}) = \sigma_i \\
795 | \qquad \mbox{and } \rettype([\mathit{re}]) = \tau \\
796 | \funtype(\fun{f}{\seq{x}}{\seq{x\mathjs{ = }\mathit{ann}_x\mathjs{;}}\ \seq{\var{\seq{y\mathjs{ = }v}}}\ \mathit{ss}\ s}) = \funty{\seq{\sigma}}{\void} \\
797 | \qquad \mbox{where } \forall i . \vartype(\mathit{ann}_{x_i}) = \sigma_i \\
798 | \qquad \mbox{and } s \not= \return{[\mathit{re}]} \\
799 | \funtype(\fun{f}{\seq{x}}{\seq{x\mathjs{ = }\mathit{ann}_x\mathjs{;}}\ \seq{\var{\seq{y\mathjs{ = }v}}}\ \epsilon}) = \funty{\seq{\sigma}}{\void} \\
800 | \qquad \mbox{where } \forall i . \vartype(\mathit{ann}_{x_i}) = \sigma_i \\
801 | \end{array}
802 | \]
803 |
804 | The types of import expressions are determined by the standard library
805 | metafunctions $G$, $M$, and $V$ or by their coercion. A foreign import
806 | with no coercion is assumed to be a function.
807 |
808 | \[
809 | \begin{array}{l}
810 | \imptype(\mathit{global}\mathjs{.}x) = G(x) \\
811 | \imptype(\mathit{global}\mathjs{.Math.}x) = M(x) \\
812 | \imptype(\mathjs{new }\funcall{\mathit{global}\mathjs{.}x}{\mathit{buffer}}) = V(y) \\
813 | \imptype(\mathit{foreign}\mathjs{.}x\mathjs{|0}) = \signed \\
814 | \imptype(\mathjs{+}\mathit{foreign}\mathjs{.}x) = \double \\
815 | \imptype(\mathit{foreign}\mathjs{.}x) = \Fun \\
816 | \end{array}
817 | \]
818 |
819 | \subsection{Module validation}
820 |
821 | Module validation takes an $\mathjs{asm.js}$ module and constructs a
822 | {\it global environment} $\Delta$, which is used to track the types of
823 | all globals: imports, buffer views, global variables, and functions.
824 | \[
825 | \begin{array}{rcl}
826 | \mu & ::= & \mut ~|~ \imm \\
827 | \Delta & ::= & \{ \seq{x : \mu\,\gamma} \} \\
828 | \end{array}
829 | \]
830 | Validation then uses this environment to check the imports, exports,
831 | and function definitions.
832 |
833 | \newsavebox{\modjudge}
834 | \begin{lrbox}{\modjudge}
835 | \begin{minipage}[t]{3in}
836 | \vspace{-.25in}
837 | \[
838 | \begin{array}{rll}
839 | & \mathjs{function }[f]\mathjs{(}[\mathit{global}[, \mathit{foreign}[, \mathit{buffer}]]]\mathjs{) \char123{}} \\
840 | & \qquad\mathjs{"use asm";} \\
841 | & \qquad\seq{\var{\seq{x \mathjs{ = } \mathit{imp}}}} \\
842 | \vdash & \qquad\seq{\mathit{fn}_g} & \ok \\
843 | & \qquad\seq{\var{\seq{y \mathjs{ = } v}}} \\
844 | & \qquad\mathit{exp} \\
845 | & \mathjs{\char125{}} \\
846 | \end{array}
847 | \]
848 | \end{minipage}
849 | \end{lrbox}
850 |
851 | \[
852 | \begin{array}{c}
853 | \multicolumn{1}{r}{\fbox{$\progjudge{\mathit{mod}}$}}
854 | \rulebreak
855 | \inferrule* [lab=\rel{T-Module}]
856 | {\Delta = \{ \seq{x : \imm\,\imptype(\mathit{imp})}, \seq{g : \imm\,\funtype(\mathit{fn}_g)}, \seq{y : \mut\,\vartype(v)} \} \\\\
857 | %%\forall i . \impjudge{[g]}{[e]}{[b]}{\Delta}{\mathit{imp}_x} \\
858 | \seq{x}, \seq{y}, \seq{g}, [f], [\mathit{global}], [\mathit{foreign}], [\mathit{buffer}]\ \mbox{distinct} \\
859 | \forall i . \fnjudge{\Delta}{\mathit{fn}_f} \\
860 | \forall i . \expjudge{\Delta}{\mathit{exp}}}
861 | {\usebox{\modjudge}}
862 | % {\progjudge{\fun{[m]}{[g[, e[, b]]}{\mathjs{"use asm";}\ \seq{\mathit{imp}_x}\ \seq{\mathit{fn}_f}\ \seq{\var{\seq{y \mathjs{ = } v}}}\ \mathit{exp}}}}
863 | \end{array}
864 | \]
865 |
866 | For simplicity of the specification, we leave as an assumption that
867 | the same $\mathit{global}$, $\mathit{foreign}$, and $\mathit{buffer}$
868 | variables are used consistently throughout the module. An actual
869 | validator must check this assumption. Similarly, we assume the
870 | existence of a single $\mathit{mask}$ constant used throughout the
871 | module, which a real validator would have to check.
872 |
873 | %% \subsection{Import validation}
874 |
875 | %% Declarations in the import section of an $\mathjs{asm.js}$ module can
876 | %% be known library functions, unknown FFI functions, typed array views,
877 | %% or imported constants.
878 |
879 | %% \[
880 | %% \begin{array}{c}
881 | %% \multicolumn{1}{r}{\fbox{$\impjudge{[g]}{[e]}{[b]}{\Delta}{\mathit{imp}}$}}
882 | %% \rulebreak
883 | %% \inferrule* [lab=\rel{T-ImportStd}]
884 | %% {\iejudge{[g]}{[e]}{\mathit{ie}}{\Delta(x)}}
885 | %% {\impjudge{[g]}{[e]}{[b]}{\Delta}{\var{x \mathjs{ = } \mathit{ie}}}}
886 | %% \qquad
887 | %% \inferrule* [lab=\rel{T-ImportFFI}]
888 | %% {\iejudge{[g]}{[e]}{\mathit{ie}}{\epsilon} \\\\
889 | %% \Delta(x) = \Fun}
890 | %% {\impjudge{[g]}{[e]}{[b]}{\Delta}{\var{x \mathjs{ = } \mathit{ie}}}}
891 | %% \\ \\
892 | %% \inferrule* [lab=\rel{T-ImportInt}]
893 | %% {\iejudge{[g]}{[e]}{\mathit{ie}}{\tau} \\\\
894 | %% \tau <: \intish \\
895 | %% \Delta(x) = \signed}
896 | %% {\impjudge{[g]}{[e]}{[b]}{\Delta}{\var{x \mathjs{ = } \mathit{ie}\mathjs{|0}}}}
897 | %% \qquad
898 | %% \inferrule* [lab=\rel{T-ImportDouble}]
899 | %% {\iejudge{[g]}{[e]}{\mathit{ie}}{\tau} \\\\
900 | %% \tau <: \doublish \\
901 | %% \Delta(x) = \double}
902 | %% {\impjudge{[g]}{[e]}{[b]}{\Delta}{\var{x \mathjs{ = +}\mathit{ie}}}}
903 | %% \\ \\
904 | %% \inferrule* [lab=\rel{T-ImportView}]
905 | %% {\Delta(x) = V(y)}
906 | %% {\impjudge{g}{[e]}{b}{\Delta}{\var{x \mathjs{ = new } g\mathjs{.}y(b)}}}
907 | %% %% \\ \\
908 | %% %% \inferrule* [lab=\rel{T-ImportStd}]
909 | %% %% {\Delta(x) = M(y)}
910 | %% %% {\impjudge{[g]}{[e]}{[b]}{\Delta}{\var{x \mathjs{ = } e\mathjs{.}y}}}
911 | %% %% \qquad
912 | %% %% \inferrule* [lab=\rel{T-ImportFFI}]
913 | %% %% {y \not\in\dom(M), \dom(A) \\\\
914 | %% %% \Delta(x) = \Fun}
915 | %% %% {\impjudge{[g]}{e}{[b]}{\Delta}{\var{x \mathjs{ = } c\mathjs{.}y}}}
916 | %% %% \\ \\
917 | %% %% \inferrule* [lab=\rel{T-View}]
918 | %% %% {\Delta(x) = \view{n}{A(y)}}
919 | %% %% {\impjudge{[g]}{e}{b}{\Delta}{\var{x \mathjs{ = new } c\mathjs{.}y(b)}}}
920 | %% %% \\ \\
921 | %% %% \inferrule* [lab=\rel{T-ImportInt}]
922 | %% %% {\Delta(x) = \int}
923 | %% %% {\impjudge{[g]}{e}{[b]}{\Delta}{\var{x \mathjs{ = }c\mathjs{.}y\mathjs{|0}}}}
924 | %% %% \qquad
925 | %% %% \inferrule* [lab=\rel{T-ImportDouble}]
926 | %% %% {\Delta(x) = \double}
927 | %% %% {\impjudge{[g]}{e}{[b]}{\Delta}{\var{x \mathjs{ = +}c\mathjs{.}y}}}
928 | %% \end{array}
929 | %% \]
930 |
931 | %% \[
932 | %% \begin{array}{c}
933 | %% \multicolumn{1}{r}{\fbox{$\iejudge{[g]}{[e]}{\mathit{ie}}{[\gamma]}$}}
934 | %% \rulebreak
935 | %% \inferrule* [lab=\rel{T-Global}]
936 | %% {y \in \dom(G)}
937 | %% {\iejudge{g}{[e]}{g\mathjs{.}y}{G(y)}}
938 | %% \qquad
939 | %% \inferrule* [lab=\rel{T-Math}]
940 | %% {y \in \dom(M)}
941 | %% {\iejudge{g}{[e]}{g\mathjs{.Math.}y}{M(y)}}
942 | %% \qquad
943 | %% \inferrule* [lab=\rel{T-FFI}]
944 | %% { }
945 | %% {\iejudge{[g]}{e}{e\mathjs{.}y}{\epsilon}}
946 | %% \end{array}
947 | %% \]
948 |
949 | \subsection{Function validation}
950 |
951 | Function validation proceeds in several steps. First, a local
952 | environment is constructed with bindings for the parameters and local
953 | variables, based on their annotations and initializers,
954 | respectively. Next, the body of the function is checked in this
955 | environment. Finally, if the function has a non-$\void$ return type,
956 | the body is checked to ensure that all control flow paths definitely
957 | return a value (see Section~\ref{sec:cfa}).
958 |
959 | \[
960 | \begin{array}{c}
961 | \multicolumn{1}{r}{\fbox{$\fnjudge{\Delta}{\mathit{fn}}$}}
962 | \rulebreak
963 | \inferrule* [lab=\rel{T-Function}]
964 | {\seq{x}, \seq{y}\ \mbox{distinct} \\
965 | \Delta(f) = \imm\,\funty{\seq{\sigma}}{\tau} \\
966 | \seq{\sigma} = \seq{\vartype(\mathit{ann}_x)} \\\\
967 | \sjudge{\Delta}{\{ \seq{x : \sigma}, \seq{y : \vartype(v)} \}}{\tau}{\mathit{ss}}}
968 | {\fnjudge{\Delta}{\fun{f}{\seq{x}}{\seq{x\mathjs{ = }\mathit{ann}_x\mathjs{;}}\ \seq{\var{\seq{y\mathjs{ = }v}}}\ \mathit{ss}}}}
969 | \end{array}
970 | \]
971 |
972 | \subsection{Export validation}
973 |
974 | Export validation ensures that all exports are functions.
975 |
976 | \[
977 | \begin{array}{c}
978 | \multicolumn{1}{r}{\fbox{$\expjudge{\Delta}{\mathit{exp}}$}}
979 | \rulebreak
980 | \inferrule* [lab=\rel{T-Singleton}]
981 | {\Delta(f) = \imm\,\funty{\seq{\sigma}}{\tau}}
982 | {\expjudge{\Delta}{\return{f}}}
983 | \qquad
984 | \inferrule* [lab=\rel{T-Module}]
985 | {\forall f . \Delta(f) = \imm\,\funty{\seq{\sigma}}{\tau}}
986 | {\expjudge{\Delta}{\return{\mathjs{\char123{} } \seq{x \mathjs{:} f} \mathjs{ \char125{}}}}}
987 | \end{array}
988 | \]
989 |
990 | \subsection{Statement list validation}
991 |
992 | \[
993 | \begin{array}{c}
994 | \multicolumn{1}{r}{\fbox{$\sjudge{\Delta}{\Gamma}{\tau}{\mathit{ss}}$}}
995 | \rulebreak
996 | \inferrule* [lab=\rel{T-Statements}]
997 | {\forall i . \sjudge{\Delta}{\Gamma}{\tau}{s_i}}
998 | {\sjudge{\Delta}{\Gamma}{\tau}{\seq{s}}}
999 | \end{array}
1000 | \]
1001 |
1002 |
1003 | \subsection{Statement validation}
1004 |
1005 | \newsavebox{\switchcontrol}
1006 | \begin{lrbox}{\switchcontrol}
1007 | \begin{minipage}[t]{2.87in}
1008 | \vspace{-.25in}
1009 | \[
1010 | \varepsilon = \left\{ \begin{array}{ll}
1011 | \mustret & \mbox{if}\ \varepsilon_n = \mustret \land \forall i . \varepsilon_i \cup \emptyset = \emptyset \\
1012 | \bigcup \varepsilon_i - \{ \epsilon \} & \mbox{otherwise}
1013 | \end{array} \right.
1014 | \]
1015 | \end{minipage}
1016 | \end{lrbox}
1017 |
1018 | \[
1019 | \begin{array}{c}
1020 | \multicolumn{1}{r}{\fbox{$\sjudge{\Delta}{\Gamma}{\tau}{s}$}}
1021 | \rulebreak
1022 | \inferrule* [lab=\rel{T-Block}]
1023 | {\sjudge{\Delta}{\Gamma}{\tau}{\mathit{ss}}}
1024 | {\sjudge{\Delta}{\Gamma}{\tau}{\block{\mathit{ss}}}}
1025 | \qquad
1026 | \inferrule* [lab=\rel{T-ExprStmt}]
1027 | {\exprjudge{\Delta}{\Gamma}{e}{\sigma}}
1028 | {\sjudge{\Delta}{\Gamma}{\tau}{e\mathjs{;}}}
1029 | \qquad
1030 | \inferrule* [lab=\rel{T-EmptyStatement}]
1031 | { }
1032 | {\sjudge{\Delta}{\Gamma}{\tau}{\mathjs{;}}}
1033 | \\ \\
1034 | \inferrule* [lab=\rel{T-If}]
1035 | {\exprjudge{\Delta}{\Gamma}{e}{\boolish} \\\\
1036 | \sjudge{\Delta}{\Gamma}{\tau}{s}}
1037 | {\sjudge{\Delta}{\Gamma}{\tau}{\ifone{e}{s}}}
1038 | \qquad
1039 | \inferrule* [lab=\rel{T-IfElse}]
1040 | {\exprjudge{\Delta}{\Gamma}{e}{\boolish} \\\\
1041 | \sjudge{\Delta}{\Gamma}{\tau}{s_1} \\
1042 | \sjudge{\Delta}{\Gamma}{\tau}{s_2}}
1043 | {\sjudge{\Delta}{\Gamma}{\tau}{\iftwo{e}{s_1}{s_2}}}
1044 | \\ \\
1045 | \inferrule* [lab=\rel{T-ReturnExpr}]
1046 | {\exprjudge{\Delta}{\Gamma}{\mathit{re}}{\tau} \\\\
1047 | \rettype(\mathit{re}) = \tau}
1048 | {\sjudge{\Delta}{\Gamma}{\tau}{\return{\mathit{re}}}}
1049 | %% \qquad
1050 | %% \inferrule* [lab=\rel{T-ReturnDouble}]
1051 | %% {\exprjudge{\Delta}{\Gamma}{e}{\double}}
1052 | %% {\sjudge{\Delta}{\Gamma}{\double}{\return{\mathjs{+}e}}}
1053 | \qquad
1054 | \inferrule* [lab=\rel{T-ReturnVoid}]
1055 | { }
1056 | {\sjudge{\Delta}{\Gamma}{\void}{\mathtt{return;}}}
1057 | \\ \\
1058 | \inferrule* [lab=\rel{T-While}]
1059 | {\exprjudge{\Delta}{\Gamma}{e}{\int} \\\\
1060 | \sjudge{\Delta}{\Gamma}{\tau}{s}}
1061 | {\sjudge{\Delta}{\Gamma}{\tau}{\while{e}{s}}}
1062 | \qquad
1063 | \inferrule* [lab=\rel{T-DoWhile}]
1064 | {\sjudge{\Delta}{\Gamma}{\tau}{s} \\\\
1065 | \exprjudge{\Delta}{\Gamma}{e}{\int}}
1066 | {\sjudge{\Delta}{\Gamma}{\tau}{\dowhile{s}{e}}}
1067 | \\ \\
1068 | \inferrule* [lab=\rel{T-For}]
1069 | {[\exprjudge{\Delta}{\Gamma}{e_1}{\sigma_1}] \\
1070 | [\exprjudge{\Delta}{\Gamma}{e_2}{\int}] \\
1071 | [\exprjudge{\Delta}{\Gamma}{e_3}{\sigma_3}] \\\\
1072 | \sjudge{\Delta}{\Gamma}{\tau}{s}}
1073 | {\sjudge{\Delta}{\Gamma}{\tau}{\for{[e_1]}{[e_2]}{[e_3]}{s}}}
1074 | \\ \\
1075 | \inferrule* [lab=\rel{T-Break}]
1076 | { }
1077 | {\sjudge{\Delta}{\Gamma}{\tau}{\brkl{[\mathit{lab}]}}}
1078 | \qquad
1079 | \inferrule* [lab=\rel{T-Continue}]
1080 | { }
1081 | {\sjudge{\Delta}{\Gamma}{\tau}{\contl{[\mathit{lab}]}}}
1082 | \qquad
1083 | \inferrule* [lab=\rel{T-Label}]
1084 | {\sjudge{\Delta}{\Gamma}{\tau}{s}}
1085 | {\sjudge{\Delta}{\Gamma}{\tau}{\lab{\mathit{lab}}{s}}}
1086 | \\ \\
1087 | \inferrule* [lab=\rel{T-Switch}]
1088 | {\exprjudge{\Delta}{\Gamma}{e}{\sigma} \\
1089 | \sigma \in \{ \signed, \unsigned \} \\
1090 | \forall i . \exprjudge{\Delta}{\Gamma}{v_i}{\sigma} \\\\
1091 | \forall i . \sjudge{\Delta}{\Gamma}{\tau}{\mathit{ss}_i} \\
1092 | [\sjudge{\Delta}{\Gamma}{\tau}{\mathit{ss}}]}
1093 | {\sjudge{\Delta}{\Gamma}{\tau}{\switch{e}{\seq{\mathjs{case }v_i\mathjs{:}\,\mathit{ss}_i}\ [\mathjs{default:}\,\mathit{ss}]}}}
1094 | \end{array}
1095 | \]
1096 |
1097 | \subsection{Case validation}
1098 |
1099 | \[
1100 | \begin{array}{c}
1101 | \multicolumn{1}{r}{\fbox{$\sjudge{\Delta}{\Gamma}{\tau}{\mathit{cd}}$}}
1102 | \rulebreak
1103 | \inferrule* [lab=\rel{T-Case}]
1104 | {\sjudge{\Delta}{\Gamma}{\tau}{\mathit{ss}}}
1105 | {\sjudge{\Delta}{\Gamma}{\tau}{\mathjs{case }v\mathjs{:}\,\mathit{ss}}}
1106 | \qquad
1107 | \inferrule* [lab=\rel{T-Default}]
1108 | {\sjudge{\Delta}{\Gamma}{\tau}{\mathit{ss}}}
1109 | {\sjudge{\Delta}{\Gamma}{\tau}{\mathjs{default:}\,\mathit{ss}}}
1110 | \end{array}
1111 | \]
1112 |
1113 | %% \subsection{Must-return analysis}
1114 | %% \label{sec:cfa}
1115 |
1116 | %% \[
1117 | %% \begin{array}{rcl}
1118 | %% \breaks(\seq{s}) & = & \bigcup_i \breaks(s_i) \\
1119 | %% \breaks(\block{\mathit{ss}}) & = & \breaks(\mathit{ss}) \\
1120 | %% \breaks(\ifone{e}{s}) & = & \breaks(s) \\
1121 | %% \breaks(\iftwo{e}{s_1}{s_2}) & = & \breaks(s_1) \cup \breaks(s_2) \\
1122 | %% \breaks(\while{e}{s}) & = & \breaks(s) - \{ \epsilon \} \\
1123 | %% \breaks(\dowhile{s}{e}) & = & \breaks(s) - \{ \epsilon \} \\
1124 | %% \breaks(\for{[e_1]}{[e_2]}{[e_3]}{s}) & = & \breaks(s) - \{ \epsilon \} \\
1125 | %% \breaks(\brk) & = & \{ \epsilon \} \\
1126 | %% \breaks(\brkl{\mathit{lab}}) & = & \{ \mathit{lab} \} \\
1127 | %% \breaks(\lab{\mathit{lab}}{s}) & = & \breaks(s) - \{ \mathit{lab} \} \\
1128 | %% \breaks(\switch{e}{\seq{\mathit{cd}}}) & = & \bigcup_i \breaks(\mathit{cd}_i) - \{ \epsilon \} \\
1129 | %% \breaks(s) \mbox{ (otherwise)} & = & \emptyset \\
1130 | %% \breaks(\mathjs{case }v\mathjs{:}\,\mathit{ss}) & = & \breaks(\mathit{ss}) \\
1131 | %% \breaks(\mathjs{default:}\,\mathit{ss}) & = & \breaks(\mathit{ss}) \\
1132 | %% \end{array}
1133 | %% \]
1134 |
1135 | %% \[
1136 | %% \begin{array}{l}
1137 | %% \returns(\seq{s}) \\
1138 | %% \qquad \mbox{if } \returns(s_m) \land \forall i < m . \breaks(s_m) = \emptyset \mbox{ for some } m \\
1139 | %% \returns(\block{\mathit{ss}}) \\
1140 | %% \qquad \mbox{if } \returns(ss) \\
1141 | %% \returns(\iftwo{e}{s_1}{s_2}) \\
1142 | %% \qquad \mbox{if } \returns(s_1) \land \returns(s_2) \\
1143 | %% \returns(\dowhile{s}{e}) \\
1144 | %% \qquad \mbox{if } \returns(s) \\
1145 | %% \returns(\switch{e}{\seq{\mathit{cd}}}) \\
1146 | %% \qquad \mbox{if } \returns(cd_n) \land \forall i . \breaks(cd_i) = \emptyset \\
1147 | %% \returns(\mathjs{case }v\mathjs{:}\,\mathit{ss}) \\
1148 | %% \qquad \mbox{if } \returns(\mathit{ss}) \\
1149 | %% \returns(\mathjs{default:}\,\mathit{ss}) \\
1150 | %% \qquad \mbox{if } \returns(\mathit{ss})
1151 | %% \end{array}
1152 | %% \]
1153 |
1154 | \subsection{Expression validation}
1155 | \label{sec:exprjudge}
1156 |
1157 | \[
1158 | (\Delta\cdot\Gamma)(x) = \left\{\begin{array}{ll}
1159 | \Gamma(x) & \mbox{if}\ x \in\dom(\Gamma) \\
1160 | \gamma & \mbox{if}\ \Delta(x) = \mu\,\gamma \\
1161 | \end{array} \right.
1162 | \]
1163 |
1164 | \[
1165 | \begin{array}{lr}
1166 | \mbox{Expression validation} & \hfil \fbox{$\exprjudge{\Delta}{\Gamma}{e}{\tau}$}
1167 | \rulebreak
1168 | \multicolumn{2}{c}{
1169 | \begin{array}{c}
1170 | \inferrule* [lab=\rel{T-Signed}]
1171 | {-2^{31} \leq i < 0}
1172 | {\exprjudge{\Delta}{\Gamma}{i}{\signed}}
1173 | \qquad
1174 | \inferrule* [lab=\rel{T-Fixnum}]
1175 | {0 \leq i < 2^{31}}
1176 | {\exprjudge{\Delta}{\Gamma}{i}{\fixnum}}
1177 | \qquad
1178 | \inferrule* [lab=\rel{T-Unsigned}]
1179 | {2^{31} \leq i < 2^{32}}
1180 | {\exprjudge{\Delta}{\Gamma}{i}{\unsigned}}
1181 | \\ \\
1182 | \inferrule* [lab=\rel{T-Double}]
1183 | { }
1184 | {\exprjudge{\Delta}{\Gamma}{r}{\double}}
1185 | \qquad
1186 | \inferrule* [lab=\rel{T-VarRef}]
1187 | {(\Delta\cdot\Gamma)(x) = \tau}
1188 | {\exprjudge{\Delta}{\Gamma}{x}{\tau}}
1189 | \\ \\
1190 | \inferrule* [lab=\rel{T-SetLocal}]
1191 | {\exprjudge{\Delta}{\Gamma}{e}{\tau} \\
1192 | \tau <: \Gamma(x)}
1193 | {\exprjudge{\Delta}{\Gamma}{x\mathjs{ = }e}{\tau}}
1194 | \qquad
1195 | \inferrule* [lab=\rel{T-SetGlobal}]
1196 | {x \not\in\dom(\Gamma) \\
1197 | \Delta(x) = \mut\,\sigma \\\\
1198 | \exprjudge{\Delta}{\Gamma}{e}{\tau} \\
1199 | \tau <: \sigma}
1200 | {\exprjudge{\Delta}{\Gamma}{x\mathjs{ = }e}{\tau}}
1201 | \\ \\
1202 | \inferrule* [lab=\rel{T-LoadImm}]
1203 | {(\Delta\cdot\Gamma)(x) = \view{n}{\tau} \\\\
1204 | i \equiv 0 \mod n \\
1205 | 0 \leq i \leq \mathit{mask} \\\\
1206 | \exprjudge{\Delta}{\Gamma}{e}{\intish}}
1207 | {\exprjudge{\Delta}{\Gamma}{\getprop{x}{i}}{\tau}}
1208 | \qquad
1209 | \inferrule* [lab=\rel{T-StoreImm}]
1210 | {(\Delta\cdot\Gamma)(x) = \view{n}{\tau} \\\\
1211 | i \equiv 0 \mod n \\
1212 | 0 \leq i \leq \mathit{mask} \\\\
1213 | \exprjudge{\Delta}{\Gamma}{e_1}{\intish} \\
1214 | \exprjudge{\Delta}{\Gamma}{e_2}{\tau}}
1215 | {\exprjudge{\Delta}{\Gamma}{\getprop{x}{i}\mathjs{ = }e_2}{\tau}}
1216 | \\ \\
1217 | \inferrule* [lab=\rel{T-LoadByte}]
1218 | {(\Delta\cdot\Gamma)(x) = \view{1}{\intsm} \\\\
1219 | \exprjudge{\Delta}{\Gamma}{e}{\intish}}
1220 | {\exprjudge{\Delta}{\Gamma}{\getprop{x}{e\mathjs{ \& } \mathit{mask}}}{\tau}}
1221 | \qquad
1222 | \inferrule* [lab=\rel{T-StoreByte}]
1223 | {(\Delta\cdot\Gamma)(x) = \view{1}{\intsm} \\\\
1224 | \exprjudge{\Delta}{\Gamma}{e_1}{\intish} \\
1225 | \exprjudge{\Delta}{\Gamma}{e_2}{\tau}}
1226 | {\exprjudge{\Delta}{\Gamma}{\getprop{x}{e_1\mathjs{ \& } \mathit{mask}}\mathjs{ = }e_2}{\tau}}
1227 | \\ \\
1228 | \inferrule* [lab=\rel{T-Load}]
1229 | {(\Delta\cdot\Gamma)(x) = \view{n}{\tau} \\\\
1230 | \mathit{shift} = \log_2(n) \\
1231 | n > 1 \\\\
1232 | \exprjudge{\Delta}{\Gamma}{e}{\intish}}
1233 | {\exprjudge{\Delta}{\Gamma}{\getprop{x}{\paren{e\mathjs{ \& } \mathit{mask}}\mathjs{ >> } \mathit{shift}}}{\tau}}
1234 | \qquad
1235 | \inferrule* [lab=\rel{T-Store}]
1236 | {(\Delta\cdot\Gamma)(x) = \view{n}{\tau} \\\\
1237 | \mathit{shift} = \log_2(n) \\
1238 | n > 1 \\\\
1239 | \exprjudge{\Delta}{\Gamma}{e_1}{\intish} \\
1240 | \exprjudge{\Delta}{\Gamma}{e_2}{\tau}}
1241 | {\exprjudge{\Delta}{\Gamma}{\getprop{x}{\paren{e_1\mathjs{ \& } \mathit{mask}}\mathjs{ >> } \mathit{shift}}\mathjs{ = }e_2}{\tau}}
1242 | \end{array}
1243 | }
1244 | \end{array}
1245 | \]
1246 |
1247 | \[
1248 | \begin{array}{lr}
1249 | \mbox{Expression validation (cont'd)} & \hfil \fbox{$\exprjudge{\Delta}{\Gamma}{e}{\tau}$}
1250 | \rulebreak
1251 | \multicolumn{2}{c}{
1252 | \begin{array}{c}
1253 | \inferrule* [lab=\rel{T-FunCall}]
1254 | {(\Delta\cdot\Gamma)(f) = \_ \land \funty{\seq{\sigma}}{\tau} \land \_ \\\\
1255 | \forall i . \exprjudge{\Delta}{\Gamma}{e_i}{\sigma_i}}
1256 | {\exprjudge{\Delta}{\Gamma}{\funcall{f}{\seq{e}}}{\tau}}
1257 | \qquad
1258 | \inferrule* [lab=\rel{T-FFICall}]
1259 | {(\Delta\cdot\Gamma)(f) = \Fun \\\\
1260 | %(\Delta\cdot\Gamma)(f) = \_ \land \funty{\ldots\sigma}{\tau} \land \_ \\\\
1261 | \forall i . \exprjudge{\Delta}{\Gamma}{e_i}{\extern}}
1262 | {\exprjudge{\Delta}{\Gamma}{\funcall{f}{\seq{e}}}{\unk}}
1263 | \\ \\
1264 | \inferrule* [lab=\rel{T-Unop}]
1265 | {\mathit{unop} : \_ \land \funty{\sigma}{\tau} \land \_ \\\\
1266 | \exprjudge{\Delta}{\Gamma}{e}{\sigma}}
1267 | {\exprjudge{\Delta}{\Gamma}{\mathit{unop}\ e}{\tau}}
1268 | \qquad
1269 | \inferrule* [lab=\rel{T-Binop}]
1270 | {\mathit{binop} : \_ \land \funty{\sigma_1, \sigma_2}{\tau} \land \_ \\\\
1271 | \exprjudge{\Delta}{\Gamma}{e_1}{\sigma_1} \\
1272 | \exprjudge{\Delta}{\Gamma}{e_2}{\sigma_2}}
1273 | {\exprjudge{\Delta}{\Gamma}{e_1\ \mathit{binop}\ e_2}{\tau}}
1274 | \\ \\
1275 | \inferrule* [lab=\rel{T-Multiary}]
1276 | {\forall i < n . \oplus_i \in \{ +, - \} \\
1277 | n \leq 2^{20} \\\\
1278 | \forall i \leq n . \exprjudge{\Delta}{\Gamma}{e_i}{\int}}
1279 | {\exprjudge{\Delta}{\Gamma}{e_1 \oplus_1 \ldots \oplus_{n-1} e_n}{\intish}}
1280 | \qquad
1281 | \inferrule* [lab=\rel{T-Cond}]
1282 | {\tau \in \{ \int, \double \} \\\\
1283 | \exprjudge{\Delta}{\Gamma}{e_1}{\int} \\\\
1284 | \exprjudge{\Delta}{\Gamma}{e_2}{\tau} \\
1285 | \exprjudge{\Delta}{\Gamma}{e_3}{\tau}}
1286 | {\exprjudge{\Delta}{\Gamma}{\ternary{e_1}{e_2}{e_3}}{\tau}}
1287 | \\ \\
1288 | \inferrule* [lab=\rel{T-Paren}]
1289 | {\forall i \leq n . \exprjudge{\Delta}{\Gamma}{e_i}{\tau_i}}
1290 | {\exprjudge{\Delta}{\Gamma}{\paren{\seq{e}}}{\tau_n}}
1291 | \qquad
1292 | \inferrule* [lab=\rel{T-Sub}]
1293 | {\exprjudge{\Delta}{\Gamma}{e}{\sigma} \\
1294 | \sigma <: \tau}
1295 | {\exprjudge{\Delta}{\Gamma}{e}{\tau}}
1296 | \qquad
1297 | \inferrule* [lab=\rel{T-Cast}]
1298 | {\exprjudge{\Delta}{\Gamma}{e}{\double}}
1299 | {\exprjudge{\Delta}{\Gamma}{\mathjs{\~{}\~{}}e}{\signed}}
1300 | \end{array}
1301 | }
1302 | \end{array}
1303 | \]
1304 |
1305 | \end{document}
1306 |
--------------------------------------------------------------------------------