basedpl 0.1.27 → 0.1.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,242 +1,60 @@
1
- # BasedPL
1
+ # basedpl
2
2
 
3
+ This package runs BasedPL (BPL) in a web page. BPL is an array language derived from APL, with ideas from J and BQN. The package holds the BPL interpreter compiled to WebAssembly, a language bar for typing BPL's glyphs, and a TextMate grammar for highlighting BPL code. The [BPL documentation](https://answerdotai.github.io/basedpl/) covers the language. The [playground](https://answerdotai.github.io/basedpl/playground.html) runs BPL in the browser with this package.
3
4
 
4
- <!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->
5
+ ## Load the package
5
6
 
6
- BasedPL, the Based-array Programming Language, is an array language derived from APL, with ideas from J and BQN. Its notation aims to be simple and consistent. Most of this documentation calls it BPL. BPL is written in Rust and comes as a native executable, a Jupyter kernel and a Python API.
7
+ jsDelivr serves every file in the package. An unversioned URL, such as `https://cdn.jsdelivr.net/npm/basedpl/basedpl_wasm.js`, gives the latest release. To keep one release, put its version in the URL: `https://cdn.jsdelivr.net/npm/basedpl@<version>/basedpl_wasm.js`. To install the package instead, run `npm install basedpl`.
7
8
 
8
- LLMs: read [llms.txt](https://answerdotai.github.io/basedpl/llms.txt) first. It is the primary reference index and concise overview.
9
+ ## Run BPL
9
10
 
10
- ## Install and try it
11
+ ```js
12
+ import init, { Session, configure } from 'https://cdn.jsdelivr.net/npm/basedpl/basedpl_wasm.js';
11
13
 
12
- ``` sh
13
- pip install basedpl
14
- bpl
14
+ await init();
15
+ configure(location.href, message => console.error(message));
16
+ const session = new Session();
17
+ const error = session.run('avg←+/÷≢ ⋄ avg 2 4 9', output => console.log(output.data['text/plain']));
15
18
  ```
16
19
 
17
- Each release also has a standalone `bpl` that needs no Python, for macOS on Apple silicon and for Linux on x86-64 and arm64. On a Mac:
20
+ This logs `5`, and `error` is `null`.
18
21
 
19
- ``` sh
20
- curl -Lo bpl https://github.com/AnswerDotAI/basedpl/releases/latest/download/bpl-macos-arm64
21
- chmod +x bpl
22
- ```
23
-
24
- On Linux, download `bpl-linux-x86_64` or `bpl-linux-arm64` instead.
25
-
26
- At the prompt, define a mean and apply it:
27
-
28
- ``` bpl
29
- avg←+/÷≢
30
- avg 2 4 9
31
- ```
32
-
33
- 5
34
-
35
- Use `bpl -e 'avg←+/÷≢ ⋄ avg 2 4 9'` for a shell command. The [command-line guide](https://answerdotai.github.io/basedpl/cli.html) covers source files and pipes.
36
-
37
- ## Interactive use
38
-
39
- In the REPL, type a backtick followed by a glyph name. For example, `` `iota `` becomes `⍳` when you press Tab or type a non-letter. Abbreviations and Alt-key shortcuts are available. `]help +` shows help for `+`. [`•prefs`](https://answerdotai.github.io/basedpl/system-functions.html#prefs) changes display settings, such as boxes and how much of a large array shows. See [REPL](https://answerdotai.github.io/basedpl/repl.html) and the [glyph reference](https://answerdotai.github.io/basedpl/glyphs.html), which lists each glyph’s key.
40
-
41
- In Jupyter, select the installed **BasedPL** kernel. Cells share definitions and support completion, Shift-Tab help and interruption. You can also use `%%bpl` cells in a Python notebook. See [Using BPL notebooks](https://answerdotai.github.io/basedpl/notebooks.html).
42
-
43
- ## New to APL?
44
-
45
- APL is a language built around operations on whole arrays and notation for combining functions. Here is a taste of that style in BPL.
46
-
47
- Numbers separated by spaces form a vector. Arithmetic applies to every element:
48
-
49
- ``` bpl
50
- 10+1 2 3
51
- ```
52
-
53
- 11 12 13
54
-
55
- Operators modify or combine functions. Reduce (`/`) turns addition into summation. `⍳10` generates 0…9:
56
-
57
- ``` bpl
58
- +/⍳10
59
- ```
60
-
61
- 45
62
-
63
- Functions can also be combined without naming their arguments. In `avg←+/÷≢`, sum (`+/`) divided by tally (`≢`) defines the mean:
64
-
65
- ``` bpl
66
- avg 1 2 3 4
67
- ```
68
-
69
- 2.5
70
-
71
- To see how these ideas express an algorithm, start from “a prime has exactly two positive divisors”. Form all remainders of 1 to 50 (`|⊗⍨1+⍳50`), count the zeros down each column (`+⌿0=`), and find the positions (`⍸`) whose count is two. Positions count from 0. `1+` turns each position back into its number:
72
-
73
- ``` bpl
74
- 1+⍸2=+⌿0=|⊗⍨1+⍳50
75
- ```
76
-
77
- 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47
78
-
79
- [Getting started](https://answerdotai.github.io/basedpl/getting-started.html#example-algorithms) builds a primes function from the same divisor count, step by step, and displays the divisibility matrix along the way.
80
-
81
- ## What’s distinctive?
82
-
83
- For APL users, some key differences are:
84
-
85
- - [Based arrays](https://answerdotai.github.io/basedpl/arrays.html), as in BQN: numbers, characters and functions are atoms; enclosure always adds a layer.
86
- - **Vectors in brackets, and grouping by spaces.** `[a b c]` is a vector, and `a+b × c+d` is `(a+b)×(c+d)`. A run that ends in a function is a train. For example, `+/÷≢ x` is the mean of `x`, and `2×` doubles its argument. `0⌷v` and `v₀` both select the first item of `v`.
87
- - **Leading-axis broadcasting**, including expansion of length-1 axes, plus string keys and names on axes.
88
- - **Exact integers and rationals** alongside approximate real and complex numbers.
89
- - Dfns, trains and operators, with additions such as Under, iteration histories, windows and function arrays.
90
-
91
- Positions and axes count from 0, as in BQN and Python. Approximate comparisons use tolerance `1E¯14`. See the [language principles](https://answerdotai.github.io/basedpl/principles.html) for why BPL works this way, the [glyph reference](https://answerdotai.github.io/basedpl/glyphs.html) for Dyalog differences and [Arrays](https://answerdotai.github.io/basedpl/arrays.html) for the array model.
92
-
93
- ### Numbers
94
-
95
- Bare numbers are approximate. Use `ₓ` for exact integers and `r` for exact fractions:
96
-
97
- ``` bpl
98
- 1r3+1r6
99
- ```
100
-
101
- 1ᵣ2
102
-
103
- Complex numbers use `j` between real and imaginary parts. Functions such as square root extend into the complex domain:
104
-
105
- ``` bpl
106
- √¯4
107
- ```
108
-
109
- 0ⱼ2
110
-
111
- See [Numbers](https://answerdotai.github.io/basedpl/numbers.html) for conversion and mixed arithmetic.
112
-
113
- ### Array literals and broadcasting
114
-
115
- Write matrix rows directly in an array literal. Leading-axis agreement lets a vector supply one offset per row:
22
+ - `init()` fetches the module from beside the glue.
23
+ - `configure(base, panic)` sets the URL that relative file reads resolve against, and the function that receives a panic's message. After a panic, the module can't run more code.
24
+ - `session.run(code, output)` runs `code`, then returns `null` or the error. The error is an object with `kind`, `message` and `display`. `display` holds the error as BPL shows it. A session keeps its names from one `run` to the next.
25
+ - `output` receives each output as the program produces it, as `{kind, data}`. `kind` is `"display"` for a displayed value, `"explicit"` for a value assigned to `⎕`, or `"text"` for text written with `"-" •nput`. Display and explicit outputs each end a line. Text output doesn't.
116
26
 
117
- ``` bpl
118
- m←[1 2 3
119
- 4 5 6]
120
- m+10 20
121
- ```
122
-
123
- 11 12 13
124
- 24 25 26
125
-
126
- See [array notation](https://answerdotai.github.io/basedpl/glyphs/brackets.html) and [broadcasting](https://answerdotai.github.io/basedpl/evaluation.html#agreement-and-pervasion).
127
-
128
- ### Keys and named axes
129
-
130
- Axes can have names, and positions along them can have string keys. Describe the axes once, then select by key or reduce by axis name:
131
-
132
- ``` bpl
133
- axes←["city":["NY" "LA"] "month":["Jan" "Feb" "Mar"]]
134
- sales←axes:[10 20 30 ⋄ 40 50 60]
135
- "LA" "Feb"⌷sales
136
- +/⍠"month" sales
137
- ```
138
-
139
- 50
140
-
141
- ["city":2]⍴["NY":60 "LA":150]
142
-
143
- Keys and names travel with axes through operations such as transpose. Arithmetic aligns matching names and keys. See [Axis keys](https://answerdotai.github.io/basedpl/keyed.html).
144
-
145
- ### Function operators
146
-
147
- A vector of counts keeps the history: one state for each count, where count 0 is the initial value. Here, double up to four times:
27
+ `data` maps MIME types to text, or to a `Uint8Array` for a binary type:
148
28
 
149
- ``` bpl
150
- 2×⍣(⍳5) 1
151
- ```
152
-
153
- 1 2 4 8 16
154
-
155
- Under (`⌾`) transforms the argument, applies a function, then reverses the transformation. Scale by ten, floor, and scale back to round down to tenths:
156
-
157
- ``` bpl
158
- ⌊⌾ 10× 1.25 2.78
159
- ```
160
-
161
- 1.2 2.7
162
-
163
- Explore [iteration and inverses](https://answerdotai.github.io/basedpl/glyphs/power.html), [Under](https://answerdotai.github.io/basedpl/glyphs/under.html), [windows](https://answerdotai.github.io/basedpl/glyphs/windows.html) and [function selection](https://answerdotai.github.io/basedpl/glyphs/agenda.html).
164
-
165
- ### Mathematical tools
166
-
167
- [Primes](https://answerdotai.github.io/basedpl/glyphs/prime.html) and [factorisation](https://answerdotai.github.io/basedpl/glyphs/factor.html) are built in:
168
-
169
- ``` bpl
170
- ⨸360ₓ
171
- ```
29
+ - `text/plain`: the output as text.
30
+ - `text/html`: markup from element functions.
31
+ - `image/svg+xml`: markup from `•svg` and `•plot`.
32
+ - `image/x-rgba;width=N`: RGBA pixels from `•image`, `N` pixels wide. `new ImageData(new Uint8ClampedArray(bytes.buffer), N)` makes a canvas image from them.
33
+ - `image/png` and `image/jpeg`: encoded images.
172
34
 
173
- [2 2 2 3 3 5]ₓ
35
+ `run` returns only when the code finishes. To keep the page responsive, run BPL in a Web Worker. The playground's [`worker.js`](https://github.com/AnswerDotAI/basedpl/blob/main/nbs/playground/worker.js) and [`page.js`](https://github.com/AnswerDotAI/basedpl/blob/main/nbs/playground/page.js) show a complete page.
174
36
 
175
- [Polynomials](https://answerdotai.github.io/basedpl/glyphs/polynomial.html) support coefficients, roots and evaluation. Polynomial functions can be [differentiated](https://answerdotai.github.io/basedpl/glyphs/derivative.html): for f(x) = 1 + 2x + 3x², f′(2) = 14.
176
-
177
- ``` bpl
178
- f←[1 2 3]ₓ⌻ ⋄ f∂2ₓ
179
- ```
180
-
181
- 14ₓ
182
-
183
- [Probability distributions](https://answerdotai.github.io/basedpl/distributions.html) provide sampling, density, CDF and quantiles. Two fair coin tosses give these probabilities for 0, 1 and 2 heads:
184
-
185
- ``` bpl
186
- coin←2 0.5 •distribution "binomial"
187
- coin.density 0 1 2
188
- ```
189
-
190
- 0.25 0.5 0.25
191
-
192
- [Matrix division](https://answerdotai.github.io/basedpl/glyphs/domino.html) handles linear systems and least squares.
193
-
194
- ### Data and text
195
-
196
- JSON objects become keyed arrays, with dot access to their fields:
197
-
198
- ``` bpl
199
- order←•json "{""price"":10.5,""qty"":2}"
200
- order.price×order.qty
201
- ```
202
-
203
- 21
204
-
205
- CSV headers likewise name column vectors. [Files, CSV and JSON](https://answerdotai.github.io/basedpl/data.html) covers reading, transforming and writing data. [Regex](https://answerdotai.github.io/basedpl/regex.html) supplies matching, captures and replacement through Rust’s regex engine.
206
-
207
- ### Drawing
208
-
209
- `•plot` draws charts from arrays. Keys label the axes and name the lines. See [Plots](https://answerdotai.github.io/basedpl/plot.html).
210
-
211
- ``` bpl
212
- ["legend":"end"]•plot sales
213
- ```
214
-
215
- ![](index_files/figure-commonmark/cell-17-output-1.svg)
216
-
217
- Build SVG from element functions and keyed attributes. Notebooks display the picture directly. The same element trees serialize to XML. See [XML and SVG](https://answerdotai.github.io/basedpl/xml.html).
218
-
219
- ``` bpl
220
- circle←•element "circle"
221
- text←•element "text"
222
- c←["cx":50 "cy":40 "r":25 "fill":"orange"]circle ""
223
- t←["x":50 "y":85 "text-anchor":"middle"]text "Hello, SVG"
224
- ["width":240 "height":240]•svg [c t]
225
- ```
37
+ ## Differences from native BPL
226
38
 
227
- ![](index_files/figure-commonmark/cell-18-output-1.svg)
39
+ - `•readdir`, `•metadata`, `•copy`, `•rename`, `•remove`, `•mkdir`, `•path` and `•delay` don't exist. `•nput` writes only to `"-"`.
40
+ - File reads and `•fetch` are synchronous `XMLHttpRequest`s, relative to the URL given to `configure`.
41
+ - `•r` uses JavaScript's `RegExp`, with its syntax and replacement templates.
42
+ - `•date⁻¹` has no `locale` option.
43
+ - Function calls nest at most 410 deep. A deeper call is a `LIMIT` error.
228
44
 
229
- ## Python
45
+ ## Language bar
230
46
 
231
- BPL functions are Python callables:
47
+ `lb.js` adds a bar of BPL's glyphs to the page. Clicking a glyph types it into the editor used last. In a textarea marked with `data-bpl`, or a Monaco editor whose language is `bpl`, a backtick followed by a glyph's name also types the glyph, as in the BPL REPL. `lb.js` and `input.js` are scripts whose value is a function. The bar needs the glyph rows from `symbols()` and the key layout from `layout.json`:
232
48
 
233
- ``` python
234
- from basedpl import fn
49
+ ```js
50
+ import init, { symbols } from 'https://cdn.jsdelivr.net/npm/basedpl/basedpl_wasm.js';
235
51
 
236
- mean = fn('+/÷≢')
237
- mean([1, 2, 3])
52
+ const text = name => fetch(`https://cdn.jsdelivr.net/npm/basedpl/${name}`).then(r => r.text());
53
+ const [lb, input, layout] = await Promise.all(['lb.js', 'input.js', 'layout.json'].map(text));
54
+ await init();
55
+ (0, eval)(lb)(JSON.parse(symbols()), (0, eval)(input), JSON.parse(layout));
238
56
  ```
239
57
 
240
- Arrays have `.py`, `.np` and `.df` conversions for Python values, NumPy and pandas. Functions also have Python names and composition operators. See the [Python tutorial](https://answerdotai.github.io/basedpl/python.html).
58
+ ## Highlighting
241
59
 
242
- For other frontends, the [process interfaces](https://answerdotai.github.io/basedpl/processes.html) provide JSON messages and interruptible workers. The [BPL library](https://github.com/AnswerDotAI/basedpl/tree/main/lib) contains more algorithms, codecs, interpreters and puzzles.
60
+ `bpl.tmLanguage.json` is a TextMate grammar for BPL, with the scope name `source.bpl`. Shiki and editors that read TextMate grammars use it to highlight BPL code.
package/basedpl_wasm.js CHANGED
@@ -16,29 +16,17 @@ export class Session {
16
16
  return this;
17
17
  }
18
18
  /**
19
- * The JSON reply to a JSON request: `{"error": …}`, with `null` when the request succeeds. Each output goes to `output`, as JSON,
20
- * while the program runs. The reply has no value: a page shows the output, and a value that holds functions has no JSON form.
21
- * @param {string} request
19
+ * Runs `code`, passing each output to `output` as the program produces it, including any result it displays. Returns the error as
20
+ * an object, or `null`.
21
+ * @param {string} code
22
22
  * @param {Function} output
23
- * @returns {string}
23
+ * @returns {any}
24
24
  */
25
- request(request, output) {
26
- let deferred2_0;
27
- let deferred2_1;
28
- try {
29
- const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
30
- const ptr0 = passStringToWasm0(request, wasm.__wbindgen_export, wasm.__wbindgen_export2);
31
- const len0 = WASM_VECTOR_LEN;
32
- wasm.session_request(retptr, this.__wbg_ptr, ptr0, len0, addHeapObject(output));
33
- var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
34
- var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
35
- deferred2_0 = r0;
36
- deferred2_1 = r1;
37
- return getStringFromWasm0(r0, r1);
38
- } finally {
39
- wasm.__wbindgen_add_to_stack_pointer(16);
40
- wasm.__wbindgen_export4(deferred2_0, deferred2_1, 1);
41
- }
25
+ run(code, output) {
26
+ const ptr0 = passStringToWasm0(code, wasm.__wbindgen_export, wasm.__wbindgen_export2);
27
+ const len0 = WASM_VECTOR_LEN;
28
+ const ret = wasm.session_run(this.__wbg_ptr, ptr0, len0, addHeapObject(output));
29
+ return takeObject(ret);
42
30
  }
43
31
  }
44
32
  if (Symbol.dispose) Session.prototype[Symbol.dispose] = Session.prototype.free;
@@ -77,6 +65,13 @@ export function symbols() {
77
65
  function __wbg_get_imports() {
78
66
  const import0 = {
79
67
  __proto__: null,
68
+ __wbg___wbindgen_debug_string_4687d8d8c2017d52: function(arg0, arg1) {
69
+ const ret = debugString(getObject(arg1));
70
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_export, wasm.__wbindgen_export2);
71
+ const len1 = WASM_VECTOR_LEN;
72
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
73
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
74
+ },
80
75
  __wbg___wbindgen_is_function_1f9d30630b8b1d3d: function(arg0) {
81
76
  const ret = typeof(getObject(arg0)) === 'function';
82
77
  return ret;
@@ -268,6 +263,10 @@ function __wbg_get_imports() {
268
263
  const ret = new Date(getObject(arg0));
269
264
  return addHeapObject(ret);
270
265
  },
266
+ __wbg_new_617a8cdb8bb1130e: function() {
267
+ const ret = new Object();
268
+ return addHeapObject(ret);
269
+ },
271
270
  __wbg_new_a217df4351db4b9b: function() { return handleError(function (arg0, arg1) {
272
271
  const ret = new OffscreenCanvas(arg0 >>> 0, arg1 >>> 0);
273
272
  return addHeapObject(ret);
@@ -276,6 +275,10 @@ function __wbg_get_imports() {
276
275
  const ret = new XMLHttpRequest();
277
276
  return addHeapObject(ret);
278
277
  }, arguments); },
278
+ __wbg_new_from_slice_9a868026ffa4208a: function(arg0, arg1) {
279
+ const ret = new Uint8Array(getArrayU8FromWasm0(arg0, arg1));
280
+ return addHeapObject(ret);
281
+ },
279
282
  __wbg_new_with_base_29cdb449ce79d2d5: function() { return handleError(function (arg0, arg1, arg2, arg3) {
280
283
  const ret = new URL(getStringFromWasm0(arg0, arg1), getStringFromWasm0(arg2, arg3));
281
284
  return addHeapObject(ret);
@@ -307,6 +310,10 @@ function __wbg_get_imports() {
307
310
  __wbg_open_f0c8628338345808: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5) {
308
311
  getObject(arg0).open(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4), arg5 !== 0);
309
312
  }, arguments); },
313
+ __wbg_parse_0fc53dead14b3b42: function() { return handleError(function (arg0, arg1) {
314
+ const ret = JSON.parse(getStringFromWasm0(arg0, arg1));
315
+ return addHeapObject(ret);
316
+ }, arguments); },
310
317
  __wbg_performance_3fcf6e32a7e1ed0a: function(arg0) {
311
318
  const ret = getObject(arg0).performance;
312
319
  return addHeapObject(ret);
@@ -331,6 +338,10 @@ function __wbg_get_imports() {
331
338
  __wbg_setRequestHeader_733b74e99bf9b791: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
332
339
  getObject(arg0).setRequestHeader(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4));
333
340
  }, arguments); },
341
+ __wbg_set_145a351398b48c65: function() { return handleError(function (arg0, arg1, arg2) {
342
+ const ret = Reflect.set(getObject(arg0), getObject(arg1), getObject(arg2));
343
+ return ret;
344
+ }, arguments); },
334
345
  __wbg_set_font_1f60a05a2544a2ff: function(arg0, arg1, arg2) {
335
346
  getObject(arg0).font = getStringFromWasm0(arg1, arg2);
336
347
  },
@@ -406,6 +417,71 @@ function addHeapObject(obj) {
406
417
  return idx;
407
418
  }
408
419
 
420
+ function debugString(val) {
421
+ // primitive types
422
+ const type = typeof val;
423
+ if (type == 'number' || type == 'boolean' || val == null) {
424
+ return `${val}`;
425
+ }
426
+ if (type == 'string') {
427
+ return `"${val}"`;
428
+ }
429
+ if (type == 'symbol') {
430
+ const description = val.description;
431
+ if (description == null) {
432
+ return 'Symbol';
433
+ } else {
434
+ return `Symbol(${description})`;
435
+ }
436
+ }
437
+ if (type == 'function') {
438
+ const name = val.name;
439
+ if (typeof name == 'string' && name.length > 0) {
440
+ return `Function(${name})`;
441
+ } else {
442
+ return 'Function';
443
+ }
444
+ }
445
+ // objects
446
+ if (Array.isArray(val)) {
447
+ const length = val.length;
448
+ let debug = '[';
449
+ if (length > 0) {
450
+ debug += debugString(val[0]);
451
+ }
452
+ for(let i = 1; i < length; i++) {
453
+ debug += ', ' + debugString(val[i]);
454
+ }
455
+ debug += ']';
456
+ return debug;
457
+ }
458
+ // Test for built-in
459
+ const builtInMatches = /\[object ([^\]]+)\]/.exec(toString.call(val));
460
+ let className;
461
+ if (builtInMatches && builtInMatches.length > 1) {
462
+ className = builtInMatches[1];
463
+ } else {
464
+ // Failed to match the standard '[object ClassName]'
465
+ return toString.call(val);
466
+ }
467
+ if (className == 'Object') {
468
+ // we're a user defined class or Object
469
+ // JSON.stringify avoids problems with cycles, and is generally much
470
+ // easier than looping through ownProperties of `val`.
471
+ try {
472
+ return 'Object(' + JSON.stringify(val) + ')';
473
+ } catch (_) {
474
+ return 'Object';
475
+ }
476
+ }
477
+ // errors
478
+ if (val instanceof Error) {
479
+ return `${val.name}: ${val.message}\n${val.stack}`;
480
+ }
481
+ // TODO we could test for more things here, like `Set`s and `Map`s.
482
+ return className;
483
+ }
484
+
409
485
  function dropObject(idx) {
410
486
  if (idx < 1028) return;
411
487
  heap[idx] = heap_next;
Binary file
@@ -0,0 +1,108 @@
1
+ {
2
+ "name": "bpl",
3
+ "scopeName": "source.bpl",
4
+ "fileTypes": [
5
+ "bpl"
6
+ ],
7
+ "patterns": [
8
+ {
9
+ "begin": "⍝",
10
+ "beginCaptures": {
11
+ "0": {
12
+ "name": "comment.line.bpl"
13
+ }
14
+ },
15
+ "end": "$",
16
+ "contentName": "comment.line.bpl",
17
+ "patterns": [],
18
+ "applyEndPatternLast": true
19
+ },
20
+ {
21
+ "begin": "\"",
22
+ "beginCaptures": {
23
+ "0": {
24
+ "name": "string.quoted.double.bpl"
25
+ }
26
+ },
27
+ "end": "\"|$",
28
+ "contentName": "string.quoted.double.bpl",
29
+ "patterns": [
30
+ {
31
+ "match": "\"\"",
32
+ "name": "string.quoted.double.bpl"
33
+ }
34
+ ],
35
+ "applyEndPatternLast": true,
36
+ "endCaptures": {
37
+ "0": {
38
+ "name": "string.quoted.double.bpl"
39
+ }
40
+ }
41
+ },
42
+ {
43
+ "match": "'.?'",
44
+ "name": "string.quoted.single.bpl"
45
+ },
46
+ {
47
+ "match": "[A-Za-z_∆⍙][A-Za-z0-9_∆⍙]*(\\.[A-Za-z_∆⍙][A-Za-z0-9_∆⍙]*)*",
48
+ "name": "source.bpl"
49
+ },
50
+ {
51
+ "match": "•[A-Za-z_∆⍙][A-Za-z0-9_∆⍙]*",
52
+ "name": "support.function.system.bpl"
53
+ },
54
+ {
55
+ "match": "¯?∞|¯?(\\d+(\\.\\d+)?|\\.\\d+)([eEₑ]¯?\\d+)?([jJⱼ]¯?(\\d+(\\.\\d+)?|\\.\\d+)([eEₑ]¯?\\d+)?|ₓ|[rᵣ]¯?\\d+)?",
56
+ "name": "constant.numeric.bpl"
57
+ },
58
+ {
59
+ "match": "⍬ₓ?",
60
+ "name": "constant.numeric.bpl"
61
+ },
62
+ {
63
+ "match": "\\$[tfn]",
64
+ "name": "constant.numeric.bpl"
65
+ },
66
+ {
67
+ "match": "\\$[ad]",
68
+ "name": "string.quoted.double.bpl"
69
+ },
70
+ {
71
+ "begin": "[\\])](?=ₓ)",
72
+ "beginCaptures": {
73
+ "0": {
74
+ "name": "source.bpl"
75
+ }
76
+ },
77
+ "end": "[ₓ]|$",
78
+ "contentName": "constant.numeric.bpl",
79
+ "patterns": [],
80
+ "applyEndPatternLast": true,
81
+ "endCaptures": {
82
+ "0": {
83
+ "name": "constant.numeric.bpl"
84
+ }
85
+ }
86
+ },
87
+ {
88
+ "match": "[\\+\\-×÷⌈⌊\\|\\*⍟○π√!∧∨⊼⊽\\~=≠<≤>≥⍳:⍴≢≡,⍪⊂⊃⊆∊∪∩⍋⍒↑↓⌽⊖⍉⊤⊥⍎⍕⌷⌹\\#↕⍭⨸⌻⍸⍷⊢⊣¿]",
89
+ "name": "support.function.bpl"
90
+ },
91
+ {
92
+ "match": "[¨⍨⊗⌸∂/⌿\\\\⍀⁰¹²³⁴⁵⁶⁷⁸⁹⁻ᵀᵘ]",
93
+ "name": "keyword.operator.monadic.bpl"
94
+ },
95
+ {
96
+ "match": "[↣⍤∘⍠⍥↢\\.⍣⇄⊘⌾⍚@⌺]",
97
+ "name": "keyword.operator.dyadic.bpl"
98
+ },
99
+ {
100
+ "match": "[⍺⍵⍶⍹∇⍢]",
101
+ "name": "variable.parameter.bpl"
102
+ },
103
+ {
104
+ "match": "[←→⎕⋄\\?₀₁₂₃₄₅₆₇₈₉₋]",
105
+ "name": "keyword.control.bpl"
106
+ }
107
+ ]
108
+ }
package/input.js CHANGED
@@ -73,8 +73,11 @@
73
73
  if (python && c === '\\') i++;
74
74
  else if (text.startsWith(quote, i)) { i += quote.length - 1; quote = ''; }
75
75
  } else if (c === "'" && !python) {
76
- if (i + 2 >= text.length) return false;
77
- i += 2;
76
+ if (text.startsWith("''", i) && !text.startsWith("'''", i)) i++;
77
+ else {
78
+ if (i + 2 >= text.length) return false;
79
+ i += 2;
80
+ }
78
81
  } else if (c === "'" || c === '"') {
79
82
  quote = python && text.startsWith(c.repeat(3), i) ? c.repeat(3) : c;
80
83
  i += quote.length - 1;
package/layout.json CHANGED
@@ -1,43 +1,44 @@
1
1
  {
2
2
  "alt_aliases": {"£": "#"},
3
+ "unshifted": {"*": "8", "~": "`", "_": "-", "|": "\\", ":": ";"},
3
4
  "option": {
4
- "`": {"state": "diamond"},
5
+ "`": "⋄",
5
6
  "1": {"state": "diaeresis"},
6
7
  "3": "√",
7
8
  "4": "⇄",
8
9
  "5": {"state": "subscript"},
9
10
  "6": {"state": "superscript"},
10
- "7": {"state": "delta"},
11
+ "7": "∆",
11
12
  "8": "∞",
12
- "9": {"state": "or"},
13
- "0": {"state": "and"},
13
+ "9": "∨",
14
+ "0": "∧",
14
15
  ")": "⍬",
15
16
  "-": {"state": "bar"},
16
17
  "=": {"state": "match"},
17
18
  "q": {"state": "quad"},
18
- "w": {"state": "omega"},
19
- "e": {"state": "epsilon"},
19
+ "w": "⍵",
20
+ "e": "∊",
20
21
  "r": "⍴",
21
22
  "t": "∘",
22
23
  "y": "•",
23
24
  "u": "÷",
24
- "i": {"state": "iota"},
25
+ "i": "⍳",
25
26
  "o": {"state": "circle"},
26
27
  "p": "π",
27
28
  "+": "≠",
28
- "\\": "⍭",
29
- "a": {"state": "alpha"},
29
+ "\\": {"state": "stile"},
30
+ "a": "⍺",
30
31
  "s": "⌈",
31
32
  "d": "⌊",
32
33
  "f": "∂",
33
- "g": {"state": "del"},
34
+ "g": "∇",
34
35
  "h": "←",
35
36
  "j": "↓",
36
37
  "k": {"state": "take"},
37
38
  "l": "→",
38
39
  ";": "⊣",
39
40
  "'": "⊢",
40
- "z": {"state": "enclose"},
41
+ "z": "⊂",
41
42
  "x": "⊃",
42
43
  "c": {"state": "cap"},
43
44
  "v": "∪",
@@ -57,21 +58,12 @@
57
58
  "superscript-minus": {"terminator": "⁻", "keys": {"0": "⁻⁰", "1": "⁻¹", "2": "⁻²", "3": "⁻³", "4": "⁻⁴", "5": "⁻⁵", "6": "⁻⁶", "7": "⁻⁷", "8": "⁻⁸", "9": "⁻⁹"}},
58
59
  "subscript": {"terminator": "_", "keys": {"0": "₀", "1": "₁", "2": "₂", "3": "₃", "4": "₄", "5": "₅", "6": "₆", "7": "₇", "8": "₈", "9": "₉", "x": "ₓ", "j": "ⱼ", "e": "ₑ", "r": "ᵣ", "-": {"state": "subscript-minus"}}},
59
60
  "subscript-minus": {"terminator": "₋", "keys": {"0": "₋₀", "1": "₋₁", "2": "₋₂", "3": "₋₃", "4": "₋₄", "5": "₋₅", "6": "₋₆", "7": "₋₇", "8": "₋₈", "9": "₋₉"}},
60
- "diamond": {"terminator": "⋄", "keys": {"_": "⍚", "-": "⍚"}},
61
- "delta": {"terminator": "∆", "keys": {"|": "⍋", "_": "⍙", "\\": "⍋", "-": "⍙"}},
62
- "or": {"terminator": "∨", "keys": {"~": "⍱", "`": "⍱"}},
63
- "and": {"terminator": "∧", "keys": {"~": "⍲", "`": "⍲"}},
64
- "bar": {"terminator": "¯", "keys": {",": "⍪", "\\": "⍀", "/": "⌿"}},
61
+ "bar": {"terminator": "¯", "keys": {",": "⍪", "\\": "⍀", "/": "⌿", "a": "⍶", "w": "⍹", "7": "⍙", "`": "⍚", "0": "⊼", "9": "⊽", "e": "⍷", "i": "⍸", "z": "⊆"}},
65
62
  "match": {"terminator": "≡", "keys": {"/": "≢"}},
66
63
  "quad": {"terminator": "⎕", "keys": {"t": "⌻", ":": "⍠", "=": "⌸", "u": "⌹", "|": "⌷", "`": "⌺", ";": "⍠", "\\": "⌷"}},
67
- "omega": {"terminator": "⍵", "keys": {"_": "⍹", "-": "⍹"}},
68
- "epsilon": {"terminator": "∊", "keys": {"_": "⍷", "-": "⍷"}},
69
- "iota": {"terminator": "⍳", "keys": {"_": "⍸", "-": "⍸"}},
70
64
  "circle": {"terminator": "○", "keys": {"-": "⊖", "\\": "⍉", "/": "⊘", "*": "⍟", "m": "⊗", "u": "⨸", "t": "⌾", "8": "⍟"}},
71
- "alpha": {"terminator": "⍺", "keys": {"_": "⍶", "-": "⍶"}},
72
- "del": {"terminator": "∇", "keys": {"|": "⍒", "\\": "⍒"}},
65
+ "stile": {"terminator": "⍭", "keys": {"7": "⍋", "g": "⍒"}},
73
66
  "take": {"terminator": "↑", "keys": {"j": "↕"}},
74
- "enclose": {"terminator": "⊂", "keys": {"_": "⊆", "-": "⊆"}},
75
67
  "cap": {"terminator": "∩", "keys": {"t": "⍝"}},
76
68
  "decode": {"terminator": "⊥", "keys": {"t": "⍎"}},
77
69
  "encode": {"terminator": "⊤", "keys": {"t": "⍕"}}
package/lb.js CHANGED
@@ -110,7 +110,7 @@
110
110
  }
111
111
  // Related glyphs stay together; arrows meet at the boundary between menus and plain buttons.
112
112
  const order = [...new Set([
113
- ...'^_⍺⍵∇∆⋄¯¨○⎕∨∧≡∊⍳⊂∩⊥⊤↑↓←→↢↣⇄⊣⊢×÷⌊⌈≤≥≠√π⍭', ...groups.keys(), ...names.keys()
113
+ ...'^_¯¨○⎕≡∩⊥⊤⍭↑↓←→↢↣⇄∨∧⍺⍵∆∇⋄∊⍳⊂⊃⊣⊢×÷⌊⌈≤≥≠√π', ...groups.keys(), ...names.keys()
114
114
  ])];
115
115
  for (const glyph of [...order.filter(g => groups.has(g)), ...order.filter(g => !groups.has(g))]) {
116
116
  if (!groups.has(glyph) && (variants.has(glyph) || /^[\x20-\x7e]+$/.test(glyph))) continue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "basedpl",
3
- "version": "0.1.27",
3
+ "version": "0.1.31",
4
4
  "description": "BasedPL, the Based-array Programming Language, is an APL-derived array language, borrowing ideas from J and BQN, with an emphasis on simple, consistent notation.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {