├── .github
└── FUNDING.yml
├── .gitignore
├── LICENSE
├── README.md
├── dist
├── compiler.js
├── compiler.js.map
├── main.js
├── main.js.map
├── main.lite.js
└── main.lite.js.map
├── package-lock.json
├── package.json
├── src
├── AbstractQuantumScript.js
├── api.compiler.global.js
├── api.global.js
├── api.global.lite.js
├── compiler
│ ├── $qDownstream.js
│ ├── $qIdentifier.js
│ ├── Compiler.js
│ ├── Node.js
│ ├── Parser.js
│ ├── Scope.js
│ └── index.js
├── index.js
├── index.lite.js
├── params.js
├── runtime
│ ├── AutoAsyncIterator.js
│ ├── AutoIterator.js
│ ├── Autorun.js
│ ├── EventTarget.js
│ ├── Runtime.js
│ ├── Scope.js
│ ├── Signal.js
│ ├── State.js
│ ├── hot-module-registry.js
│ └── index.js
└── util.js
└── test
├── ast.test.driver.js
├── ast.test.obsolete.js
├── behaviour.test.js
└── m.js
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: ox-harris # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: webqit
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .*
2 | !/.gitignore
3 | node_modules
4 | src2
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2022-present, WebQit, Inc.
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
13 | all 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
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Quantum JS
2 |
3 | [![npm version][npm-version-src]][npm-version-href]
4 | [![bundle][bundle-src]][bundle-href]
5 | [![License][license-src]][license-href]
6 |
7 | [Overview](#overview) • [Creating Quantum Programs](#creating-quantum-programs) • [Implementation](#implementation) • [Examples](#examples) • [License](#license)
8 |
9 | Quantum JS is a runtime extension to JavaScript that brings Imperative Reactive Programming to JavaScript!
10 |
11 | What's that?
12 |
13 | ## Overview
14 |
15 | Where you normally would require certain reactive primitives to express reactive logic...
16 |
17 | ```js
18 | // Import reactive primitives
19 | import { createSignal, createMemo, createEffect } from 'solid-js';
20 |
21 | // Declare values
22 | const [ count, setCount ] = createSignal(5);
23 | const doubleCount = createMemo(() => count() * 2);
24 | // Log this value live
25 | createEffect(() => {
26 | console.log(doubleCount());
27 | });
28 | ```
29 |
30 | ```js
31 | // Setup periodic updates
32 | setInterval(() => setCount(10), 1000);
33 | ```
34 |
35 | Quantum JS lets you acheive the same in the ordinary imperative form of the language:
36 |
37 | ```js
38 | // Declare values
39 | let count = 5;
40 | let doubleCount = count * 2;
41 | // Log this value live
42 | console.log(doubleCount);
43 | ```
44 |
45 | ```js
46 | // Setup periodic updates
47 | setInterval(() => count = 10, 1000);
48 | ```
49 |
50 | Wanna play?:
51 |
52 | 1. Add the following script to your page:
53 |
54 | ```html
55 |
56 | ```
57 |
58 | 2. Write your logic within a `quantum` script tag:
59 |
60 | ```html
61 |
71 | ```
72 |
73 | 3. Watch your console. Have fun.
74 |
75 | Wanna see how magical things really are here? Update your step 2 to split the logic into two separate scripts:
76 |
77 | 2. One ordinary script and one quantum script:
78 |
79 | ```html
80 |
87 | ```
88 |
89 | ```html
90 |
94 | ```
95 |
96 | Watching your console? Reactivity is still intact!
97 |
98 | That reactivity is really happening within the Quantum script! It's a regular script in every way except that any peice of code thrown in is able to statically reflect changes to state in granular details!
99 |
100 | To define, Quantum programs are an extension to JavaScript that has any piece of code stay sensitive to changes in the most fine-grained details - and entirely with no moving parts!
101 |
102 | Now, while that is the `` part of the HTML page above, there are many different ways to have this form of reactivity play out. Examples are [just ahead](#examples).
103 |
104 | This project pursues a futuristic, more efficient way to write reactive applocations *today*! And it occupies [a new category](https://en.wikipedia.org/wiki/Reactive_programming#Imperative) in the reactivity spectrum!
105 |
106 |
137 |
138 | ## Implementation
139 |
140 | As seen above, you can have all of Quantum JS live in the browser!
141 |
142 | Up there, we've used a version of the Quantum JS implementation that supports HTML `
151 | ```
152 |
153 | └ This is to be placed early on in the document and should be a classic script without any `defer` or `async` directives!
154 |
155 | ```js
156 | // Destructure from the webqit namespace
157 | const { QuantumFunction, AsyncQuantumFunction, QuantumScript, QuantumModule, State, Observer } = window.webqit;
158 | ```
159 |
160 |
161 |
162 | Install from NPM
163 | └───────── 
164 |
165 | ```js
166 | // npm install
167 | npm i @webqit/quantum-js
168 | ```
169 |
170 | ```js
171 | // Import API
172 | import { QuantumFunction, AsyncQuantumFunction, QuantumScript, AsyncQuantumScript, QuantumModule, State, Observer } from '@webqit/quantum-js';
173 | ```
174 |
175 |
176 |
177 |
178 |
179 | ### Quantum JS Lite
180 |
181 | It is possible to use a lighter version of Quantum JS where you want something further feather weight for your initial application load.
182 |
183 |
184 | Load from a CDN
185 | └───────── 
186 |
187 | ```html
188 |
189 | ```
190 |
191 | └ This is to be placed early on in the document and should be a classic script without any `defer` or `async` directives!
192 |
193 | ```js
194 | // Destructure from the webqit namespace
195 | const { AsyncQuantumFunction, AsyncQuantumScript, QuantumModule, State, Observer } = window.webqit;
196 | ```
197 |
198 | Additional details
199 |
200 | The Lite APIs initially come without the compiler and yet lets you work with Quantum JS ahead of that. Additionally, these APIs are able to do their compilation off the main thread by getting the Quantum JS compiler loaded into a [Web Worker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers)!
201 |
202 | > But if you may, the Quantum JS Compiler is all still loadable directly - as if short-circuiting the lazy-loading strategy of the Lite APIs:
203 | >
204 | > ```html
205 | >
206 | >
207 | >
208 | >
209 | > ```
210 |
211 |
212 |
213 |
214 |
215 | Install from NPM
216 | └───────── 
217 |
218 | ```js
219 | // npm install
220 | npm i @webqit/quantum-js
221 | ```
222 |
223 | ```js
224 | // Import Lite API
225 | import { AsyncQuantumFunction, AsyncQuantumScript, QuantumModule, State, Observer } from '@webqit/quantum-js/lite';
226 | ```
227 |
228 |
229 |
230 | ## Creating Quantum Programs
231 |
232 | You can write Quantum programs in either of two ways: as "Quantum Functions" and as "Quantum Scripts"!
233 |
234 | ### Quantum Functions
235 |
236 | Here, we introduce a new type of function that works like any other JavaScript function but in reactive mode. This function may be wrtten in any of the forms below:
237 |
238 | #### Syntax 1: Using the `quantum` Function keyword
239 |
240 | > Available since v4.3.
241 |
242 | Here you prepend your function with the `quantum` keyword, just in how you use the `async` keyword:
243 |
244 | ```js
245 | // Quantum function declaration
246 | quantum function bar() {
247 | let count = 5;
248 | let doubleCount = count * 2;
249 | console.log(doubleCount);
250 | }
251 | bar();
252 | ```
253 |
254 | ```js
255 | // Async quantum function declaration
256 | async quantum function bar() {
257 | let count = await 5;
258 | let doubleCount = count * 2;
259 | console.log(doubleCount);
260 | }
261 | await bar();
262 | ```
263 |
264 | Show more syntax examples
265 |
266 | ```js
267 | // Quantum function expression
268 | const bar = quantum function() {
269 | }
270 | const bar = async quantum function() {
271 | }
272 | ```
273 |
274 | ```js
275 | // Quantum object property
276 | const foo = {
277 | bar: quantum function() { ... },
278 | }
279 | const foo = {
280 | bar: async quantum function() { ... },
281 | }
282 | ```
283 |
284 | ```js
285 | // Quantum object method
286 | const foo = {
287 | quantum bar() { ... },
288 | }
289 | const foo = {
290 | async quantum bar() { ... },
291 | }
292 | ```
293 |
294 | ```js
295 | // Quantum class method
296 | class Foo {
297 | quantum bar() { ... }
298 | }
299 | class Foo {
300 | async quantum bar() { ... }
301 | }
302 | ```
303 |
304 | ```js
305 | // Quantum arrow function expression
306 | const bar = quantum () => {
307 | }
308 | const bar = async quantum () => {
309 | }
310 | ```
311 |
312 | ```js
313 | // Quantum arrow function expression
314 | const bar = quantum arg => {
315 | }
316 | const bar = async quantum arg => {
317 | }
318 | ```
319 |
320 |
321 |
322 | Show polyfill support
323 |
324 | This syntax is universally supported both within:
325 |
326 | + Quantum JS' dynamic APIs:
327 |
328 | ```js
329 | const program = new QuantumFunction(`
330 | // External dependency
331 | let externalVar = 10;
332 |
333 | // QuantumFunction
334 | quantum function sum(a, b) {
335 | return a + b + externalVar;
336 | }
337 | const state = sum(10, 10);
338 |
339 | // Inspect
340 | console.log(state.value); // 30
341 | `);
342 | program();
343 | ```
344 |
345 | + and inline `
361 | ```
362 |
363 |
364 |
365 | #### Syntax 2: Using the Double Star `**` Notation
366 |
367 | Here you append your function with the double star `**` notation, much like how you write [generator functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator):
368 |
369 | ```js
370 | // Quantum function declaration
371 | function** bar() {
372 | let count = 5;
373 | let doubleCount = count * 2;
374 | console.log(doubleCount);
375 | }
376 | bar();
377 | ```
378 |
379 | ```js
380 | // Async quantum function declaration
381 | async function** bar() {
382 | let count = await 5;
383 | let doubleCount = count * 2;
384 | console.log(doubleCount);
385 | }
386 | await bar();
387 | ```
388 |
389 | Show more syntax examples
390 |
391 | ```js
392 | // Quantum function expression
393 | const bar = function** () {
394 | }
395 | const bar = async function** () {
396 | }
397 | ```
398 |
399 | ```js
400 | // Quantum object property
401 | const foo = {
402 | bar: function** () { ... },
403 | }
404 | const foo = {
405 | bar: async function** () { ... },
406 | }
407 | ```
408 |
409 | ```js
410 | // Quantum object method
411 | const foo = {
412 | **bar() { ... },
413 | }
414 | const foo = {
415 | async **bar() { ... },
416 | }
417 | ```
418 |
419 | ```js
420 | // Quantum class method, optionally async
421 | class Foo {
422 | **bar() { ... }
423 | }
424 | class Foo {
425 | async **bar() { ... }
426 | }
427 | ```
428 |
429 |
430 |
431 | Show polyfill support
432 |
433 | This syntax is universally supported both within:
434 |
435 | + Quantum JS' dynamic APIs:
436 |
437 | ```js
438 | const program = new QuantumFunction(`
439 | // External dependency
440 | let externalVar = 10;
441 |
442 | // QuantumFunction
443 | function** sum(a, b) {
444 | return a + b + externalVar;
445 | }
446 | const state = sum(10, 10);
447 |
448 | // Inspect
449 | console.log(state.value); // 30
450 | `);
451 | program();
452 | ```
453 |
454 | + and inline `
470 | ```
471 |
472 |
473 |
474 | #### Syntax 3: Using Quantum Function Constructors
475 |
476 | Here you use special function constructors to create a new Quantum function:
477 |
478 | ```js
479 | // Quantum function constructor
480 | const bar = QuantumFunction(`
481 | let count = 5;
482 | let doubleCount = count * 2;
483 | console.log(doubleCount);
484 | `);
485 | bar();
486 | ```
487 |
488 | ```js
489 | // Async quantum function constructor
490 | const bar = AsyncQuantumFunction(`
491 | let count = await 5;
492 | let doubleCount = count * 2;
493 | console.log(doubleCount);
494 | `);
495 | await bar();
496 | ```
497 |
498 | Show more syntax examples
499 |
500 | ```js
501 | // With function parameters
502 | const bar = QuantumFunction( param1, ... paramN, functionBody );
503 | ```
504 |
505 | ```js
506 | // With the new keyword
507 | const bar = new QuantumFunction( param1, ... paramN, functionBody );
508 | ```
509 |
510 | ```js
511 | // As class property
512 | class Foo {
513 | bar = QuantumFunction( param1, ... paramN, functionBody );
514 | }
515 | ```
516 |
517 |
518 |
519 | Show polyfill support
520 |
521 | This is how you obtain the APIs:
522 |
523 | ```js
524 | // Import API
525 | import { QuantumFunction, AsyncQuantumFunction } from '@webqit/quantum-js';
526 | ```
527 |
528 | ```js
529 | const { QuantumFunction, AsyncQuantumFunction } = window.webqit;
530 | ```
531 |
532 | Here, the difference between `QuantumFunction` and `AsyncQuantumFunction` is same as the difference between a regular synchronous JS function (`function() {}`) and its *async* equivalent (`async function() {}`).
533 |
534 | ```js
535 | // External dependency
536 | globalThis.externalVar = 10;
537 |
538 | // QuantumFunction
539 | const sum = QuantumFunction(`a`, `b`, `
540 | return a + b + externalVar;
541 | `);
542 | const state = sum(10, 10);
543 |
544 | // Inspect
545 | console.log(state.value); // 30
546 | ```
547 |
548 | > Note that, unlike the main Quantum JS build, the Quantum JS Lite edition only implements the `AsyncQuantumFunction` API which falls within the asynchronous operation of the Lite edition.
549 |
550 |
551 |
552 | Additional details
553 |
554 | Note that unlike normal function declarations and expressions that can see their surrounding scope, as in syntaxes 1 and 2 above, code in [function constructors](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/Function) is only able to see the global scope:
555 |
556 | ```js
557 | let a;
558 | globalThis.b = 2;
559 | var c = 'c'; // Equivalent to globalThis.c = 'c' assuming that we aren't running in a function scope or module scope
560 | const bar = QuantumFunction(`
561 | console.log(typeof a); // undefined
562 | console.log(typeof b); // number
563 | console.log(typeof c); // string
564 | `);
565 | bar();
566 | ```
567 |
568 |
569 |
570 | ### Quantum Scripts (Whole Programs)
571 |
572 | Here, whole programs are able to run in *quantum* execution mode using special scripting APIs:
573 |
574 | ```js
575 | // Quantum regular JS
576 | const program = new QuantumScript(`
577 | let count = 5;
578 | let doubleCount = count * 2;
579 | console.log(doubleCount);
580 | `);
581 | program.execute();
582 | ```
583 |
584 | ```js
585 | // Quantum module
586 | const program = new QuantumModule(`
587 | let count = await 5;
588 | let doubleCount = count * 2;
589 | console.log(doubleCount);
590 | `);
591 | await program.execute();
592 | ```
593 |
594 | These will run in the global scope!
595 |
596 | The latter does certainly let you use `import` and `export` statements!
597 |
598 | Exanple
599 |
600 | ```js
601 | // Quantum module
602 | const program = new QuantumModule(`
603 | import module1, { module2 } from 'package-name';
604 | import { module3 as alias } from 'package-name';
605 | ...
606 | export * from 'package-name';
607 | export let localVar = 0;
608 | `);
609 | ```
610 |
611 |
612 |
613 | Show polyfill support
614 |
615 | This is how you obtain the APIs:
616 |
617 | ```js
618 | // Import API
619 | import { QuantumScript, QuantumModule, AsyncQuantumScript } from '@webqit/quantum-js';
620 | ```
621 |
622 | ```js
623 | const { QuantumScript, QuantumModule, AsyncQuantumScript } = window.webqit;
624 | ```
625 |
626 | Here, the difference between `QuantumScript`, `AsyncQuantumScript`, and `QuantumModule` is same as the difference between a regular synchronous script element (`