├── LICENSE
├── __tests__
├── apps.ts
├── compiler.ts
├── interpreter.ts
├── parser.ts
├── tokenizer.ts
└── traverse.ts
├── docs
├── GitHub-Mark-64px.png
├── bundle.js
├── index.html
└── index.ts
├── jest.config.js
├── package.json
├── src
├── compiler.ts
├── emitter.ts
├── encoding.ts
├── interpreter.ts
├── parser.ts
├── tokenizer.ts
├── transformer.ts
├── traverse.ts
└── types
│ ├── compiler.ts
│ ├── emitter.ts
│ ├── parser.ts
│ ├── runtime.ts
│ ├── tokenizer.ts
│ ├── transformer.ts
│ └── traverse.ts
├── tsconfig.json
└── yarn.lock
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Mridul M Kumar
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/__tests__/apps.ts:
--------------------------------------------------------------------------------
1 | let apps = [
2 | { name: "an empty program", input: "", output: [] },
3 | { name: "a print statement", input: "print 8", output: [8] },
4 | {
5 | name: "multiple statements",
6 | input: "print 8 print 24",
7 | output: [8, 24]
8 | },
9 | {
10 | name: "binary expressions",
11 | input: "print(2+ 4)",
12 | output: [6]
13 | },
14 | {
15 | name: "nested binary expressions",
16 | input: "print ((6 - 4)+10)",
17 | output: [12]
18 | },
19 | {
20 | name: "variable declaration",
21 | input: "var f = 22 print f",
22 | output: [22]
23 | },
24 | {
25 | name: "variable declaration",
26 | input: "var foo = 21 print foo",
27 | output: [21]
28 | },
29 | {
30 | name: "floating point variable declaration",
31 | input: "var f = 22.5 print f",
32 | output: [22.5]
33 | },
34 | {
35 | name: "variable assignment",
36 | input: "var f = 22 f = (f+1) print f",
37 | output: [23]
38 | },
39 | {
40 | name: "floating point variable assignment",
41 | input: "var f = 22.5 f = (f+1.5) print f",
42 | output: [24]
43 | },
44 | {
45 | name: "handles scientific notation and various other numeric formats",
46 | input: "print 23e02 print -2 print .5",
47 | output: [2300, -2, 0.5]
48 | },
49 | {
50 | name: "while statements",
51 | input: "var f = 0 while (f < 5) f = (f + 1) print f endwhile",
52 | output: [1, 2, 3, 4, 5]
53 | },
54 | {
55 | name: "setpixel statements",
56 | input: "setpixel (1, 2, 3)",
57 | output: [] as any[],
58 | pixels: [[201, 3]]
59 | },
60 | {
61 | name: "if statement",
62 | input: `
63 | var f = 5
64 | if (f < 10)
65 | print 2
66 | endif
67 | if (f > 10)
68 | print 3
69 | endif
70 | `,
71 | output: [2]
72 | },
73 | {
74 | name: "else statement operator",
75 | input: `
76 | if (5 < 3)
77 | print 2
78 | else
79 | print 3
80 | endif
81 | `,
82 | output: [3]
83 | },
84 | {
85 | name: "support a single main proc",
86 | input: `
87 | proc main()
88 | print 22
89 | endproc`,
90 | output: [22]
91 | },
92 | {
93 | name: "supports procedure invocation",
94 | input: `
95 | proc foo()
96 | print 27
97 | endproc
98 | proc main()
99 | foo()
100 | endproc`,
101 | output: [27]
102 | },
103 | {
104 | name: "supports procedure invocation with arguments",
105 | input: `
106 | proc foo(f)
107 | print (f + 1)
108 | endproc
109 | proc main()
110 | foo(28)
111 | endproc`,
112 | output: [29]
113 | }
114 | ];
115 |
116 | // https://github.com/facebook/jest/issues/7280
117 | test.skip("skip", () => {});
118 |
119 | export default apps;
120 |
--------------------------------------------------------------------------------
/__tests__/compiler.ts:
--------------------------------------------------------------------------------
1 | import { runtime } from "../src/compiler";
2 | import apps from "./apps";
3 |
4 | const executeCode = async (code: string, done: jest.DoneCallback) => {
5 | const output: any[] = [];
6 | const display = new Uint8Array(10000);
7 | const pixels: any[] = [];
8 |
9 | try {
10 | const tick = await runtime(code, {
11 | print: d => output.push(d),
12 | display
13 | });
14 | tick();
15 |
16 | // find any pixels that have been written to
17 | display.forEach((value, index) => {
18 | if (value !== 0) {
19 | pixels.push([index, value]);
20 | }
21 | });
22 |
23 | done();
24 | return { output, pixels };
25 | } catch (e) {
26 | console.error(e);
27 | done.fail();
28 | }
29 | };
30 |
31 | describe("compiler", () => {
32 | apps.forEach(app => {
33 | test(app.name, async done => {
34 | const result = await executeCode(app.input, done);
35 | expect(result.output).toEqual(app.output);
36 | if (app.pixels || result.pixels.length) {
37 | expect(result.pixels).toEqual(app.pixels);
38 | }
39 | });
40 | });
41 | });
42 |
--------------------------------------------------------------------------------
/__tests__/interpreter.ts:
--------------------------------------------------------------------------------
1 | import { runtime } from "../src/interpreter";
2 | import apps from "./apps";
3 |
4 | // execute the app, recording print statements and pixel writes
5 | const executeCode = async (code: string) => {
6 | const output: any[] = [];
7 | const pixels: any[] = [];
8 | const display = new Uint8Array(10000);
9 |
10 | const tick = await runtime(code, {
11 | print: d => output.push(d),
12 | display
13 | });
14 | tick();
15 |
16 | // find any pixels that have been written to
17 | display.forEach((value, index) => {
18 | if (value !== 0) {
19 | pixels.push([index, value]);
20 | }
21 | });
22 |
23 | return {
24 | output, pixels
25 | };
26 | };
27 |
28 | describe("interpreter", () => {
29 | apps.forEach(app => {
30 | test(app.name, async () => {
31 | const result = await executeCode(app.input);
32 | expect(result.output).toEqual(app.output);
33 | if (app.pixels || result.pixels.length) {
34 | expect(result.pixels).toEqual(app.pixels);
35 | }
36 | });
37 | });
38 | });
39 |
--------------------------------------------------------------------------------
/__tests__/parser.ts:
--------------------------------------------------------------------------------
1 | const { parse } = require("../src/parser");
2 |
3 | test("parses single statements", () => {
4 | const tokens = [
5 | { type: "keyword", value: "print" },
6 | { type: "number", value: "22" }
7 | ];
8 |
9 | const ast = parse(tokens);
10 | expect(ast.length).toEqual(1);
11 | });
12 |
13 | test("parses multiple homogenous statements", () => {
14 | const tokens = [
15 | // print 22
16 | { type: "keyword", value: "print" },
17 | { type: "number", value: "22" },
18 | // print 22
19 | { type: "keyword", value: "print" },
20 | { type: "number", value: "22" }
21 | ];
22 |
23 | const ast = parse(tokens);
24 | expect(ast.length).toEqual(2);
25 | });
26 |
27 | test("parses print statement with unary expression", () => {
28 | const tokens = [
29 | {
30 | type: "keyword",
31 | value: "print"
32 | },
33 | {
34 | type: "number",
35 | value: "22"
36 | }
37 | ];
38 |
39 | const ast = parse(tokens);
40 | const node = ast[0];
41 |
42 | expect(node).toEqual({
43 | type: "printStatement",
44 | expression: { type: "numberLiteral", value: 22 }
45 | });
46 | });
47 |
48 | test("parses proc with single arg", () => {
49 | const tokens = [
50 | { type: "keyword", value: "proc" },
51 | { type: "identifier", value: "fish" },
52 | { type: "parens", value: "(" },
53 | { type: "identifier", value: "foo" },
54 | { type: "parens", value: ")" },
55 | { type: "keyword", value: "print" },
56 | { type: "number", value: "22" },
57 | { type: "keyword", value: "endproc" }
58 | ];
59 |
60 | const ast = parse(tokens);
61 | expect(ast.length).toEqual(1);
62 |
63 | const node = ast[0];
64 | expect(node).toEqual({
65 | type: "procStatement",
66 | name: "fish",
67 | args: [
68 | {
69 | type: "identifier",
70 | value: "foo"
71 | }
72 | ],
73 | statements: [
74 | {
75 | type: "printStatement",
76 | expression: { type: "numberLiteral", value: 22 }
77 | }
78 | ]
79 | });
80 | });
81 |
--------------------------------------------------------------------------------
/__tests__/tokenizer.ts:
--------------------------------------------------------------------------------
1 | const { tokenize } = require("../src/tokenizer");
2 |
3 | describe("tokenize", () => {
4 | test("copes with a single token", () => {
5 | const input = " print";
6 | const tokens = tokenize(input);
7 | expect(tokens.length).toBe(1);
8 | expect(tokens[0].type).toBe("keyword");
9 | });
10 |
11 | test("copes with multiple tokens", () => {
12 | const input = " printprint";
13 | const tokens = tokenize(input);
14 | expect(tokens.length).toBe(2);
15 | });
16 |
17 | test("consumes whitespace", () => {
18 | const input = " print print";
19 | const tokens = tokenize(input);
20 | expect(tokens.length).toBe(2);
21 | });
22 |
23 | test("barfs on unrecognized token", () => {
24 | expect(() => {
25 | const input = " print $ print";
26 | tokenize(input);
27 | }).toThrowError("Unexpected token $");
28 | });
29 |
30 | test("copes with multiple mixed tokens", () => {
31 | const input = " print 2";
32 | const tokens = tokenize(input);
33 | expect(tokens.length).toBe(2);
34 | expect(tokens[0].type).toBe("keyword");
35 | expect(tokens[1].type).toBe("number");
36 | });
37 | });
38 |
--------------------------------------------------------------------------------
/__tests__/traverse.ts:
--------------------------------------------------------------------------------
1 | import traverse from "../src/traverse";
2 |
3 | test("traverses post order - visiting leaves first", () => {
4 | const ast = {
5 | type: "foo",
6 | bar: {
7 | type: "baz"
8 | }
9 | };
10 |
11 | const visited: string[] = [];
12 | const visitor: Visitor = node => visited.push(node.type);
13 | traverse(ast, visitor);
14 |
15 | expect(visited).toEqual(["baz", "foo"]);
16 | });
17 |
18 | test("traverses array properties", () => {
19 | const ast = {
20 | type: "foo",
21 | bar: [
22 | {
23 | type: "baz"
24 | },
25 | {
26 | type: "bar"
27 | }
28 | ]
29 | };
30 |
31 | const visited: string[] = [];
32 | const visitor: Visitor = node => visited.push(node.type);
33 | traverse(ast, visitor);
34 |
35 | expect(visited).toEqual(["baz", "bar", "foo"]);
36 | });
37 |
38 | test("traverses array root", () => {
39 | const ast = [
40 | {
41 | type: "baz"
42 | },
43 | {
44 | type: "bar"
45 | }
46 | ];
47 |
48 | const visited: string[] = [];
49 | const visitor: Visitor = node => visited.push(node.type);
50 | traverse(ast, visitor);
51 |
52 | expect(visited).toEqual(["baz", "bar"]);
53 | });
54 |
--------------------------------------------------------------------------------
/docs/GitHub-Mark-64px.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mridul0703/Web-Assembly-Compiler/4506bb69b596f7f5c4ee87daee6f791422b53428/docs/GitHub-Mark-64px.png
--------------------------------------------------------------------------------
/docs/bundle.js:
--------------------------------------------------------------------------------
1 | (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i {
19 | const scaled = ctx.createImageData(imageData.width * scale, imageData.height * scale);
20 | const subLine = ctx.createImageData(scale, 1).data;
21 | for (let row = 0; row < imageData.height; row++) {
22 | for (let col = 0; col < imageData.width; col++) {
23 | const sourcePixel = imageData.data.subarray((row * imageData.width + col) * 4, (row * imageData.width + col) * 4 + 4);
24 | for (let x = 0; x < scale; x++)
25 | subLine.set(sourcePixel, x * 4);
26 | for (let y = 0; y < scale; y++) {
27 | const destRow = row * scale + y;
28 | const destCol = col * scale;
29 | scaled.data.set(subLine, (destRow * scaled.width + destCol) * 4);
30 | }
31 | }
32 | }
33 | return scaled;
34 | };
35 | CodeMirror.defineSimpleMode("simplemode", {
36 | start: [
37 | {
38 | regex: new RegExp(`(${keywords.join("|")})`),
39 | token: "keyword"
40 | },
41 | {
42 | regex: /0x[a-f\d]+|[-+]?(?:\.\d+|\d+\.?\d*)(?:e[-+]?\d+)?/i,
43 | token: "number"
44 | },
45 | { regex: /[-+\/*=<>!]+/, token: "operator" },
46 | { regex: /[a-z$][\w$]*/, token: "variable" }
47 | ]
48 | });
49 | const editor = CodeMirror.fromTextArea(codeArea, {
50 | mode: "simplemode",
51 | theme: "abcdef",
52 | lineNumbers: true
53 | });
54 | $("#shareModal").on("show.bs.modal", () => {
55 | const baseUrl = window.location.href.split("#")[0];
56 | const code = encodeURIComponent(btoa(editor.getValue()));
57 | shareUrl.value = `${baseUrl}#${code}`;
58 | });
59 | copyUrl.addEventListener("click", () => navigator.clipboard.writeText(shareUrl.value));
60 | const sleep = async (ms) => await new Promise(resolve => setTimeout(resolve, ms));
61 | let marker;
62 | const logMessage = (message) => (outputArea.value = outputArea.value + message + "\n");
63 | const markError = (token) => {
64 | marker = editor.markText({ line: token.line, ch: token.char }, { line: token.line, ch: token.char + token.value.length }, { className: "error" });
65 | };
66 | const updateCanvas = (display) => {
67 | const context = canvas.getContext("2d");
68 | const imgData = context.createImageData(100, 100);
69 | for (let i = 0; i < 100 * 100; i++) {
70 | imgData.data[i * 4] = display[i];
71 | imgData.data[i * 4 + 1] = display[i];
72 | imgData.data[i * 4 + 2] = display[i];
73 | imgData.data[i * 4 + 3] = 255;
74 | }
75 | const data = scaleImageData(imgData, 3, context);
76 | context.putImageData(data, 0, 0);
77 | };
78 | const run = async (runtime) => {
79 | if (marker) {
80 | marker.clear();
81 | }
82 | await sleep(10);
83 | let tickFunction;
84 | try {
85 | const display = new Uint8Array(10000);
86 | tickFunction = await runtime(editor.getValue(), {
87 | print: logMessage,
88 | display
89 | });
90 | outputArea.value = "";
91 | logMessage(`Executing ... `);
92 | tickFunction();
93 | updateCanvas(display);
94 | interpretButton.classList.remove("active");
95 | compileButton.classList.remove("active");
96 | }
97 | catch (error) {
98 | logMessage(error.message);
99 | markError(error.token);
100 | }
101 | };
102 | interpretButton.addEventListener("click", async () => {
103 | interpretButton.classList.add("active");
104 | compileButton.classList.remove("active");
105 | await run(interpreterRuntime);
106 | });
107 | compileButton.addEventListener("click", async () => {
108 | compileButton.classList.add("active");
109 | interpretButton.classList.remove("active");
110 | await run(compilerRuntime);
111 | });
112 |
113 | },{"../src/compiler":5,"../src/interpreter":8,"../src/tokenizer":10}],2:[function(require,module,exports){
114 | 'use strict'
115 |
116 | exports.byteLength = byteLength
117 | exports.toByteArray = toByteArray
118 | exports.fromByteArray = fromByteArray
119 |
120 | var lookup = []
121 | var revLookup = []
122 | var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array
123 |
124 | var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
125 | for (var i = 0, len = code.length; i < len; ++i) {
126 | lookup[i] = code[i]
127 | revLookup[code.charCodeAt(i)] = i
128 | }
129 |
130 | // Support decoding URL-safe base64 strings, as Node.js does.
131 | // See: https://en.wikipedia.org/wiki/Base64#URL_applications
132 | revLookup['-'.charCodeAt(0)] = 62
133 | revLookup['_'.charCodeAt(0)] = 63
134 |
135 | function getLens (b64) {
136 | var len = b64.length
137 |
138 | if (len % 4 > 0) {
139 | throw new Error('Invalid string. Length must be a multiple of 4')
140 | }
141 |
142 | // Trim off extra bytes after placeholder bytes are found
143 | // See: https://github.com/beatgammit/base64-js/issues/42
144 | var validLen = b64.indexOf('=')
145 | if (validLen === -1) validLen = len
146 |
147 | var placeHoldersLen = validLen === len
148 | ? 0
149 | : 4 - (validLen % 4)
150 |
151 | return [validLen, placeHoldersLen]
152 | }
153 |
154 | // base64 is 4/3 + up to two characters of the original data
155 | function byteLength (b64) {
156 | var lens = getLens(b64)
157 | var validLen = lens[0]
158 | var placeHoldersLen = lens[1]
159 | return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen
160 | }
161 |
162 | function _byteLength (b64, validLen, placeHoldersLen) {
163 | return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen
164 | }
165 |
166 | function toByteArray (b64) {
167 | var tmp
168 | var lens = getLens(b64)
169 | var validLen = lens[0]
170 | var placeHoldersLen = lens[1]
171 |
172 | var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen))
173 |
174 | var curByte = 0
175 |
176 | // if there are placeholders, only get up to the last complete 4 chars
177 | var len = placeHoldersLen > 0
178 | ? validLen - 4
179 | : validLen
180 |
181 | for (var i = 0; i < len; i += 4) {
182 | tmp =
183 | (revLookup[b64.charCodeAt(i)] << 18) |
184 | (revLookup[b64.charCodeAt(i + 1)] << 12) |
185 | (revLookup[b64.charCodeAt(i + 2)] << 6) |
186 | revLookup[b64.charCodeAt(i + 3)]
187 | arr[curByte++] = (tmp >> 16) & 0xFF
188 | arr[curByte++] = (tmp >> 8) & 0xFF
189 | arr[curByte++] = tmp & 0xFF
190 | }
191 |
192 | if (placeHoldersLen === 2) {
193 | tmp =
194 | (revLookup[b64.charCodeAt(i)] << 2) |
195 | (revLookup[b64.charCodeAt(i + 1)] >> 4)
196 | arr[curByte++] = tmp & 0xFF
197 | }
198 |
199 | if (placeHoldersLen === 1) {
200 | tmp =
201 | (revLookup[b64.charCodeAt(i)] << 10) |
202 | (revLookup[b64.charCodeAt(i + 1)] << 4) |
203 | (revLookup[b64.charCodeAt(i + 2)] >> 2)
204 | arr[curByte++] = (tmp >> 8) & 0xFF
205 | arr[curByte++] = tmp & 0xFF
206 | }
207 |
208 | return arr
209 | }
210 |
211 | function tripletToBase64 (num) {
212 | return lookup[num >> 18 & 0x3F] +
213 | lookup[num >> 12 & 0x3F] +
214 | lookup[num >> 6 & 0x3F] +
215 | lookup[num & 0x3F]
216 | }
217 |
218 | function encodeChunk (uint8, start, end) {
219 | var tmp
220 | var output = []
221 | for (var i = start; i < end; i += 3) {
222 | tmp =
223 | ((uint8[i] << 16) & 0xFF0000) +
224 | ((uint8[i + 1] << 8) & 0xFF00) +
225 | (uint8[i + 2] & 0xFF)
226 | output.push(tripletToBase64(tmp))
227 | }
228 | return output.join('')
229 | }
230 |
231 | function fromByteArray (uint8) {
232 | var tmp
233 | var len = uint8.length
234 | var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes
235 | var parts = []
236 | var maxChunkLength = 16383 // must be multiple of 3
237 |
238 | // go through the array every three bytes, we'll deal with trailing stuff later
239 | for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {
240 | parts.push(encodeChunk(
241 | uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)
242 | ))
243 | }
244 |
245 | // pad the end with zeros, but make sure to not forget the extra bytes
246 | if (extraBytes === 1) {
247 | tmp = uint8[len - 1]
248 | parts.push(
249 | lookup[tmp >> 2] +
250 | lookup[(tmp << 4) & 0x3F] +
251 | '=='
252 | )
253 | } else if (extraBytes === 2) {
254 | tmp = (uint8[len - 2] << 8) + uint8[len - 1]
255 | parts.push(
256 | lookup[tmp >> 10] +
257 | lookup[(tmp >> 4) & 0x3F] +
258 | lookup[(tmp << 2) & 0x3F] +
259 | '='
260 | )
261 | }
262 |
263 | return parts.join('')
264 | }
265 |
266 | },{}],3:[function(require,module,exports){
267 | (function (Buffer){
268 | /*!
269 | * The buffer module from node.js, for the browser.
270 | *
271 | * @author Feross Aboukhadijeh
272 | * @license MIT
273 | */
274 | /* eslint-disable no-proto */
275 |
276 | 'use strict'
277 |
278 | var base64 = require('base64-js')
279 | var ieee754 = require('ieee754')
280 |
281 | exports.Buffer = Buffer
282 | exports.SlowBuffer = SlowBuffer
283 | exports.INSPECT_MAX_BYTES = 50
284 |
285 | var K_MAX_LENGTH = 0x7fffffff
286 | exports.kMaxLength = K_MAX_LENGTH
287 |
288 | /**
289 | * If `Buffer.TYPED_ARRAY_SUPPORT`:
290 | * === true Use Uint8Array implementation (fastest)
291 | * === false Print warning and recommend using `buffer` v4.x which has an Object
292 | * implementation (most compatible, even IE6)
293 | *
294 | * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,
295 | * Opera 11.6+, iOS 4.2+.
296 | *
297 | * We report that the browser does not support typed arrays if the are not subclassable
298 | * using __proto__. Firefox 4-29 lacks support for adding new properties to `Uint8Array`
299 | * (See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438). IE 10 lacks support
300 | * for __proto__ and has a buggy typed array implementation.
301 | */
302 | Buffer.TYPED_ARRAY_SUPPORT = typedArraySupport()
303 |
304 | if (!Buffer.TYPED_ARRAY_SUPPORT && typeof console !== 'undefined' &&
305 | typeof console.error === 'function') {
306 | console.error(
307 | 'This browser lacks typed array (Uint8Array) support which is required by ' +
308 | '`buffer` v5.x. Use `buffer` v4.x if you require old browser support.'
309 | )
310 | }
311 |
312 | function typedArraySupport () {
313 | // Can typed array instances can be augmented?
314 | try {
315 | var arr = new Uint8Array(1)
316 | arr.__proto__ = { __proto__: Uint8Array.prototype, foo: function () { return 42 } }
317 | return arr.foo() === 42
318 | } catch (e) {
319 | return false
320 | }
321 | }
322 |
323 | Object.defineProperty(Buffer.prototype, 'parent', {
324 | enumerable: true,
325 | get: function () {
326 | if (!Buffer.isBuffer(this)) return undefined
327 | return this.buffer
328 | }
329 | })
330 |
331 | Object.defineProperty(Buffer.prototype, 'offset', {
332 | enumerable: true,
333 | get: function () {
334 | if (!Buffer.isBuffer(this)) return undefined
335 | return this.byteOffset
336 | }
337 | })
338 |
339 | function createBuffer (length) {
340 | if (length > K_MAX_LENGTH) {
341 | throw new RangeError('The value "' + length + '" is invalid for option "size"')
342 | }
343 | // Return an augmented `Uint8Array` instance
344 | var buf = new Uint8Array(length)
345 | buf.__proto__ = Buffer.prototype
346 | return buf
347 | }
348 |
349 | /**
350 | * The Buffer constructor returns instances of `Uint8Array` that have their
351 | * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of
352 | * `Uint8Array`, so the returned instances will have all the node `Buffer` methods
353 | * and the `Uint8Array` methods. Square bracket notation works as expected -- it
354 | * returns a single octet.
355 | *
356 | * The `Uint8Array` prototype remains unmodified.
357 | */
358 |
359 | function Buffer (arg, encodingOrOffset, length) {
360 | // Common case.
361 | if (typeof arg === 'number') {
362 | if (typeof encodingOrOffset === 'string') {
363 | throw new TypeError(
364 | 'The "string" argument must be of type string. Received type number'
365 | )
366 | }
367 | return allocUnsafe(arg)
368 | }
369 | return from(arg, encodingOrOffset, length)
370 | }
371 |
372 | // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97
373 | if (typeof Symbol !== 'undefined' && Symbol.species != null &&
374 | Buffer[Symbol.species] === Buffer) {
375 | Object.defineProperty(Buffer, Symbol.species, {
376 | value: null,
377 | configurable: true,
378 | enumerable: false,
379 | writable: false
380 | })
381 | }
382 |
383 | Buffer.poolSize = 8192 // not used by this implementation
384 |
385 | function from (value, encodingOrOffset, length) {
386 | if (typeof value === 'string') {
387 | return fromString(value, encodingOrOffset)
388 | }
389 |
390 | if (ArrayBuffer.isView(value)) {
391 | return fromArrayLike(value)
392 | }
393 |
394 | if (value == null) {
395 | throw TypeError(
396 | 'The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' +
397 | 'or Array-like Object. Received type ' + (typeof value)
398 | )
399 | }
400 |
401 | if (isInstance(value, ArrayBuffer) ||
402 | (value && isInstance(value.buffer, ArrayBuffer))) {
403 | return fromArrayBuffer(value, encodingOrOffset, length)
404 | }
405 |
406 | if (typeof value === 'number') {
407 | throw new TypeError(
408 | 'The "value" argument must not be of type number. Received type number'
409 | )
410 | }
411 |
412 | var valueOf = value.valueOf && value.valueOf()
413 | if (valueOf != null && valueOf !== value) {
414 | return Buffer.from(valueOf, encodingOrOffset, length)
415 | }
416 |
417 | var b = fromObject(value)
418 | if (b) return b
419 |
420 | if (typeof Symbol !== 'undefined' && Symbol.toPrimitive != null &&
421 | typeof value[Symbol.toPrimitive] === 'function') {
422 | return Buffer.from(
423 | value[Symbol.toPrimitive]('string'), encodingOrOffset, length
424 | )
425 | }
426 |
427 | throw new TypeError(
428 | 'The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' +
429 | 'or Array-like Object. Received type ' + (typeof value)
430 | )
431 | }
432 |
433 | /**
434 | * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError
435 | * if value is a number.
436 | * Buffer.from(str[, encoding])
437 | * Buffer.from(array)
438 | * Buffer.from(buffer)
439 | * Buffer.from(arrayBuffer[, byteOffset[, length]])
440 | **/
441 | Buffer.from = function (value, encodingOrOffset, length) {
442 | return from(value, encodingOrOffset, length)
443 | }
444 |
445 | // Note: Change prototype *after* Buffer.from is defined to workaround Chrome bug:
446 | // https://github.com/feross/buffer/pull/148
447 | Buffer.prototype.__proto__ = Uint8Array.prototype
448 | Buffer.__proto__ = Uint8Array
449 |
450 | function assertSize (size) {
451 | if (typeof size !== 'number') {
452 | throw new TypeError('"size" argument must be of type number')
453 | } else if (size < 0) {
454 | throw new RangeError('The value "' + size + '" is invalid for option "size"')
455 | }
456 | }
457 |
458 | function alloc (size, fill, encoding) {
459 | assertSize(size)
460 | if (size <= 0) {
461 | return createBuffer(size)
462 | }
463 | if (fill !== undefined) {
464 | // Only pay attention to encoding if it's a string. This
465 | // prevents accidentally sending in a number that would
466 | // be interpretted as a start offset.
467 | return typeof encoding === 'string'
468 | ? createBuffer(size).fill(fill, encoding)
469 | : createBuffer(size).fill(fill)
470 | }
471 | return createBuffer(size)
472 | }
473 |
474 | /**
475 | * Creates a new filled Buffer instance.
476 | * alloc(size[, fill[, encoding]])
477 | **/
478 | Buffer.alloc = function (size, fill, encoding) {
479 | return alloc(size, fill, encoding)
480 | }
481 |
482 | function allocUnsafe (size) {
483 | assertSize(size)
484 | return createBuffer(size < 0 ? 0 : checked(size) | 0)
485 | }
486 |
487 | /**
488 | * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance.
489 | * */
490 | Buffer.allocUnsafe = function (size) {
491 | return allocUnsafe(size)
492 | }
493 | /**
494 | * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance.
495 | */
496 | Buffer.allocUnsafeSlow = function (size) {
497 | return allocUnsafe(size)
498 | }
499 |
500 | function fromString (string, encoding) {
501 | if (typeof encoding !== 'string' || encoding === '') {
502 | encoding = 'utf8'
503 | }
504 |
505 | if (!Buffer.isEncoding(encoding)) {
506 | throw new TypeError('Unknown encoding: ' + encoding)
507 | }
508 |
509 | var length = byteLength(string, encoding) | 0
510 | var buf = createBuffer(length)
511 |
512 | var actual = buf.write(string, encoding)
513 |
514 | if (actual !== length) {
515 | // Writing a hex string, for example, that contains invalid characters will
516 | // cause everything after the first invalid character to be ignored. (e.g.
517 | // 'abxxcd' will be treated as 'ab')
518 | buf = buf.slice(0, actual)
519 | }
520 |
521 | return buf
522 | }
523 |
524 | function fromArrayLike (array) {
525 | var length = array.length < 0 ? 0 : checked(array.length) | 0
526 | var buf = createBuffer(length)
527 | for (var i = 0; i < length; i += 1) {
528 | buf[i] = array[i] & 255
529 | }
530 | return buf
531 | }
532 |
533 | function fromArrayBuffer (array, byteOffset, length) {
534 | if (byteOffset < 0 || array.byteLength < byteOffset) {
535 | throw new RangeError('"offset" is outside of buffer bounds')
536 | }
537 |
538 | if (array.byteLength < byteOffset + (length || 0)) {
539 | throw new RangeError('"length" is outside of buffer bounds')
540 | }
541 |
542 | var buf
543 | if (byteOffset === undefined && length === undefined) {
544 | buf = new Uint8Array(array)
545 | } else if (length === undefined) {
546 | buf = new Uint8Array(array, byteOffset)
547 | } else {
548 | buf = new Uint8Array(array, byteOffset, length)
549 | }
550 |
551 | // Return an augmented `Uint8Array` instance
552 | buf.__proto__ = Buffer.prototype
553 | return buf
554 | }
555 |
556 | function fromObject (obj) {
557 | if (Buffer.isBuffer(obj)) {
558 | var len = checked(obj.length) | 0
559 | var buf = createBuffer(len)
560 |
561 | if (buf.length === 0) {
562 | return buf
563 | }
564 |
565 | obj.copy(buf, 0, 0, len)
566 | return buf
567 | }
568 |
569 | if (obj.length !== undefined) {
570 | if (typeof obj.length !== 'number' || numberIsNaN(obj.length)) {
571 | return createBuffer(0)
572 | }
573 | return fromArrayLike(obj)
574 | }
575 |
576 | if (obj.type === 'Buffer' && Array.isArray(obj.data)) {
577 | return fromArrayLike(obj.data)
578 | }
579 | }
580 |
581 | function checked (length) {
582 | // Note: cannot use `length < K_MAX_LENGTH` here because that fails when
583 | // length is NaN (which is otherwise coerced to zero.)
584 | if (length >= K_MAX_LENGTH) {
585 | throw new RangeError('Attempt to allocate Buffer larger than maximum ' +
586 | 'size: 0x' + K_MAX_LENGTH.toString(16) + ' bytes')
587 | }
588 | return length | 0
589 | }
590 |
591 | function SlowBuffer (length) {
592 | if (+length != length) { // eslint-disable-line eqeqeq
593 | length = 0
594 | }
595 | return Buffer.alloc(+length)
596 | }
597 |
598 | Buffer.isBuffer = function isBuffer (b) {
599 | return b != null && b._isBuffer === true &&
600 | b !== Buffer.prototype // so Buffer.isBuffer(Buffer.prototype) will be false
601 | }
602 |
603 | Buffer.compare = function compare (a, b) {
604 | if (isInstance(a, Uint8Array)) a = Buffer.from(a, a.offset, a.byteLength)
605 | if (isInstance(b, Uint8Array)) b = Buffer.from(b, b.offset, b.byteLength)
606 | if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {
607 | throw new TypeError(
608 | 'The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array'
609 | )
610 | }
611 |
612 | if (a === b) return 0
613 |
614 | var x = a.length
615 | var y = b.length
616 |
617 | for (var i = 0, len = Math.min(x, y); i < len; ++i) {
618 | if (a[i] !== b[i]) {
619 | x = a[i]
620 | y = b[i]
621 | break
622 | }
623 | }
624 |
625 | if (x < y) return -1
626 | if (y < x) return 1
627 | return 0
628 | }
629 |
630 | Buffer.isEncoding = function isEncoding (encoding) {
631 | switch (String(encoding).toLowerCase()) {
632 | case 'hex':
633 | case 'utf8':
634 | case 'utf-8':
635 | case 'ascii':
636 | case 'latin1':
637 | case 'binary':
638 | case 'base64':
639 | case 'ucs2':
640 | case 'ucs-2':
641 | case 'utf16le':
642 | case 'utf-16le':
643 | return true
644 | default:
645 | return false
646 | }
647 | }
648 |
649 | Buffer.concat = function concat (list, length) {
650 | if (!Array.isArray(list)) {
651 | throw new TypeError('"list" argument must be an Array of Buffers')
652 | }
653 |
654 | if (list.length === 0) {
655 | return Buffer.alloc(0)
656 | }
657 |
658 | var i
659 | if (length === undefined) {
660 | length = 0
661 | for (i = 0; i < list.length; ++i) {
662 | length += list[i].length
663 | }
664 | }
665 |
666 | var buffer = Buffer.allocUnsafe(length)
667 | var pos = 0
668 | for (i = 0; i < list.length; ++i) {
669 | var buf = list[i]
670 | if (isInstance(buf, Uint8Array)) {
671 | buf = Buffer.from(buf)
672 | }
673 | if (!Buffer.isBuffer(buf)) {
674 | throw new TypeError('"list" argument must be an Array of Buffers')
675 | }
676 | buf.copy(buffer, pos)
677 | pos += buf.length
678 | }
679 | return buffer
680 | }
681 |
682 | function byteLength (string, encoding) {
683 | if (Buffer.isBuffer(string)) {
684 | return string.length
685 | }
686 | if (ArrayBuffer.isView(string) || isInstance(string, ArrayBuffer)) {
687 | return string.byteLength
688 | }
689 | if (typeof string !== 'string') {
690 | throw new TypeError(
691 | 'The "string" argument must be one of type string, Buffer, or ArrayBuffer. ' +
692 | 'Received type ' + typeof string
693 | )
694 | }
695 |
696 | var len = string.length
697 | var mustMatch = (arguments.length > 2 && arguments[2] === true)
698 | if (!mustMatch && len === 0) return 0
699 |
700 | // Use a for loop to avoid recursion
701 | var loweredCase = false
702 | for (;;) {
703 | switch (encoding) {
704 | case 'ascii':
705 | case 'latin1':
706 | case 'binary':
707 | return len
708 | case 'utf8':
709 | case 'utf-8':
710 | return utf8ToBytes(string).length
711 | case 'ucs2':
712 | case 'ucs-2':
713 | case 'utf16le':
714 | case 'utf-16le':
715 | return len * 2
716 | case 'hex':
717 | return len >>> 1
718 | case 'base64':
719 | return base64ToBytes(string).length
720 | default:
721 | if (loweredCase) {
722 | return mustMatch ? -1 : utf8ToBytes(string).length // assume utf8
723 | }
724 | encoding = ('' + encoding).toLowerCase()
725 | loweredCase = true
726 | }
727 | }
728 | }
729 | Buffer.byteLength = byteLength
730 |
731 | function slowToString (encoding, start, end) {
732 | var loweredCase = false
733 |
734 | // No need to verify that "this.length <= MAX_UINT32" since it's a read-only
735 | // property of a typed array.
736 |
737 | // This behaves neither like String nor Uint8Array in that we set start/end
738 | // to their upper/lower bounds if the value passed is out of range.
739 | // undefined is handled specially as per ECMA-262 6th Edition,
740 | // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization.
741 | if (start === undefined || start < 0) {
742 | start = 0
743 | }
744 | // Return early if start > this.length. Done here to prevent potential uint32
745 | // coercion fail below.
746 | if (start > this.length) {
747 | return ''
748 | }
749 |
750 | if (end === undefined || end > this.length) {
751 | end = this.length
752 | }
753 |
754 | if (end <= 0) {
755 | return ''
756 | }
757 |
758 | // Force coersion to uint32. This will also coerce falsey/NaN values to 0.
759 | end >>>= 0
760 | start >>>= 0
761 |
762 | if (end <= start) {
763 | return ''
764 | }
765 |
766 | if (!encoding) encoding = 'utf8'
767 |
768 | while (true) {
769 | switch (encoding) {
770 | case 'hex':
771 | return hexSlice(this, start, end)
772 |
773 | case 'utf8':
774 | case 'utf-8':
775 | return utf8Slice(this, start, end)
776 |
777 | case 'ascii':
778 | return asciiSlice(this, start, end)
779 |
780 | case 'latin1':
781 | case 'binary':
782 | return latin1Slice(this, start, end)
783 |
784 | case 'base64':
785 | return base64Slice(this, start, end)
786 |
787 | case 'ucs2':
788 | case 'ucs-2':
789 | case 'utf16le':
790 | case 'utf-16le':
791 | return utf16leSlice(this, start, end)
792 |
793 | default:
794 | if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)
795 | encoding = (encoding + '').toLowerCase()
796 | loweredCase = true
797 | }
798 | }
799 | }
800 |
801 | // This property is used by `Buffer.isBuffer` (and the `is-buffer` npm package)
802 | // to detect a Buffer instance. It's not possible to use `instanceof Buffer`
803 | // reliably in a browserify context because there could be multiple different
804 | // copies of the 'buffer' package in use. This method works even for Buffer
805 | // instances that were created from another copy of the `buffer` package.
806 | // See: https://github.com/feross/buffer/issues/154
807 | Buffer.prototype._isBuffer = true
808 |
809 | function swap (b, n, m) {
810 | var i = b[n]
811 | b[n] = b[m]
812 | b[m] = i
813 | }
814 |
815 | Buffer.prototype.swap16 = function swap16 () {
816 | var len = this.length
817 | if (len % 2 !== 0) {
818 | throw new RangeError('Buffer size must be a multiple of 16-bits')
819 | }
820 | for (var i = 0; i < len; i += 2) {
821 | swap(this, i, i + 1)
822 | }
823 | return this
824 | }
825 |
826 | Buffer.prototype.swap32 = function swap32 () {
827 | var len = this.length
828 | if (len % 4 !== 0) {
829 | throw new RangeError('Buffer size must be a multiple of 32-bits')
830 | }
831 | for (var i = 0; i < len; i += 4) {
832 | swap(this, i, i + 3)
833 | swap(this, i + 1, i + 2)
834 | }
835 | return this
836 | }
837 |
838 | Buffer.prototype.swap64 = function swap64 () {
839 | var len = this.length
840 | if (len % 8 !== 0) {
841 | throw new RangeError('Buffer size must be a multiple of 64-bits')
842 | }
843 | for (var i = 0; i < len; i += 8) {
844 | swap(this, i, i + 7)
845 | swap(this, i + 1, i + 6)
846 | swap(this, i + 2, i + 5)
847 | swap(this, i + 3, i + 4)
848 | }
849 | return this
850 | }
851 |
852 | Buffer.prototype.toString = function toString () {
853 | var length = this.length
854 | if (length === 0) return ''
855 | if (arguments.length === 0) return utf8Slice(this, 0, length)
856 | return slowToString.apply(this, arguments)
857 | }
858 |
859 | Buffer.prototype.toLocaleString = Buffer.prototype.toString
860 |
861 | Buffer.prototype.equals = function equals (b) {
862 | if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')
863 | if (this === b) return true
864 | return Buffer.compare(this, b) === 0
865 | }
866 |
867 | Buffer.prototype.inspect = function inspect () {
868 | var str = ''
869 | var max = exports.INSPECT_MAX_BYTES
870 | str = this.toString('hex', 0, max).replace(/(.{2})/g, '$1 ').trim()
871 | if (this.length > max) str += ' ... '
872 | return ''
873 | }
874 |
875 | Buffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) {
876 | if (isInstance(target, Uint8Array)) {
877 | target = Buffer.from(target, target.offset, target.byteLength)
878 | }
879 | if (!Buffer.isBuffer(target)) {
880 | throw new TypeError(
881 | 'The "target" argument must be one of type Buffer or Uint8Array. ' +
882 | 'Received type ' + (typeof target)
883 | )
884 | }
885 |
886 | if (start === undefined) {
887 | start = 0
888 | }
889 | if (end === undefined) {
890 | end = target ? target.length : 0
891 | }
892 | if (thisStart === undefined) {
893 | thisStart = 0
894 | }
895 | if (thisEnd === undefined) {
896 | thisEnd = this.length
897 | }
898 |
899 | if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) {
900 | throw new RangeError('out of range index')
901 | }
902 |
903 | if (thisStart >= thisEnd && start >= end) {
904 | return 0
905 | }
906 | if (thisStart >= thisEnd) {
907 | return -1
908 | }
909 | if (start >= end) {
910 | return 1
911 | }
912 |
913 | start >>>= 0
914 | end >>>= 0
915 | thisStart >>>= 0
916 | thisEnd >>>= 0
917 |
918 | if (this === target) return 0
919 |
920 | var x = thisEnd - thisStart
921 | var y = end - start
922 | var len = Math.min(x, y)
923 |
924 | var thisCopy = this.slice(thisStart, thisEnd)
925 | var targetCopy = target.slice(start, end)
926 |
927 | for (var i = 0; i < len; ++i) {
928 | if (thisCopy[i] !== targetCopy[i]) {
929 | x = thisCopy[i]
930 | y = targetCopy[i]
931 | break
932 | }
933 | }
934 |
935 | if (x < y) return -1
936 | if (y < x) return 1
937 | return 0
938 | }
939 |
940 | // Finds either the first index of `val` in `buffer` at offset >= `byteOffset`,
941 | // OR the last index of `val` in `buffer` at offset <= `byteOffset`.
942 | //
943 | // Arguments:
944 | // - buffer - a Buffer to search
945 | // - val - a string, Buffer, or number
946 | // - byteOffset - an index into `buffer`; will be clamped to an int32
947 | // - encoding - an optional encoding, relevant is val is a string
948 | // - dir - true for indexOf, false for lastIndexOf
949 | function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) {
950 | // Empty buffer means no match
951 | if (buffer.length === 0) return -1
952 |
953 | // Normalize byteOffset
954 | if (typeof byteOffset === 'string') {
955 | encoding = byteOffset
956 | byteOffset = 0
957 | } else if (byteOffset > 0x7fffffff) {
958 | byteOffset = 0x7fffffff
959 | } else if (byteOffset < -0x80000000) {
960 | byteOffset = -0x80000000
961 | }
962 | byteOffset = +byteOffset // Coerce to Number.
963 | if (numberIsNaN(byteOffset)) {
964 | // byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer
965 | byteOffset = dir ? 0 : (buffer.length - 1)
966 | }
967 |
968 | // Normalize byteOffset: negative offsets start from the end of the buffer
969 | if (byteOffset < 0) byteOffset = buffer.length + byteOffset
970 | if (byteOffset >= buffer.length) {
971 | if (dir) return -1
972 | else byteOffset = buffer.length - 1
973 | } else if (byteOffset < 0) {
974 | if (dir) byteOffset = 0
975 | else return -1
976 | }
977 |
978 | // Normalize val
979 | if (typeof val === 'string') {
980 | val = Buffer.from(val, encoding)
981 | }
982 |
983 | // Finally, search either indexOf (if dir is true) or lastIndexOf
984 | if (Buffer.isBuffer(val)) {
985 | // Special case: looking for empty string/buffer always fails
986 | if (val.length === 0) {
987 | return -1
988 | }
989 | return arrayIndexOf(buffer, val, byteOffset, encoding, dir)
990 | } else if (typeof val === 'number') {
991 | val = val & 0xFF // Search for a byte value [0-255]
992 | if (typeof Uint8Array.prototype.indexOf === 'function') {
993 | if (dir) {
994 | return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset)
995 | } else {
996 | return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset)
997 | }
998 | }
999 | return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir)
1000 | }
1001 |
1002 | throw new TypeError('val must be string, number or Buffer')
1003 | }
1004 |
1005 | function arrayIndexOf (arr, val, byteOffset, encoding, dir) {
1006 | var indexSize = 1
1007 | var arrLength = arr.length
1008 | var valLength = val.length
1009 |
1010 | if (encoding !== undefined) {
1011 | encoding = String(encoding).toLowerCase()
1012 | if (encoding === 'ucs2' || encoding === 'ucs-2' ||
1013 | encoding === 'utf16le' || encoding === 'utf-16le') {
1014 | if (arr.length < 2 || val.length < 2) {
1015 | return -1
1016 | }
1017 | indexSize = 2
1018 | arrLength /= 2
1019 | valLength /= 2
1020 | byteOffset /= 2
1021 | }
1022 | }
1023 |
1024 | function read (buf, i) {
1025 | if (indexSize === 1) {
1026 | return buf[i]
1027 | } else {
1028 | return buf.readUInt16BE(i * indexSize)
1029 | }
1030 | }
1031 |
1032 | var i
1033 | if (dir) {
1034 | var foundIndex = -1
1035 | for (i = byteOffset; i < arrLength; i++) {
1036 | if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) {
1037 | if (foundIndex === -1) foundIndex = i
1038 | if (i - foundIndex + 1 === valLength) return foundIndex * indexSize
1039 | } else {
1040 | if (foundIndex !== -1) i -= i - foundIndex
1041 | foundIndex = -1
1042 | }
1043 | }
1044 | } else {
1045 | if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength
1046 | for (i = byteOffset; i >= 0; i--) {
1047 | var found = true
1048 | for (var j = 0; j < valLength; j++) {
1049 | if (read(arr, i + j) !== read(val, j)) {
1050 | found = false
1051 | break
1052 | }
1053 | }
1054 | if (found) return i
1055 | }
1056 | }
1057 |
1058 | return -1
1059 | }
1060 |
1061 | Buffer.prototype.includes = function includes (val, byteOffset, encoding) {
1062 | return this.indexOf(val, byteOffset, encoding) !== -1
1063 | }
1064 |
1065 | Buffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) {
1066 | return bidirectionalIndexOf(this, val, byteOffset, encoding, true)
1067 | }
1068 |
1069 | Buffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) {
1070 | return bidirectionalIndexOf(this, val, byteOffset, encoding, false)
1071 | }
1072 |
1073 | function hexWrite (buf, string, offset, length) {
1074 | offset = Number(offset) || 0
1075 | var remaining = buf.length - offset
1076 | if (!length) {
1077 | length = remaining
1078 | } else {
1079 | length = Number(length)
1080 | if (length > remaining) {
1081 | length = remaining
1082 | }
1083 | }
1084 |
1085 | var strLen = string.length
1086 |
1087 | if (length > strLen / 2) {
1088 | length = strLen / 2
1089 | }
1090 | for (var i = 0; i < length; ++i) {
1091 | var parsed = parseInt(string.substr(i * 2, 2), 16)
1092 | if (numberIsNaN(parsed)) return i
1093 | buf[offset + i] = parsed
1094 | }
1095 | return i
1096 | }
1097 |
1098 | function utf8Write (buf, string, offset, length) {
1099 | return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)
1100 | }
1101 |
1102 | function asciiWrite (buf, string, offset, length) {
1103 | return blitBuffer(asciiToBytes(string), buf, offset, length)
1104 | }
1105 |
1106 | function latin1Write (buf, string, offset, length) {
1107 | return asciiWrite(buf, string, offset, length)
1108 | }
1109 |
1110 | function base64Write (buf, string, offset, length) {
1111 | return blitBuffer(base64ToBytes(string), buf, offset, length)
1112 | }
1113 |
1114 | function ucs2Write (buf, string, offset, length) {
1115 | return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)
1116 | }
1117 |
1118 | Buffer.prototype.write = function write (string, offset, length, encoding) {
1119 | // Buffer#write(string)
1120 | if (offset === undefined) {
1121 | encoding = 'utf8'
1122 | length = this.length
1123 | offset = 0
1124 | // Buffer#write(string, encoding)
1125 | } else if (length === undefined && typeof offset === 'string') {
1126 | encoding = offset
1127 | length = this.length
1128 | offset = 0
1129 | // Buffer#write(string, offset[, length][, encoding])
1130 | } else if (isFinite(offset)) {
1131 | offset = offset >>> 0
1132 | if (isFinite(length)) {
1133 | length = length >>> 0
1134 | if (encoding === undefined) encoding = 'utf8'
1135 | } else {
1136 | encoding = length
1137 | length = undefined
1138 | }
1139 | } else {
1140 | throw new Error(
1141 | 'Buffer.write(string, encoding, offset[, length]) is no longer supported'
1142 | )
1143 | }
1144 |
1145 | var remaining = this.length - offset
1146 | if (length === undefined || length > remaining) length = remaining
1147 |
1148 | if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {
1149 | throw new RangeError('Attempt to write outside buffer bounds')
1150 | }
1151 |
1152 | if (!encoding) encoding = 'utf8'
1153 |
1154 | var loweredCase = false
1155 | for (;;) {
1156 | switch (encoding) {
1157 | case 'hex':
1158 | return hexWrite(this, string, offset, length)
1159 |
1160 | case 'utf8':
1161 | case 'utf-8':
1162 | return utf8Write(this, string, offset, length)
1163 |
1164 | case 'ascii':
1165 | return asciiWrite(this, string, offset, length)
1166 |
1167 | case 'latin1':
1168 | case 'binary':
1169 | return latin1Write(this, string, offset, length)
1170 |
1171 | case 'base64':
1172 | // Warning: maxLength not taken into account in base64Write
1173 | return base64Write(this, string, offset, length)
1174 |
1175 | case 'ucs2':
1176 | case 'ucs-2':
1177 | case 'utf16le':
1178 | case 'utf-16le':
1179 | return ucs2Write(this, string, offset, length)
1180 |
1181 | default:
1182 | if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)
1183 | encoding = ('' + encoding).toLowerCase()
1184 | loweredCase = true
1185 | }
1186 | }
1187 | }
1188 |
1189 | Buffer.prototype.toJSON = function toJSON () {
1190 | return {
1191 | type: 'Buffer',
1192 | data: Array.prototype.slice.call(this._arr || this, 0)
1193 | }
1194 | }
1195 |
1196 | function base64Slice (buf, start, end) {
1197 | if (start === 0 && end === buf.length) {
1198 | return base64.fromByteArray(buf)
1199 | } else {
1200 | return base64.fromByteArray(buf.slice(start, end))
1201 | }
1202 | }
1203 |
1204 | function utf8Slice (buf, start, end) {
1205 | end = Math.min(buf.length, end)
1206 | var res = []
1207 |
1208 | var i = start
1209 | while (i < end) {
1210 | var firstByte = buf[i]
1211 | var codePoint = null
1212 | var bytesPerSequence = (firstByte > 0xEF) ? 4
1213 | : (firstByte > 0xDF) ? 3
1214 | : (firstByte > 0xBF) ? 2
1215 | : 1
1216 |
1217 | if (i + bytesPerSequence <= end) {
1218 | var secondByte, thirdByte, fourthByte, tempCodePoint
1219 |
1220 | switch (bytesPerSequence) {
1221 | case 1:
1222 | if (firstByte < 0x80) {
1223 | codePoint = firstByte
1224 | }
1225 | break
1226 | case 2:
1227 | secondByte = buf[i + 1]
1228 | if ((secondByte & 0xC0) === 0x80) {
1229 | tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F)
1230 | if (tempCodePoint > 0x7F) {
1231 | codePoint = tempCodePoint
1232 | }
1233 | }
1234 | break
1235 | case 3:
1236 | secondByte = buf[i + 1]
1237 | thirdByte = buf[i + 2]
1238 | if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {
1239 | tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F)
1240 | if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {
1241 | codePoint = tempCodePoint
1242 | }
1243 | }
1244 | break
1245 | case 4:
1246 | secondByte = buf[i + 1]
1247 | thirdByte = buf[i + 2]
1248 | fourthByte = buf[i + 3]
1249 | if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {
1250 | tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F)
1251 | if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {
1252 | codePoint = tempCodePoint
1253 | }
1254 | }
1255 | }
1256 | }
1257 |
1258 | if (codePoint === null) {
1259 | // we did not generate a valid codePoint so insert a
1260 | // replacement char (U+FFFD) and advance only 1 byte
1261 | codePoint = 0xFFFD
1262 | bytesPerSequence = 1
1263 | } else if (codePoint > 0xFFFF) {
1264 | // encode to utf16 (surrogate pair dance)
1265 | codePoint -= 0x10000
1266 | res.push(codePoint >>> 10 & 0x3FF | 0xD800)
1267 | codePoint = 0xDC00 | codePoint & 0x3FF
1268 | }
1269 |
1270 | res.push(codePoint)
1271 | i += bytesPerSequence
1272 | }
1273 |
1274 | return decodeCodePointsArray(res)
1275 | }
1276 |
1277 | // Based on http://stackoverflow.com/a/22747272/680742, the browser with
1278 | // the lowest limit is Chrome, with 0x10000 args.
1279 | // We go 1 magnitude less, for safety
1280 | var MAX_ARGUMENTS_LENGTH = 0x1000
1281 |
1282 | function decodeCodePointsArray (codePoints) {
1283 | var len = codePoints.length
1284 | if (len <= MAX_ARGUMENTS_LENGTH) {
1285 | return String.fromCharCode.apply(String, codePoints) // avoid extra slice()
1286 | }
1287 |
1288 | // Decode in chunks to avoid "call stack size exceeded".
1289 | var res = ''
1290 | var i = 0
1291 | while (i < len) {
1292 | res += String.fromCharCode.apply(
1293 | String,
1294 | codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)
1295 | )
1296 | }
1297 | return res
1298 | }
1299 |
1300 | function asciiSlice (buf, start, end) {
1301 | var ret = ''
1302 | end = Math.min(buf.length, end)
1303 |
1304 | for (var i = start; i < end; ++i) {
1305 | ret += String.fromCharCode(buf[i] & 0x7F)
1306 | }
1307 | return ret
1308 | }
1309 |
1310 | function latin1Slice (buf, start, end) {
1311 | var ret = ''
1312 | end = Math.min(buf.length, end)
1313 |
1314 | for (var i = start; i < end; ++i) {
1315 | ret += String.fromCharCode(buf[i])
1316 | }
1317 | return ret
1318 | }
1319 |
1320 | function hexSlice (buf, start, end) {
1321 | var len = buf.length
1322 |
1323 | if (!start || start < 0) start = 0
1324 | if (!end || end < 0 || end > len) end = len
1325 |
1326 | var out = ''
1327 | for (var i = start; i < end; ++i) {
1328 | out += toHex(buf[i])
1329 | }
1330 | return out
1331 | }
1332 |
1333 | function utf16leSlice (buf, start, end) {
1334 | var bytes = buf.slice(start, end)
1335 | var res = ''
1336 | for (var i = 0; i < bytes.length; i += 2) {
1337 | res += String.fromCharCode(bytes[i] + (bytes[i + 1] * 256))
1338 | }
1339 | return res
1340 | }
1341 |
1342 | Buffer.prototype.slice = function slice (start, end) {
1343 | var len = this.length
1344 | start = ~~start
1345 | end = end === undefined ? len : ~~end
1346 |
1347 | if (start < 0) {
1348 | start += len
1349 | if (start < 0) start = 0
1350 | } else if (start > len) {
1351 | start = len
1352 | }
1353 |
1354 | if (end < 0) {
1355 | end += len
1356 | if (end < 0) end = 0
1357 | } else if (end > len) {
1358 | end = len
1359 | }
1360 |
1361 | if (end < start) end = start
1362 |
1363 | var newBuf = this.subarray(start, end)
1364 | // Return an augmented `Uint8Array` instance
1365 | newBuf.__proto__ = Buffer.prototype
1366 | return newBuf
1367 | }
1368 |
1369 | /*
1370 | * Need to make sure that buffer isn't trying to write out of bounds.
1371 | */
1372 | function checkOffset (offset, ext, length) {
1373 | if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')
1374 | if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')
1375 | }
1376 |
1377 | Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {
1378 | offset = offset >>> 0
1379 | byteLength = byteLength >>> 0
1380 | if (!noAssert) checkOffset(offset, byteLength, this.length)
1381 |
1382 | var val = this[offset]
1383 | var mul = 1
1384 | var i = 0
1385 | while (++i < byteLength && (mul *= 0x100)) {
1386 | val += this[offset + i] * mul
1387 | }
1388 |
1389 | return val
1390 | }
1391 |
1392 | Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {
1393 | offset = offset >>> 0
1394 | byteLength = byteLength >>> 0
1395 | if (!noAssert) {
1396 | checkOffset(offset, byteLength, this.length)
1397 | }
1398 |
1399 | var val = this[offset + --byteLength]
1400 | var mul = 1
1401 | while (byteLength > 0 && (mul *= 0x100)) {
1402 | val += this[offset + --byteLength] * mul
1403 | }
1404 |
1405 | return val
1406 | }
1407 |
1408 | Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {
1409 | offset = offset >>> 0
1410 | if (!noAssert) checkOffset(offset, 1, this.length)
1411 | return this[offset]
1412 | }
1413 |
1414 | Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {
1415 | offset = offset >>> 0
1416 | if (!noAssert) checkOffset(offset, 2, this.length)
1417 | return this[offset] | (this[offset + 1] << 8)
1418 | }
1419 |
1420 | Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {
1421 | offset = offset >>> 0
1422 | if (!noAssert) checkOffset(offset, 2, this.length)
1423 | return (this[offset] << 8) | this[offset + 1]
1424 | }
1425 |
1426 | Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {
1427 | offset = offset >>> 0
1428 | if (!noAssert) checkOffset(offset, 4, this.length)
1429 |
1430 | return ((this[offset]) |
1431 | (this[offset + 1] << 8) |
1432 | (this[offset + 2] << 16)) +
1433 | (this[offset + 3] * 0x1000000)
1434 | }
1435 |
1436 | Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {
1437 | offset = offset >>> 0
1438 | if (!noAssert) checkOffset(offset, 4, this.length)
1439 |
1440 | return (this[offset] * 0x1000000) +
1441 | ((this[offset + 1] << 16) |
1442 | (this[offset + 2] << 8) |
1443 | this[offset + 3])
1444 | }
1445 |
1446 | Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {
1447 | offset = offset >>> 0
1448 | byteLength = byteLength >>> 0
1449 | if (!noAssert) checkOffset(offset, byteLength, this.length)
1450 |
1451 | var val = this[offset]
1452 | var mul = 1
1453 | var i = 0
1454 | while (++i < byteLength && (mul *= 0x100)) {
1455 | val += this[offset + i] * mul
1456 | }
1457 | mul *= 0x80
1458 |
1459 | if (val >= mul) val -= Math.pow(2, 8 * byteLength)
1460 |
1461 | return val
1462 | }
1463 |
1464 | Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {
1465 | offset = offset >>> 0
1466 | byteLength = byteLength >>> 0
1467 | if (!noAssert) checkOffset(offset, byteLength, this.length)
1468 |
1469 | var i = byteLength
1470 | var mul = 1
1471 | var val = this[offset + --i]
1472 | while (i > 0 && (mul *= 0x100)) {
1473 | val += this[offset + --i] * mul
1474 | }
1475 | mul *= 0x80
1476 |
1477 | if (val >= mul) val -= Math.pow(2, 8 * byteLength)
1478 |
1479 | return val
1480 | }
1481 |
1482 | Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) {
1483 | offset = offset >>> 0
1484 | if (!noAssert) checkOffset(offset, 1, this.length)
1485 | if (!(this[offset] & 0x80)) return (this[offset])
1486 | return ((0xff - this[offset] + 1) * -1)
1487 | }
1488 |
1489 | Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {
1490 | offset = offset >>> 0
1491 | if (!noAssert) checkOffset(offset, 2, this.length)
1492 | var val = this[offset] | (this[offset + 1] << 8)
1493 | return (val & 0x8000) ? val | 0xFFFF0000 : val
1494 | }
1495 |
1496 | Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {
1497 | offset = offset >>> 0
1498 | if (!noAssert) checkOffset(offset, 2, this.length)
1499 | var val = this[offset + 1] | (this[offset] << 8)
1500 | return (val & 0x8000) ? val | 0xFFFF0000 : val
1501 | }
1502 |
1503 | Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {
1504 | offset = offset >>> 0
1505 | if (!noAssert) checkOffset(offset, 4, this.length)
1506 |
1507 | return (this[offset]) |
1508 | (this[offset + 1] << 8) |
1509 | (this[offset + 2] << 16) |
1510 | (this[offset + 3] << 24)
1511 | }
1512 |
1513 | Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {
1514 | offset = offset >>> 0
1515 | if (!noAssert) checkOffset(offset, 4, this.length)
1516 |
1517 | return (this[offset] << 24) |
1518 | (this[offset + 1] << 16) |
1519 | (this[offset + 2] << 8) |
1520 | (this[offset + 3])
1521 | }
1522 |
1523 | Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {
1524 | offset = offset >>> 0
1525 | if (!noAssert) checkOffset(offset, 4, this.length)
1526 | return ieee754.read(this, offset, true, 23, 4)
1527 | }
1528 |
1529 | Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {
1530 | offset = offset >>> 0
1531 | if (!noAssert) checkOffset(offset, 4, this.length)
1532 | return ieee754.read(this, offset, false, 23, 4)
1533 | }
1534 |
1535 | Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {
1536 | offset = offset >>> 0
1537 | if (!noAssert) checkOffset(offset, 8, this.length)
1538 | return ieee754.read(this, offset, true, 52, 8)
1539 | }
1540 |
1541 | Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {
1542 | offset = offset >>> 0
1543 | if (!noAssert) checkOffset(offset, 8, this.length)
1544 | return ieee754.read(this, offset, false, 52, 8)
1545 | }
1546 |
1547 | function checkInt (buf, value, offset, ext, max, min) {
1548 | if (!Buffer.isBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance')
1549 | if (value > max || value < min) throw new RangeError('"value" argument is out of bounds')
1550 | if (offset + ext > buf.length) throw new RangeError('Index out of range')
1551 | }
1552 |
1553 | Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {
1554 | value = +value
1555 | offset = offset >>> 0
1556 | byteLength = byteLength >>> 0
1557 | if (!noAssert) {
1558 | var maxBytes = Math.pow(2, 8 * byteLength) - 1
1559 | checkInt(this, value, offset, byteLength, maxBytes, 0)
1560 | }
1561 |
1562 | var mul = 1
1563 | var i = 0
1564 | this[offset] = value & 0xFF
1565 | while (++i < byteLength && (mul *= 0x100)) {
1566 | this[offset + i] = (value / mul) & 0xFF
1567 | }
1568 |
1569 | return offset + byteLength
1570 | }
1571 |
1572 | Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {
1573 | value = +value
1574 | offset = offset >>> 0
1575 | byteLength = byteLength >>> 0
1576 | if (!noAssert) {
1577 | var maxBytes = Math.pow(2, 8 * byteLength) - 1
1578 | checkInt(this, value, offset, byteLength, maxBytes, 0)
1579 | }
1580 |
1581 | var i = byteLength - 1
1582 | var mul = 1
1583 | this[offset + i] = value & 0xFF
1584 | while (--i >= 0 && (mul *= 0x100)) {
1585 | this[offset + i] = (value / mul) & 0xFF
1586 | }
1587 |
1588 | return offset + byteLength
1589 | }
1590 |
1591 | Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {
1592 | value = +value
1593 | offset = offset >>> 0
1594 | if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0)
1595 | this[offset] = (value & 0xff)
1596 | return offset + 1
1597 | }
1598 |
1599 | Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {
1600 | value = +value
1601 | offset = offset >>> 0
1602 | if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)
1603 | this[offset] = (value & 0xff)
1604 | this[offset + 1] = (value >>> 8)
1605 | return offset + 2
1606 | }
1607 |
1608 | Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {
1609 | value = +value
1610 | offset = offset >>> 0
1611 | if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)
1612 | this[offset] = (value >>> 8)
1613 | this[offset + 1] = (value & 0xff)
1614 | return offset + 2
1615 | }
1616 |
1617 | Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {
1618 | value = +value
1619 | offset = offset >>> 0
1620 | if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)
1621 | this[offset + 3] = (value >>> 24)
1622 | this[offset + 2] = (value >>> 16)
1623 | this[offset + 1] = (value >>> 8)
1624 | this[offset] = (value & 0xff)
1625 | return offset + 4
1626 | }
1627 |
1628 | Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {
1629 | value = +value
1630 | offset = offset >>> 0
1631 | if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)
1632 | this[offset] = (value >>> 24)
1633 | this[offset + 1] = (value >>> 16)
1634 | this[offset + 2] = (value >>> 8)
1635 | this[offset + 3] = (value & 0xff)
1636 | return offset + 4
1637 | }
1638 |
1639 | Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {
1640 | value = +value
1641 | offset = offset >>> 0
1642 | if (!noAssert) {
1643 | var limit = Math.pow(2, (8 * byteLength) - 1)
1644 |
1645 | checkInt(this, value, offset, byteLength, limit - 1, -limit)
1646 | }
1647 |
1648 | var i = 0
1649 | var mul = 1
1650 | var sub = 0
1651 | this[offset] = value & 0xFF
1652 | while (++i < byteLength && (mul *= 0x100)) {
1653 | if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) {
1654 | sub = 1
1655 | }
1656 | this[offset + i] = ((value / mul) >> 0) - sub & 0xFF
1657 | }
1658 |
1659 | return offset + byteLength
1660 | }
1661 |
1662 | Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {
1663 | value = +value
1664 | offset = offset >>> 0
1665 | if (!noAssert) {
1666 | var limit = Math.pow(2, (8 * byteLength) - 1)
1667 |
1668 | checkInt(this, value, offset, byteLength, limit - 1, -limit)
1669 | }
1670 |
1671 | var i = byteLength - 1
1672 | var mul = 1
1673 | var sub = 0
1674 | this[offset + i] = value & 0xFF
1675 | while (--i >= 0 && (mul *= 0x100)) {
1676 | if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) {
1677 | sub = 1
1678 | }
1679 | this[offset + i] = ((value / mul) >> 0) - sub & 0xFF
1680 | }
1681 |
1682 | return offset + byteLength
1683 | }
1684 |
1685 | Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {
1686 | value = +value
1687 | offset = offset >>> 0
1688 | if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80)
1689 | if (value < 0) value = 0xff + value + 1
1690 | this[offset] = (value & 0xff)
1691 | return offset + 1
1692 | }
1693 |
1694 | Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {
1695 | value = +value
1696 | offset = offset >>> 0
1697 | if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)
1698 | this[offset] = (value & 0xff)
1699 | this[offset + 1] = (value >>> 8)
1700 | return offset + 2
1701 | }
1702 |
1703 | Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {
1704 | value = +value
1705 | offset = offset >>> 0
1706 | if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)
1707 | this[offset] = (value >>> 8)
1708 | this[offset + 1] = (value & 0xff)
1709 | return offset + 2
1710 | }
1711 |
1712 | Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {
1713 | value = +value
1714 | offset = offset >>> 0
1715 | if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)
1716 | this[offset] = (value & 0xff)
1717 | this[offset + 1] = (value >>> 8)
1718 | this[offset + 2] = (value >>> 16)
1719 | this[offset + 3] = (value >>> 24)
1720 | return offset + 4
1721 | }
1722 |
1723 | Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {
1724 | value = +value
1725 | offset = offset >>> 0
1726 | if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)
1727 | if (value < 0) value = 0xffffffff + value + 1
1728 | this[offset] = (value >>> 24)
1729 | this[offset + 1] = (value >>> 16)
1730 | this[offset + 2] = (value >>> 8)
1731 | this[offset + 3] = (value & 0xff)
1732 | return offset + 4
1733 | }
1734 |
1735 | function checkIEEE754 (buf, value, offset, ext, max, min) {
1736 | if (offset + ext > buf.length) throw new RangeError('Index out of range')
1737 | if (offset < 0) throw new RangeError('Index out of range')
1738 | }
1739 |
1740 | function writeFloat (buf, value, offset, littleEndian, noAssert) {
1741 | value = +value
1742 | offset = offset >>> 0
1743 | if (!noAssert) {
1744 | checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38)
1745 | }
1746 | ieee754.write(buf, value, offset, littleEndian, 23, 4)
1747 | return offset + 4
1748 | }
1749 |
1750 | Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {
1751 | return writeFloat(this, value, offset, true, noAssert)
1752 | }
1753 |
1754 | Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {
1755 | return writeFloat(this, value, offset, false, noAssert)
1756 | }
1757 |
1758 | function writeDouble (buf, value, offset, littleEndian, noAssert) {
1759 | value = +value
1760 | offset = offset >>> 0
1761 | if (!noAssert) {
1762 | checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308)
1763 | }
1764 | ieee754.write(buf, value, offset, littleEndian, 52, 8)
1765 | return offset + 8
1766 | }
1767 |
1768 | Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {
1769 | return writeDouble(this, value, offset, true, noAssert)
1770 | }
1771 |
1772 | Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {
1773 | return writeDouble(this, value, offset, false, noAssert)
1774 | }
1775 |
1776 | // copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)
1777 | Buffer.prototype.copy = function copy (target, targetStart, start, end) {
1778 | if (!Buffer.isBuffer(target)) throw new TypeError('argument should be a Buffer')
1779 | if (!start) start = 0
1780 | if (!end && end !== 0) end = this.length
1781 | if (targetStart >= target.length) targetStart = target.length
1782 | if (!targetStart) targetStart = 0
1783 | if (end > 0 && end < start) end = start
1784 |
1785 | // Copy 0 bytes; we're done
1786 | if (end === start) return 0
1787 | if (target.length === 0 || this.length === 0) return 0
1788 |
1789 | // Fatal error conditions
1790 | if (targetStart < 0) {
1791 | throw new RangeError('targetStart out of bounds')
1792 | }
1793 | if (start < 0 || start >= this.length) throw new RangeError('Index out of range')
1794 | if (end < 0) throw new RangeError('sourceEnd out of bounds')
1795 |
1796 | // Are we oob?
1797 | if (end > this.length) end = this.length
1798 | if (target.length - targetStart < end - start) {
1799 | end = target.length - targetStart + start
1800 | }
1801 |
1802 | var len = end - start
1803 |
1804 | if (this === target && typeof Uint8Array.prototype.copyWithin === 'function') {
1805 | // Use built-in when available, missing from IE11
1806 | this.copyWithin(targetStart, start, end)
1807 | } else if (this === target && start < targetStart && targetStart < end) {
1808 | // descending copy from end
1809 | for (var i = len - 1; i >= 0; --i) {
1810 | target[i + targetStart] = this[i + start]
1811 | }
1812 | } else {
1813 | Uint8Array.prototype.set.call(
1814 | target,
1815 | this.subarray(start, end),
1816 | targetStart
1817 | )
1818 | }
1819 |
1820 | return len
1821 | }
1822 |
1823 | // Usage:
1824 | // buffer.fill(number[, offset[, end]])
1825 | // buffer.fill(buffer[, offset[, end]])
1826 | // buffer.fill(string[, offset[, end]][, encoding])
1827 | Buffer.prototype.fill = function fill (val, start, end, encoding) {
1828 | // Handle string cases:
1829 | if (typeof val === 'string') {
1830 | if (typeof start === 'string') {
1831 | encoding = start
1832 | start = 0
1833 | end = this.length
1834 | } else if (typeof end === 'string') {
1835 | encoding = end
1836 | end = this.length
1837 | }
1838 | if (encoding !== undefined && typeof encoding !== 'string') {
1839 | throw new TypeError('encoding must be a string')
1840 | }
1841 | if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) {
1842 | throw new TypeError('Unknown encoding: ' + encoding)
1843 | }
1844 | if (val.length === 1) {
1845 | var code = val.charCodeAt(0)
1846 | if ((encoding === 'utf8' && code < 128) ||
1847 | encoding === 'latin1') {
1848 | // Fast path: If `val` fits into a single byte, use that numeric value.
1849 | val = code
1850 | }
1851 | }
1852 | } else if (typeof val === 'number') {
1853 | val = val & 255
1854 | }
1855 |
1856 | // Invalid ranges are not set to a default, so can range check early.
1857 | if (start < 0 || this.length < start || this.length < end) {
1858 | throw new RangeError('Out of range index')
1859 | }
1860 |
1861 | if (end <= start) {
1862 | return this
1863 | }
1864 |
1865 | start = start >>> 0
1866 | end = end === undefined ? this.length : end >>> 0
1867 |
1868 | if (!val) val = 0
1869 |
1870 | var i
1871 | if (typeof val === 'number') {
1872 | for (i = start; i < end; ++i) {
1873 | this[i] = val
1874 | }
1875 | } else {
1876 | var bytes = Buffer.isBuffer(val)
1877 | ? val
1878 | : Buffer.from(val, encoding)
1879 | var len = bytes.length
1880 | if (len === 0) {
1881 | throw new TypeError('The value "' + val +
1882 | '" is invalid for argument "value"')
1883 | }
1884 | for (i = 0; i < end - start; ++i) {
1885 | this[i + start] = bytes[i % len]
1886 | }
1887 | }
1888 |
1889 | return this
1890 | }
1891 |
1892 | // HELPER FUNCTIONS
1893 | // ================
1894 |
1895 | var INVALID_BASE64_RE = /[^+/0-9A-Za-z-_]/g
1896 |
1897 | function base64clean (str) {
1898 | // Node takes equal signs as end of the Base64 encoding
1899 | str = str.split('=')[0]
1900 | // Node strips out invalid characters like \n and \t from the string, base64-js does not
1901 | str = str.trim().replace(INVALID_BASE64_RE, '')
1902 | // Node converts strings with length < 2 to ''
1903 | if (str.length < 2) return ''
1904 | // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not
1905 | while (str.length % 4 !== 0) {
1906 | str = str + '='
1907 | }
1908 | return str
1909 | }
1910 |
1911 | function toHex (n) {
1912 | if (n < 16) return '0' + n.toString(16)
1913 | return n.toString(16)
1914 | }
1915 |
1916 | function utf8ToBytes (string, units) {
1917 | units = units || Infinity
1918 | var codePoint
1919 | var length = string.length
1920 | var leadSurrogate = null
1921 | var bytes = []
1922 |
1923 | for (var i = 0; i < length; ++i) {
1924 | codePoint = string.charCodeAt(i)
1925 |
1926 | // is surrogate component
1927 | if (codePoint > 0xD7FF && codePoint < 0xE000) {
1928 | // last char was a lead
1929 | if (!leadSurrogate) {
1930 | // no lead yet
1931 | if (codePoint > 0xDBFF) {
1932 | // unexpected trail
1933 | if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
1934 | continue
1935 | } else if (i + 1 === length) {
1936 | // unpaired lead
1937 | if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
1938 | continue
1939 | }
1940 |
1941 | // valid lead
1942 | leadSurrogate = codePoint
1943 |
1944 | continue
1945 | }
1946 |
1947 | // 2 leads in a row
1948 | if (codePoint < 0xDC00) {
1949 | if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
1950 | leadSurrogate = codePoint
1951 | continue
1952 | }
1953 |
1954 | // valid surrogate pair
1955 | codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000
1956 | } else if (leadSurrogate) {
1957 | // valid bmp char, but last char was a lead
1958 | if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
1959 | }
1960 |
1961 | leadSurrogate = null
1962 |
1963 | // encode utf8
1964 | if (codePoint < 0x80) {
1965 | if ((units -= 1) < 0) break
1966 | bytes.push(codePoint)
1967 | } else if (codePoint < 0x800) {
1968 | if ((units -= 2) < 0) break
1969 | bytes.push(
1970 | codePoint >> 0x6 | 0xC0,
1971 | codePoint & 0x3F | 0x80
1972 | )
1973 | } else if (codePoint < 0x10000) {
1974 | if ((units -= 3) < 0) break
1975 | bytes.push(
1976 | codePoint >> 0xC | 0xE0,
1977 | codePoint >> 0x6 & 0x3F | 0x80,
1978 | codePoint & 0x3F | 0x80
1979 | )
1980 | } else if (codePoint < 0x110000) {
1981 | if ((units -= 4) < 0) break
1982 | bytes.push(
1983 | codePoint >> 0x12 | 0xF0,
1984 | codePoint >> 0xC & 0x3F | 0x80,
1985 | codePoint >> 0x6 & 0x3F | 0x80,
1986 | codePoint & 0x3F | 0x80
1987 | )
1988 | } else {
1989 | throw new Error('Invalid code point')
1990 | }
1991 | }
1992 |
1993 | return bytes
1994 | }
1995 |
1996 | function asciiToBytes (str) {
1997 | var byteArray = []
1998 | for (var i = 0; i < str.length; ++i) {
1999 | // Node's code seems to be doing this and not & 0x7F..
2000 | byteArray.push(str.charCodeAt(i) & 0xFF)
2001 | }
2002 | return byteArray
2003 | }
2004 |
2005 | function utf16leToBytes (str, units) {
2006 | var c, hi, lo
2007 | var byteArray = []
2008 | for (var i = 0; i < str.length; ++i) {
2009 | if ((units -= 2) < 0) break
2010 |
2011 | c = str.charCodeAt(i)
2012 | hi = c >> 8
2013 | lo = c % 256
2014 | byteArray.push(lo)
2015 | byteArray.push(hi)
2016 | }
2017 |
2018 | return byteArray
2019 | }
2020 |
2021 | function base64ToBytes (str) {
2022 | return base64.toByteArray(base64clean(str))
2023 | }
2024 |
2025 | function blitBuffer (src, dst, offset, length) {
2026 | for (var i = 0; i < length; ++i) {
2027 | if ((i + offset >= dst.length) || (i >= src.length)) break
2028 | dst[i + offset] = src[i]
2029 | }
2030 | return i
2031 | }
2032 |
2033 | // ArrayBuffer or Uint8Array objects from other contexts (i.e. iframes) do not pass
2034 | // the `instanceof` check but they should be treated as of that type.
2035 | // See: https://github.com/feross/buffer/issues/166
2036 | function isInstance (obj, type) {
2037 | return obj instanceof type ||
2038 | (obj != null && obj.constructor != null && obj.constructor.name != null &&
2039 | obj.constructor.name === type.name)
2040 | }
2041 | function numberIsNaN (obj) {
2042 | // For IE11 support
2043 | return obj !== obj // eslint-disable-line no-self-compare
2044 | }
2045 |
2046 | }).call(this,require("buffer").Buffer)
2047 | },{"base64-js":2,"buffer":3,"ieee754":4}],4:[function(require,module,exports){
2048 | exports.read = function (buffer, offset, isLE, mLen, nBytes) {
2049 | var e, m
2050 | var eLen = (nBytes * 8) - mLen - 1
2051 | var eMax = (1 << eLen) - 1
2052 | var eBias = eMax >> 1
2053 | var nBits = -7
2054 | var i = isLE ? (nBytes - 1) : 0
2055 | var d = isLE ? -1 : 1
2056 | var s = buffer[offset + i]
2057 |
2058 | i += d
2059 |
2060 | e = s & ((1 << (-nBits)) - 1)
2061 | s >>= (-nBits)
2062 | nBits += eLen
2063 | for (; nBits > 0; e = (e * 256) + buffer[offset + i], i += d, nBits -= 8) {}
2064 |
2065 | m = e & ((1 << (-nBits)) - 1)
2066 | e >>= (-nBits)
2067 | nBits += mLen
2068 | for (; nBits > 0; m = (m * 256) + buffer[offset + i], i += d, nBits -= 8) {}
2069 |
2070 | if (e === 0) {
2071 | e = 1 - eBias
2072 | } else if (e === eMax) {
2073 | return m ? NaN : ((s ? -1 : 1) * Infinity)
2074 | } else {
2075 | m = m + Math.pow(2, mLen)
2076 | e = e - eBias
2077 | }
2078 | return (s ? -1 : 1) * m * Math.pow(2, e - mLen)
2079 | }
2080 |
2081 | exports.write = function (buffer, value, offset, isLE, mLen, nBytes) {
2082 | var e, m, c
2083 | var eLen = (nBytes * 8) - mLen - 1
2084 | var eMax = (1 << eLen) - 1
2085 | var eBias = eMax >> 1
2086 | var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)
2087 | var i = isLE ? 0 : (nBytes - 1)
2088 | var d = isLE ? 1 : -1
2089 | var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0
2090 |
2091 | value = Math.abs(value)
2092 |
2093 | if (isNaN(value) || value === Infinity) {
2094 | m = isNaN(value) ? 1 : 0
2095 | e = eMax
2096 | } else {
2097 | e = Math.floor(Math.log(value) / Math.LN2)
2098 | if (value * (c = Math.pow(2, -e)) < 1) {
2099 | e--
2100 | c *= 2
2101 | }
2102 | if (e + eBias >= 1) {
2103 | value += rt / c
2104 | } else {
2105 | value += rt * Math.pow(2, 1 - eBias)
2106 | }
2107 | if (value * c >= 2) {
2108 | e++
2109 | c /= 2
2110 | }
2111 |
2112 | if (e + eBias >= eMax) {
2113 | m = 0
2114 | e = eMax
2115 | } else if (e + eBias >= 1) {
2116 | m = ((value * c) - 1) * Math.pow(2, mLen)
2117 | e = e + eBias
2118 | } else {
2119 | m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)
2120 | e = 0
2121 | }
2122 | }
2123 |
2124 | for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}
2125 |
2126 | e = (e << mLen) | m
2127 | eLen += mLen
2128 | for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}
2129 |
2130 | buffer[offset + i - d] |= s * 128
2131 | }
2132 |
2133 | },{}],5:[function(require,module,exports){
2134 | "use strict";
2135 | Object.defineProperty(exports, "__esModule", { value: true });
2136 | const emitter_1 = require("./emitter");
2137 | const tokenizer_1 = require("./tokenizer");
2138 | const parser_1 = require("./parser");
2139 | const transformer_1 = require("./transformer");
2140 | exports.compile = src => {
2141 | const tokens = tokenizer_1.tokenize(src);
2142 | const ast = parser_1.parse(tokens);
2143 | const transformedAst = transformer_1.transformer(ast);
2144 | const wasm = emitter_1.emitter(transformedAst);
2145 | return wasm;
2146 | };
2147 | exports.runtime = async (src, env) => {
2148 | const wasm = exports.compile(src);
2149 | const memory = new WebAssembly.Memory({ initial: 1 });
2150 | const result = await WebAssembly.instantiate(wasm, {
2151 | env: Object.assign({}, env, { memory })
2152 | });
2153 | return () => {
2154 | result.instance.exports.run();
2155 | env.display.set(new Uint8Array(memory.buffer, 0, 10000));
2156 | };
2157 | };
2158 |
2159 | },{"./emitter":6,"./parser":9,"./tokenizer":10,"./transformer":11}],6:[function(require,module,exports){
2160 | "use strict";
2161 | Object.defineProperty(exports, "__esModule", { value: true });
2162 | const encoding_1 = require("./encoding");
2163 | const traverse_1 = require("./traverse");
2164 | const flatten = (arr) => [].concat.apply([], arr);
2165 | // https://webassembly.github.io/spec/core/binary/modules.html#sections
2166 | var Section;
2167 | (function (Section) {
2168 | Section[Section["custom"] = 0] = "custom";
2169 | Section[Section["type"] = 1] = "type";
2170 | Section[Section["import"] = 2] = "import";
2171 | Section[Section["func"] = 3] = "func";
2172 | Section[Section["table"] = 4] = "table";
2173 | Section[Section["memory"] = 5] = "memory";
2174 | Section[Section["global"] = 6] = "global";
2175 | Section[Section["export"] = 7] = "export";
2176 | Section[Section["start"] = 8] = "start";
2177 | Section[Section["element"] = 9] = "element";
2178 | Section[Section["code"] = 10] = "code";
2179 | Section[Section["data"] = 11] = "data";
2180 | })(Section || (Section = {}));
2181 | // https://webassembly.github.io/spec/core/binary/types.html
2182 | var Valtype;
2183 | (function (Valtype) {
2184 | Valtype[Valtype["i32"] = 127] = "i32";
2185 | Valtype[Valtype["f32"] = 125] = "f32";
2186 | })(Valtype || (Valtype = {}));
2187 | // https://webassembly.github.io/spec/core/binary/types.html#binary-blocktype
2188 | var Blocktype;
2189 | (function (Blocktype) {
2190 | Blocktype[Blocktype["void"] = 64] = "void";
2191 | })(Blocktype || (Blocktype = {}));
2192 | // https://webassembly.github.io/spec/core/binary/instructions.html
2193 | var Opcodes;
2194 | (function (Opcodes) {
2195 | Opcodes[Opcodes["block"] = 2] = "block";
2196 | Opcodes[Opcodes["loop"] = 3] = "loop";
2197 | Opcodes[Opcodes["br"] = 12] = "br";
2198 | Opcodes[Opcodes["br_if"] = 13] = "br_if";
2199 | Opcodes[Opcodes["end"] = 11] = "end";
2200 | Opcodes[Opcodes["call"] = 16] = "call";
2201 | Opcodes[Opcodes["get_local"] = 32] = "get_local";
2202 | Opcodes[Opcodes["set_local"] = 33] = "set_local";
2203 | Opcodes[Opcodes["i32_store_8"] = 58] = "i32_store_8";
2204 | Opcodes[Opcodes["i32_const"] = 65] = "i32_const";
2205 | Opcodes[Opcodes["f32_const"] = 67] = "f32_const";
2206 | Opcodes[Opcodes["i32_eqz"] = 69] = "i32_eqz";
2207 | Opcodes[Opcodes["i32_eq"] = 70] = "i32_eq";
2208 | Opcodes[Opcodes["f32_eq"] = 91] = "f32_eq";
2209 | Opcodes[Opcodes["f32_lt"] = 93] = "f32_lt";
2210 | Opcodes[Opcodes["f32_gt"] = 94] = "f32_gt";
2211 | Opcodes[Opcodes["i32_and"] = 113] = "i32_and";
2212 | Opcodes[Opcodes["f32_add"] = 146] = "f32_add";
2213 | Opcodes[Opcodes["f32_sub"] = 147] = "f32_sub";
2214 | Opcodes[Opcodes["f32_mul"] = 148] = "f32_mul";
2215 | Opcodes[Opcodes["f32_div"] = 149] = "f32_div";
2216 | Opcodes[Opcodes["i32_trunc_f32_s"] = 168] = "i32_trunc_f32_s";
2217 | })(Opcodes || (Opcodes = {}));
2218 | const binaryOpcode = {
2219 | "+": Opcodes.f32_add,
2220 | "-": Opcodes.f32_sub,
2221 | "*": Opcodes.f32_mul,
2222 | "/": Opcodes.f32_div,
2223 | "==": Opcodes.f32_eq,
2224 | ">": Opcodes.f32_gt,
2225 | "<": Opcodes.f32_lt,
2226 | "&&": Opcodes.i32_and
2227 | };
2228 | // http://webassembly.github.io/spec/core/binary/modules.html#export-section
2229 | var ExportType;
2230 | (function (ExportType) {
2231 | ExportType[ExportType["func"] = 0] = "func";
2232 | ExportType[ExportType["table"] = 1] = "table";
2233 | ExportType[ExportType["mem"] = 2] = "mem";
2234 | ExportType[ExportType["global"] = 3] = "global";
2235 | })(ExportType || (ExportType = {}));
2236 | // http://webassembly.github.io/spec/core/binary/types.html#function-types
2237 | const functionType = 0x60;
2238 | const emptyArray = 0x0;
2239 | // https://webassembly.github.io/spec/core/binary/modules.html#binary-module
2240 | const magicModuleHeader = [0x00, 0x61, 0x73, 0x6d];
2241 | const moduleVersion = [0x01, 0x00, 0x00, 0x00];
2242 | // https://webassembly.github.io/spec/core/binary/conventions.html#binary-vec
2243 | // Vectors are encoded with their length followed by their element sequence
2244 | const encodeVector = (data) => [
2245 | ...encoding_1.unsignedLEB128(data.length),
2246 | ...flatten(data)
2247 | ];
2248 | // https://webassembly.github.io/spec/core/binary/modules.html#code-section
2249 | const encodeLocal = (count, type) => [
2250 | ...encoding_1.unsignedLEB128(count),
2251 | type
2252 | ];
2253 | // https://webassembly.github.io/spec/core/binary/modules.html#sections
2254 | // sections are encoded by their type followed by their vector contents
2255 | const createSection = (sectionType, data) => [
2256 | sectionType,
2257 | ...encodeVector(data)
2258 | ];
2259 | const codeFromProc = (node, program) => {
2260 | const code = [];
2261 | const symbols = new Map(node.args.map((arg, index) => [arg.value, index]));
2262 | const localIndexForSymbol = (name) => {
2263 | if (!symbols.has(name)) {
2264 | symbols.set(name, symbols.size);
2265 | }
2266 | return symbols.get(name);
2267 | };
2268 | const emitExpression = (node) => traverse_1.default(node, (node) => {
2269 | switch (node.type) {
2270 | case "numberLiteral":
2271 | code.push(Opcodes.f32_const);
2272 | code.push(...encoding_1.ieee754(node.value));
2273 | break;
2274 | case "identifier":
2275 | code.push(Opcodes.get_local);
2276 | code.push(...encoding_1.unsignedLEB128(localIndexForSymbol(node.value)));
2277 | break;
2278 | case "binaryExpression":
2279 | code.push(binaryOpcode[node.operator]);
2280 | break;
2281 | }
2282 | });
2283 | const emitStatements = (statements) => statements.forEach(statement => {
2284 | switch (statement.type) {
2285 | case "printStatement":
2286 | emitExpression(statement.expression);
2287 | code.push(Opcodes.call);
2288 | code.push(...encoding_1.unsignedLEB128(0));
2289 | break;
2290 | case "variableDeclaration":
2291 | emitExpression(statement.initializer);
2292 | code.push(Opcodes.set_local);
2293 | code.push(...encoding_1.unsignedLEB128(localIndexForSymbol(statement.name)));
2294 | break;
2295 | case "variableAssignment":
2296 | emitExpression(statement.value);
2297 | code.push(Opcodes.set_local);
2298 | code.push(...encoding_1.unsignedLEB128(localIndexForSymbol(statement.name)));
2299 | break;
2300 | case "whileStatement":
2301 | // outer block
2302 | code.push(Opcodes.block);
2303 | code.push(Blocktype.void);
2304 | // inner loop
2305 | code.push(Opcodes.loop);
2306 | code.push(Blocktype.void);
2307 | // compute the while expression
2308 | emitExpression(statement.expression);
2309 | code.push(Opcodes.i32_eqz);
2310 | // br_if $label0
2311 | code.push(Opcodes.br_if);
2312 | code.push(...encoding_1.signedLEB128(1));
2313 | // the nested logic
2314 | emitStatements(statement.statements);
2315 | // br $label1
2316 | code.push(Opcodes.br);
2317 | code.push(...encoding_1.signedLEB128(0));
2318 | // end loop
2319 | code.push(Opcodes.end);
2320 | // end block
2321 | code.push(Opcodes.end);
2322 | break;
2323 | case "ifStatement":
2324 | // if block
2325 | code.push(Opcodes.block);
2326 | code.push(Blocktype.void);
2327 | // compute the if expression
2328 | emitExpression(statement.expression);
2329 | code.push(Opcodes.i32_eqz);
2330 | // br_if $label0
2331 | code.push(Opcodes.br_if);
2332 | code.push(...encoding_1.signedLEB128(0));
2333 | // the nested logic
2334 | emitStatements(statement.consequent);
2335 | // end block
2336 | code.push(Opcodes.end);
2337 | // else block
2338 | code.push(Opcodes.block);
2339 | code.push(Blocktype.void);
2340 | // compute the if expression
2341 | emitExpression(statement.expression);
2342 | code.push(Opcodes.i32_const);
2343 | code.push(...encoding_1.signedLEB128(1));
2344 | code.push(Opcodes.i32_eq);
2345 | // br_if $label0
2346 | code.push(Opcodes.br_if);
2347 | code.push(...encoding_1.signedLEB128(0));
2348 | // the nested logic
2349 | emitStatements(statement.alternate);
2350 | // end block
2351 | code.push(Opcodes.end);
2352 | break;
2353 | case "callStatement":
2354 | if (statement.name === "setpixel") {
2355 | // compute and cache the setpixel parameters
2356 | emitExpression(statement.args[0]);
2357 | code.push(Opcodes.set_local);
2358 | code.push(...encoding_1.unsignedLEB128(localIndexForSymbol("x")));
2359 | emitExpression(statement.args[1]);
2360 | code.push(Opcodes.set_local);
2361 | code.push(...encoding_1.unsignedLEB128(localIndexForSymbol("y")));
2362 | emitExpression(statement.args[2]);
2363 | code.push(Opcodes.set_local);
2364 | code.push(...encoding_1.unsignedLEB128(localIndexForSymbol("color")));
2365 | // compute the offset (x * 100) + y
2366 | code.push(Opcodes.get_local);
2367 | code.push(...encoding_1.unsignedLEB128(localIndexForSymbol("y")));
2368 | code.push(Opcodes.f32_const);
2369 | code.push(...encoding_1.ieee754(100));
2370 | code.push(Opcodes.f32_mul);
2371 | code.push(Opcodes.get_local);
2372 | code.push(...encoding_1.unsignedLEB128(localIndexForSymbol("x")));
2373 | code.push(Opcodes.f32_add);
2374 | // convert to an integer
2375 | code.push(Opcodes.i32_trunc_f32_s);
2376 | // fetch the color
2377 | code.push(Opcodes.get_local);
2378 | code.push(...encoding_1.unsignedLEB128(localIndexForSymbol("color")));
2379 | code.push(Opcodes.i32_trunc_f32_s);
2380 | // write
2381 | code.push(Opcodes.i32_store_8);
2382 | code.push(...[0x00, 0x00]); // align and offset
2383 | }
2384 | else {
2385 | statement.args.forEach(arg => {
2386 | emitExpression(arg);
2387 | });
2388 | const index = program.findIndex(f => f.name === statement.name);
2389 | code.push(Opcodes.call);
2390 | code.push(...encoding_1.unsignedLEB128(index + 1));
2391 | }
2392 | break;
2393 | }
2394 | });
2395 | emitStatements(node.statements);
2396 | const localCount = symbols.size;
2397 | const locals = localCount > 0 ? [encodeLocal(localCount, Valtype.f32)] : [];
2398 | return encodeVector([...encodeVector(locals), ...code, Opcodes.end]);
2399 | };
2400 | exports.emitter = (ast) => {
2401 | // Function types are vectors of parameters and return types. Currently
2402 | // WebAssembly only supports single return values
2403 | const printFunctionType = [
2404 | functionType,
2405 | ...encodeVector([Valtype.f32]),
2406 | emptyArray
2407 | ];
2408 | // TODO: optimise - some of the procs might have the same type signature
2409 | const funcTypes = ast.map(proc => [
2410 | functionType,
2411 | ...encodeVector(proc.args.map(_ => Valtype.f32)),
2412 | emptyArray
2413 | ]);
2414 | // the type section is a vector of function types
2415 | const typeSection = createSection(Section.type, encodeVector([printFunctionType, ...funcTypes]));
2416 | // the function section is a vector of type indices that indicate the type of each function
2417 | // in the code section
2418 | const funcSection = createSection(Section.func, encodeVector(ast.map((_, index) => index + 1 /* type index */)));
2419 | // the import section is a vector of imported functions
2420 | const printFunctionImport = [
2421 | ...encoding_1.encodeString("env"),
2422 | ...encoding_1.encodeString("print"),
2423 | ExportType.func,
2424 | 0x00 // type index
2425 | ];
2426 | const memoryImport = [
2427 | ...encoding_1.encodeString("env"),
2428 | ...encoding_1.encodeString("memory"),
2429 | ExportType.mem,
2430 | /* limits https://webassembly.github.io/spec/core/binary/types.html#limits -
2431 | indicates a min memory size of one page */
2432 | 0x00,
2433 | 0x01
2434 | ];
2435 | const importSection = createSection(Section.import, encodeVector([printFunctionImport, memoryImport]));
2436 | // the export section is a vector of exported functions
2437 | const exportSection = createSection(Section.export, encodeVector([
2438 | [
2439 | ...encoding_1.encodeString("run"),
2440 | ExportType.func,
2441 | ast.findIndex(a => a.name === "main") + 1
2442 | ]
2443 | ]));
2444 | // the code section contains vectors of functions
2445 | const codeSection = createSection(Section.code, encodeVector(ast.map(a => codeFromProc(a, ast))));
2446 | return Uint8Array.from([
2447 | ...magicModuleHeader,
2448 | ...moduleVersion,
2449 | ...typeSection,
2450 | ...importSection,
2451 | ...funcSection,
2452 | ...exportSection,
2453 | ...codeSection
2454 | ]);
2455 | };
2456 |
2457 | },{"./encoding":7,"./traverse":12}],7:[function(require,module,exports){
2458 | (function (Buffer){
2459 | "use strict";
2460 | Object.defineProperty(exports, "__esModule", { value: true });
2461 | exports.ieee754 = (n) => {
2462 | const buf = Buffer.allocUnsafe(4);
2463 | buf.writeFloatLE(n, 0);
2464 | return Uint8Array.from(buf);
2465 | };
2466 | exports.encodeString = (str) => [
2467 | str.length,
2468 | ...str.split("").map(s => s.charCodeAt(0))
2469 | ];
2470 | exports.signedLEB128 = (n) => {
2471 | const buffer = [];
2472 | let more = true;
2473 | while (more) {
2474 | let byte = n & 0x7f;
2475 | n >>>= 7;
2476 | if ((n === 0 && (byte & 0x40) === 0) || (n === -1 && (byte & 0x40) !== 0)) {
2477 | more = false;
2478 | }
2479 | else {
2480 | byte |= 0x80;
2481 | }
2482 | buffer.push(byte);
2483 | }
2484 | return buffer;
2485 | };
2486 | exports.unsignedLEB128 = (n) => {
2487 | const buffer = [];
2488 | do {
2489 | let byte = n & 0x7f;
2490 | n >>>= 7;
2491 | if (n !== 0) {
2492 | byte |= 0x80;
2493 | }
2494 | buffer.push(byte);
2495 | } while (n !== 0);
2496 | return buffer;
2497 | };
2498 |
2499 | }).call(this,require("buffer").Buffer)
2500 | },{"buffer":3}],8:[function(require,module,exports){
2501 | "use strict";
2502 | Object.defineProperty(exports, "__esModule", { value: true });
2503 | const tokenizer_1 = require("./tokenizer");
2504 | const parser_1 = require("./parser");
2505 | const transformer_1 = require("./transformer");
2506 | const applyOperator = (operator, left, right) => {
2507 | switch (operator) {
2508 | case "+":
2509 | return left + right;
2510 | case "-":
2511 | return left - right;
2512 | case "*":
2513 | return left * right;
2514 | case "/":
2515 | return left / right;
2516 | case "==":
2517 | return left == right ? 1 : 0;
2518 | case ">":
2519 | return left > right ? 1 : 0;
2520 | case "<":
2521 | return left < right ? 1 : 0;
2522 | case "&&":
2523 | return left && right;
2524 | }
2525 | throw Error(`Unknown binary operator ${operator}`);
2526 | };
2527 | const executeProc = (node, env, program, args = []) => {
2528 | const symbols = new Map(node.args.map((arg, index) => [arg.value, args[index]]));
2529 | const evaluateExpression = (expression) => {
2530 | switch (expression.type) {
2531 | case "numberLiteral":
2532 | return expression.value;
2533 | case "binaryExpression":
2534 | return applyOperator(expression.operator, evaluateExpression(expression.left), evaluateExpression(expression.right));
2535 | case "identifier":
2536 | return symbols.get(expression.value);
2537 | }
2538 | };
2539 | const executeStatements = (statements) => {
2540 | statements.forEach(statement => {
2541 | switch (statement.type) {
2542 | case "printStatement":
2543 | env.print(evaluateExpression(statement.expression));
2544 | break;
2545 | case "variableDeclaration":
2546 | symbols.set(statement.name, evaluateExpression(statement.initializer));
2547 | break;
2548 | case "variableAssignment":
2549 | symbols.set(statement.name, evaluateExpression(statement.value));
2550 | break;
2551 | case "whileStatement":
2552 | while (evaluateExpression(statement.expression)) {
2553 | executeStatements(statement.statements);
2554 | }
2555 | break;
2556 | case "ifStatement":
2557 | if (evaluateExpression(statement.expression)) {
2558 | executeStatements(statement.consequent);
2559 | }
2560 | else {
2561 | executeStatements(statement.alternate);
2562 | }
2563 | break;
2564 | case "callStatement":
2565 | if (statement.name === "setpixel") {
2566 | const x = evaluateExpression(statement.args[0]);
2567 | const y = evaluateExpression(statement.args[1]);
2568 | const color = evaluateExpression(statement.args[2]);
2569 | env.display[y * 100 + x] = color;
2570 | }
2571 | else {
2572 | const procName = statement.name;
2573 | const argValues = statement.args.map(arg => evaluateExpression(arg));
2574 | const proc = program.find(f => f.name === procName);
2575 | executeProc(proc, env, program, argValues);
2576 | }
2577 | break;
2578 | }
2579 | });
2580 | };
2581 | executeStatements(node.statements);
2582 | };
2583 | exports.runtime = async (src, env) => () => {
2584 | const tokens = tokenizer_1.tokenize(src);
2585 | const program = parser_1.parse(tokens);
2586 | const transformedProgram = transformer_1.transformer(program);
2587 | const main = transformedProgram.find(f => f.name === "main");
2588 | executeProc(main, env, transformedProgram);
2589 | };
2590 |
2591 | },{"./parser":9,"./tokenizer":10,"./transformer":11}],9:[function(require,module,exports){
2592 | "use strict";
2593 | Object.defineProperty(exports, "__esModule", { value: true });
2594 | class ParserError extends Error {
2595 | constructor(message, token) {
2596 | super(message);
2597 | this.token = token;
2598 | }
2599 | }
2600 | exports.ParserError = ParserError;
2601 | const asOperator = (value) => {
2602 | // TODO: check it really is an operator
2603 | return value;
2604 | };
2605 | exports.parse = tokens => {
2606 | const tokenIterator = tokens[Symbol.iterator]();
2607 | let currentToken = tokenIterator.next().value;
2608 | let nextToken = tokenIterator.next().value;
2609 | const currentTokenIsKeyword = (name) => currentToken.value === name && currentToken.type === "keyword";
2610 | const eatToken = (value) => {
2611 | if (value && value !== currentToken.value) {
2612 | throw new ParserError(`Unexpected token value, expected ${value}, received ${currentToken.value}`, currentToken);
2613 | }
2614 | currentToken = nextToken;
2615 | nextToken = tokenIterator.next().value;
2616 | };
2617 | const parseExpression = () => {
2618 | let node;
2619 | switch (currentToken.type) {
2620 | case "number":
2621 | node = {
2622 | type: "numberLiteral",
2623 | value: Number(currentToken.value)
2624 | };
2625 | eatToken();
2626 | return node;
2627 | case "identifier":
2628 | node = { type: "identifier", value: currentToken.value };
2629 | eatToken();
2630 | return node;
2631 | case "parens":
2632 | eatToken("(");
2633 | const left = parseExpression();
2634 | const operator = currentToken.value;
2635 | eatToken();
2636 | const right = parseExpression();
2637 | eatToken(")");
2638 | return {
2639 | type: "binaryExpression",
2640 | left,
2641 | right,
2642 | operator: asOperator(operator)
2643 | };
2644 | default:
2645 | throw new ParserError(`Unexpected token type ${currentToken.type}`, currentToken);
2646 | }
2647 | };
2648 | const parsePrintStatement = () => {
2649 | eatToken("print");
2650 | return {
2651 | type: "printStatement",
2652 | expression: parseExpression()
2653 | };
2654 | };
2655 | const parseIfStatement = () => {
2656 | eatToken("if");
2657 | const expression = parseExpression();
2658 | let elseStatements = false;
2659 | const consequent = [];
2660 | const alternate = [];
2661 | while (!currentTokenIsKeyword("endif")) {
2662 | if (currentTokenIsKeyword("else")) {
2663 | eatToken("else");
2664 | elseStatements = true;
2665 | }
2666 | if (elseStatements) {
2667 | alternate.push(parseStatement());
2668 | }
2669 | else {
2670 | consequent.push(parseStatement());
2671 | }
2672 | }
2673 | eatToken("endif");
2674 | return { type: "ifStatement", expression, consequent, alternate };
2675 | };
2676 | const parseWhileStatement = () => {
2677 | eatToken("while");
2678 | const expression = parseExpression();
2679 | const statements = [];
2680 | while (!currentTokenIsKeyword("endwhile")) {
2681 | statements.push(parseStatement());
2682 | }
2683 | eatToken("endwhile");
2684 | return { type: "whileStatement", expression, statements };
2685 | };
2686 | const parseVariableAssignment = () => {
2687 | const name = currentToken.value;
2688 | eatToken();
2689 | eatToken("=");
2690 | return { type: "variableAssignment", name, value: parseExpression() };
2691 | };
2692 | const parseVariableDeclarationStatement = () => {
2693 | eatToken("var");
2694 | const name = currentToken.value;
2695 | eatToken();
2696 | eatToken("=");
2697 | return {
2698 | type: "variableDeclaration",
2699 | name,
2700 | initializer: parseExpression()
2701 | };
2702 | };
2703 | const parseCallStatementNode = () => {
2704 | const name = currentToken.value;
2705 | eatToken();
2706 | const args = parseCommaSeperatedList(() => parseExpression());
2707 | return {
2708 | type: "callStatement",
2709 | name,
2710 | args
2711 | };
2712 | };
2713 | function parseCommaSeperatedList(foo) {
2714 | const args = [];
2715 | eatToken("(");
2716 | while (currentToken.value !== ")") {
2717 | args.push(foo());
2718 | if (currentToken.value !== ")") {
2719 | eatToken(",");
2720 | }
2721 | }
2722 | eatToken(")");
2723 | return args;
2724 | }
2725 | const parseProcStatement = () => {
2726 | eatToken("proc");
2727 | const name = currentToken.value;
2728 | eatToken();
2729 | const args = parseCommaSeperatedList(() => {
2730 | const arg = { type: "identifier", value: currentToken.value };
2731 | eatToken();
2732 | return arg;
2733 | });
2734 | const statements = [];
2735 | while (!currentTokenIsKeyword("endproc")) {
2736 | statements.push(parseStatement());
2737 | }
2738 | eatToken("endproc");
2739 | return {
2740 | type: "procStatement",
2741 | name,
2742 | args,
2743 | statements
2744 | };
2745 | };
2746 | const parseStatement = () => {
2747 | if (currentToken.type === "keyword") {
2748 | switch (currentToken.value) {
2749 | case "print":
2750 | return parsePrintStatement();
2751 | case "var":
2752 | return parseVariableDeclarationStatement();
2753 | case "while":
2754 | return parseWhileStatement();
2755 | case "if":
2756 | return parseIfStatement();
2757 | case "proc":
2758 | return parseProcStatement();
2759 | default:
2760 | throw new ParserError(`Unknown keyword ${currentToken.value}`, currentToken);
2761 | }
2762 | }
2763 | else if (currentToken.type === "identifier") {
2764 | if (nextToken.value === "=") {
2765 | return parseVariableAssignment();
2766 | }
2767 | else {
2768 | return parseCallStatementNode();
2769 | }
2770 | }
2771 | };
2772 | const nodes = [];
2773 | while (currentToken) {
2774 | nodes.push(parseStatement());
2775 | }
2776 | return nodes;
2777 | };
2778 |
2779 | },{}],10:[function(require,module,exports){
2780 | "use strict";
2781 | Object.defineProperty(exports, "__esModule", { value: true });
2782 | exports.keywords = [
2783 | "print",
2784 | "var",
2785 | "while",
2786 | "endwhile",
2787 | "if",
2788 | "endif",
2789 | "else",
2790 | "proc",
2791 | "endproc"
2792 | ];
2793 | exports.operators = ["+", "-", "*", "/", "==", "<", ">", "&&", ","];
2794 | const escapeRegEx = (text) => text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
2795 | class TokenizerError extends Error {
2796 | constructor(message, index) {
2797 | super(message);
2798 | this.index = index;
2799 | }
2800 | }
2801 | exports.TokenizerError = TokenizerError;
2802 | // returns a token if the given regex matches at the current index
2803 | const regexMatcher = (regex, type) => (input, index) => {
2804 | const match = input.substring(index).match(regex);
2805 | return (match && {
2806 | type,
2807 | value: match[0]
2808 | });
2809 | };
2810 | // matchers in precedence order
2811 | const matchers = [
2812 | regexMatcher("^-?[.0-9]+([eE]-?[0-9]{2})?", "number"),
2813 | regexMatcher(`^(${exports.keywords.join("|")})`, "keyword"),
2814 | regexMatcher("^\\s+", "whitespace"),
2815 | regexMatcher(`^(${exports.operators.map(escapeRegEx).join("|")})`, "operator"),
2816 | regexMatcher(`^[a-zA-Z]+`, "identifier"),
2817 | regexMatcher(`^=`, "assignment"),
2818 | regexMatcher("^[()]{1}", "parens")
2819 | ];
2820 | const locationForIndex = (input, index) => ({
2821 | char: index - input.lastIndexOf("\n", index) - 1,
2822 | line: input.substring(0, index).split("\n").length - 1
2823 | });
2824 | exports.tokenize = input => {
2825 | const tokens = [];
2826 | let index = 0;
2827 | while (index < input.length) {
2828 | const matches = matchers.map(m => m(input, index)).filter(f => f);
2829 | if (matches.length > 0) {
2830 | // take the highest priority match
2831 | const match = matches[0];
2832 | if (match.type !== "whitespace") {
2833 | tokens.push(Object.assign({}, match, locationForIndex(input, index)));
2834 | }
2835 | index += match.value.length;
2836 | }
2837 | else {
2838 | throw new TokenizerError(`Unexpected token ${input.substring(index, index + 1)}`, index);
2839 | }
2840 | }
2841 | return tokens;
2842 | };
2843 |
2844 | },{}],11:[function(require,module,exports){
2845 | "use strict";
2846 | Object.defineProperty(exports, "__esModule", { value: true });
2847 | exports.transformer = (ast) => {
2848 | // do we have a main proc?
2849 | if (!ast.find(a => a.type === "procStatement" && a.name === "main")) {
2850 | // if not - collect up any 'free' statements and add one.
2851 | const freeStatements = ast.filter(a => a.type !== "procStatement");
2852 | const mainProc = {
2853 | type: "procStatement",
2854 | name: "main",
2855 | args: [],
2856 | statements: freeStatements
2857 | };
2858 | ast = [mainProc, ...ast.filter(a => a.type === "procStatement")];
2859 | }
2860 | return ast.map(a => a);
2861 | };
2862 |
2863 | },{}],12:[function(require,module,exports){
2864 | "use strict";
2865 | Object.defineProperty(exports, "__esModule", { value: true });
2866 | // post order ast walker
2867 | const traverse = (nodes, visitor) => {
2868 | nodes = Array.isArray(nodes) ? nodes : [nodes];
2869 | nodes.forEach(node => {
2870 | Object.keys(node).forEach((prop) => {
2871 | const value = node[prop];
2872 | const valueAsArray = Array.isArray(value) ? value : [value];
2873 | valueAsArray.forEach((childNode) => {
2874 | if (typeof childNode.type === "string") {
2875 | traverse(childNode, visitor);
2876 | }
2877 | });
2878 | });
2879 | visitor(node);
2880 | });
2881 | };
2882 | exports.default = traverse;
2883 |
2884 | },{}]},{},[1]);
2885 |
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
33 |
34 |
35 |
36 |
37 |
39 |
41 |
43 |
44 |
45 |
46 |
47 |
48 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
Share your playground code ...
74 |
77 |
78 |
79 |
87 |
88 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 | Code
99 |
128 |
129 |
130 | Console output
131 |
137 |
138 |
139 | Canvas output
140 |
141 |
142 |
143 |
144 |
145 |
chasm is a very simple programming language which I developed to accompany a talk at
146 | FullStack Conference NYC. It is not intended to be a fully featured language; rather, its purpose is two-fold:
147 |
148 |
149 |
150 |
Introduce the basic building blocks of compilers - and show that they aren't that scary or difficult!
151 |
Reveal some of the inner working of WebAssembly, a new and exciting language / runtime that I think people need to
152 | know more about.
153 |
154 |
155 |
156 |
The chasm compiler is written in TypeScript, you can try it out using the above editor. When you click either of the 'run' buttons above, the code is tokenised then parsed into an Abstract Syntax Tree (AST). If you use the interpreter this AST is executed by a JavaScript interpreter. If you use the compiler, this AST is compiled to a WebAssembly module then executed via the browser's WebAssembly runtime.
157 |