diff options
| author | Marshall Lochbaum <mwlochbaum@gmail.com> | 2021-04-15 22:03:37 -0400 |
|---|---|---|
| committer | Marshall Lochbaum <mwlochbaum@gmail.com> | 2021-04-15 22:03:37 -0400 |
| commit | bbe589b136df82a3e0a6e0801b33218c49105fb6 (patch) | |
| tree | 57fd8676fbbf48f36722609f5dfac91d1a416df4 | |
| parent | 5cdd24de4d8d50d10ef000d46772f7bd488e9357 (diff) | |
Move executable to bqn.js so the online REPL doesn't have to load lots of node-specific code
| -rwxr-xr-x | bqn.js | 59 | ||||
| -rw-r--r--[-rwxr-xr-x] | docs/bqn.js | 55 | ||||
| -rw-r--r-- | docs/running.html | 2 | ||||
| -rw-r--r-- | running.md | 2 |
4 files changed, 62 insertions, 56 deletions
@@ -0,0 +1,59 @@ +#! /usr/bin/env node + +"use strict"; +let path = require('path'); +let fs = require('fs'); + +let bqn = require("./docs/bqn.js"); +let {fmt,fmtErr,sysvals}=bqn; +let {has,list,str,unstr,dynsys,req1str}=bqn.util; + +let show = x => console.log(fmt(x)); +sysvals.show = (x,w) => { show(x); return x; }; +sysvals.out = (x,w) => { console.log(req1str("•Out",x,w)); return x; }; + +let getres = e => { + let p = sysvals.path; + if (p) { p=unstr(p); return f=>path.resolve(p,f); } + return f => { if (!path.isAbsolute(f)) throw Error(e+": Paths must be absolute when not running from a file"); return f; }; +} +let withres = (e,fn) => dynsys(() => fn(getres(e))); +let ff = (e,fr,fw,o) => withres(e, resolve => (x,w) => { + let f = resolve(req1str(e,has(w)?w:x)); + if (has(w)) { fs.writeFileSync(f,fw(x),o); return str(f); } + else { return fr(fs.readFileSync(f,o)); } +}); +sysvals.fchars = ff("•FChars",str,unstr,"utf-8"); +sysvals.flines = ff("•FLines",s=>list(s.split('\n').map(str)),s=>s.map(unstr).join('\n'),"utf-8"); +sysvals.fbytes = ff("•FBytes",s=>list(Array.from(s).map(c=>String.fromCodePoint(c))),s=>Buffer.from(s.map(c=>c.codePointAt(0)))); +let bqn_state = sysvals.bqn = (x,w) => { + w = w||[]; + sysvals.path=w[0]; sysvals.name=w[1]; sysvals.args=w[2]; + return bqn(x); +} +sysvals.bqn = (x,w) => bqn_state(req1str("•BQN",x), w); +let bqn_file = (f,t,w) => bqn_state( + t, [ str(path.resolve(f,'..')+'/'), str(path.basename(f)), w ] +); +sysvals.import = withres("•Import", resolve => (x,w) => { + let f = resolve(req1str("•Import",x)); + return bqn_file(f, fs.readFileSync(f,'utf-8'), w); +}); + +if (!module.parent) { + let args = process.argv.slice(2); + let arg0 = args[0]; + let exec = fn => src => { + try { + fn(src); + } catch(e) { + console.error('[31m'+fmtErr(Array.from(src),e)+'[39m'); + } + } + if (arg0[0] !== '-' || (arg0==='-f'&&(arg0=(args=args.slice(1))[0],1))) { + let f=arg0, a=list(args.slice(1).map(str)); + exec(s=>bqn_file(f,s,a))(fs.readFileSync(f,'utf-8')); + } else if (arg0 === '-e') { + args.slice(1).map(exec(s=>show(bqn_state(s)))); + } +} diff --git a/docs/bqn.js b/docs/bqn.js index 320830fb..54141cf0 100755..100644 --- a/docs/bqn.js +++ b/docs/bqn.js @@ -1,5 +1,3 @@ -#! /usr/bin/env node - "use strict"; // Virtual machine let has = x => x!==undefined; @@ -362,57 +360,6 @@ if (typeof process!=='undefined') { if (typeof module!=='undefined') { // Node.js bqn.fmt=fmt; bqn.fmtErr=fmtErr; bqn.compile=compile; bqn.run=run; + bqn.sysvals=sysvals; bqn.util={has,list,str,unstr,dynsys,req1str}; module.exports=bqn; - - let show = x => console.log(fmt(x)); - sysvals.show = (x,w) => { show(x); return x; }; - sysvals.out = (x,w) => { console.log(req1str("•Out",x,w)); return x; }; - - let path = require('path'); - let fs = require('fs'); - let getres = e => { - let p = sysvals.path; - if (p) { p=unstr(p); return f=>path.resolve(p,f); } - return f => { if (!path.isAbsolute(f)) throw Error(e+": Paths must be absolute when not running from a file"); return f; }; - } - let withres = (e,fn) => dynsys(() => fn(getres(e))); - let ff = (e,fr,fw,o) => withres(e, resolve => (x,w) => { - let f = resolve(req1str(e,has(w)?w:x)); - if (has(w)) { fs.writeFileSync(f,fw(x),o); return str(f); } - else { return fr(fs.readFileSync(f,o)); } - }); - sysvals.fchars = ff("•FChars",str,unstr,"utf-8"); - sysvals.flines = ff("•FLines",s=>list(s.split('\n').map(str)),s=>s.map(unstr).join('\n'),"utf-8"); - sysvals.fbytes = ff("•FBytes",s=>list(Array.from(s).map(c=>String.fromCodePoint(c))),s=>Buffer.from(s.map(c=>c.codePointAt(0)))); - let bqn_state = sysvals.bqn = (x,w) => { - w = w||[]; - sysvals.path=w[0]; sysvals.name=w[1]; sysvals.args=w[2]; - return bqn(x); - } - sysvals.bqn = (x,w) => bqn_state(req1str("•BQN",x), w); - let bqn_file = (f,t,w) => bqn_state( - t, [ str(path.resolve(f,'..')+'/'), str(path.basename(f)), w ] - ); - sysvals.import = withres("•Import", resolve => (x,w) => { - let f = resolve(req1str("•Import",x)); - return bqn_file(f, fs.readFileSync(f,'utf-8'), w); - }); - - if (!module.parent) { - let args = process.argv.slice(2); - let arg0 = args[0]; - let exec = fn => src => { - try { - fn(src); - } catch(e) { - console.error('[31m'+fmtErr(Array.from(src),e)+'[39m'); - } - } - if (arg0[0] !== '-' || (arg0==='-f'&&(arg0=(args=args.slice(1))[0],1))) { - let f=arg0, a=list(args.slice(1).map(str)); - exec(s=>bqn_file(f,s,a))(fs.readFileSync(f,'utf-8')); - } else if (arg0 === '-e') { - args.slice(1).map(exec(s=>show(bqn_state(s)))); - } - } } diff --git a/docs/running.html b/docs/running.html index cd3eac79..f11791be 100644 --- a/docs/running.html +++ b/docs/running.html @@ -7,7 +7,7 @@ <h1 id="how-to-run-bqn">How to run BQN</h1> <p>There are currently two active BQN implementations: the self-hosted one in this repository, and the independent dzaima/BQN. Neither is entirely complete but they are quite capable for pure programming tasks (say, implementing a compiler). dzaima/BQN has good performance while self-hosted is about a thousand times slower. I tend to develop parts of applications in the online REPL and move to dzaima/BQN scripts in order to run them.</p> <h3 id="bqn">BQN</h3> -<p>The online REPL is <a href="https://mlochbaum.github.io/BQN/try.html">here</a>. The file <a href="https://github.com/mlochbaum/BQN/blob/master/docs/bqn.js">docs/bqn.js</a> is zero-dependency Javascript, and can be loaded from HTML or Node.js. It can also be called directly from the command line (using Node): pass a file and <code><span class='Value'>•args</span></code> or <code><span class='Function'>-</span><span class='Value'>e</span></code> to execute all remaining arguments directly and print the results. <a href="https://observablehq.com/@lsh/bqn">This notebook</a> shows how to run it in an Observable notebook.</p> +<p>The online REPL is <a href="https://mlochbaum.github.io/BQN/try.html">here</a>. The file <a href="https://github.com/mlochbaum/BQN/blob/master/docs/bqn.js">docs/bqn.js</a> is zero-dependency Javascript, and can be loaded from HTML or Node.js. For command line use, call the Node.js script <a href="https://github.com/mlochbaum/BQN/blob/master/bqn.js">bqn.js</a>, passing a file and <code><span class='Value'>•args</span></code>, or <code><span class='Function'>-</span><span class='Value'>e</span></code> to execute all remaining arguments directly and print the results. <a href="https://observablehq.com/@lsh/bqn">This notebook</a> shows how to run it in an Observable notebook.</p> <p>The version of BQN in this repository is implemented mainly in BQN itself—the compiler is entirely self-hosted, while the runtime is built from a small number of starting functions using preprocessed BQN. It completely supports the core language except for block headers and multiple body syntax, and a few cases of structural Under (<code><span class='Modifier2'>⌾</span></code>). The Javascript-based compiler is also slow, taking about 0.05 seconds plus 1 second per kilobyte of source (this is purely due to the slow runtime, as dzaima+reference achieves 1ms/kB with the same compiler once warmed up).</p> <p>Because self-hosted BQN requires only a simple virtual machine to run, it is <a href="implementation/vm.html">fairly easy</a> to embed it in another programming language by implementing this virtual machine. The way data is represented is part of the VM implementation: it can use native arrays or a custom data structure, depending on what the language supports. An initial implementation will be very slow, but can be improved by replacing functions from the BQN-based runtime with native code. As the VM system can be hard to work with if you're not familiar with it, I advise you to contact me to discuss this option it you are interested.</p> <p>In progress VMs are <a href="https://github.com/dzaima/CBQN">CBQN</a> in C, and <a href="https://github.com/cannadayr/ebqn">ebqn</a> in Erlang. Although both of these work (can compile and run code; only missing some fill support in CBQN), neither is considered useful for any purpose yet. CBQN is likely to become the main high-performance BQN implementation but is currently only a few times faster than Javascript and has an interface that's only useful for testing. ebqn is extremely slow—hours to compile.</p> @@ -6,7 +6,7 @@ There are currently two active BQN implementations: the self-hosted one in this ### BQN -The online REPL is [here](https://mlochbaum.github.io/BQN/try.html). The file [docs/bqn.js](docs/bqn.js) is zero-dependency Javascript, and can be loaded from HTML or Node.js. It can also be called directly from the command line (using Node): pass a file and `•args` or `-e` to execute all remaining arguments directly and print the results. [This notebook](https://observablehq.com/@lsh/bqn) shows how to run it in an Observable notebook. +The online REPL is [here](https://mlochbaum.github.io/BQN/try.html). The file [docs/bqn.js](docs/bqn.js) is zero-dependency Javascript, and can be loaded from HTML or Node.js. For command line use, call the Node.js script [bqn.js](bqn.js), passing a file and `•args`, or `-e` to execute all remaining arguments directly and print the results. [This notebook](https://observablehq.com/@lsh/bqn) shows how to run it in an Observable notebook. The version of BQN in this repository is implemented mainly in BQN itself—the compiler is entirely self-hosted, while the runtime is built from a small number of starting functions using preprocessed BQN. It completely supports the core language except for block headers and multiple body syntax, and a few cases of structural Under (`⌾`). The Javascript-based compiler is also slow, taking about 0.05 seconds plus 1 second per kilobyte of source (this is purely due to the slow runtime, as dzaima+reference achieves 1ms/kB with the same compiler once warmed up). |
