@fraczak/k 6.1.3 → 6.2.0
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/AGENTS.md +4 -4
- package/CLAUDE.md +1 -1
- package/DOCS/OBJECT_FILE_AND_PATTERN.md +6 -0
- package/DOCS/REPL.md +22 -17
- package/README.md +6 -5
- package/export.mjs +10 -0
- package/k-vscode/README.md +10 -1
- package/k-vscode/extension.js +273 -0
- package/k-vscode/package.json +22 -0
- package/k-vscode/syntaxes/k.tmLanguage.json +493 -137
- package/k-vscode/test/background-ranges.test.js +50 -0
- package/k-vscode/themes/k-contrast-color-theme.json +104 -0
- package/package.json +2 -2
- package/repl.mjs +43 -2
- package/scripts/run-tests.mjs +54 -0
- package/{Code-derivation-tests → tests/code-derivation}/codec-witness-pattern.mjs +3 -3
- package/{Code-derivation-tests → tests/code-derivation}/convergence-strategy.mjs +1 -1
- package/{Code-derivation-tests → tests/code-derivation}/dot.mjs +1 -1
- package/{Code-derivation-tests → tests/code-derivation}/filter-syntax.mjs +1 -1
- package/{Code-derivation-tests → tests/code-derivation}/index.mjs +1 -1
- package/{Code-derivation-tests → tests/code-derivation}/pattern-envelope.mjs +5 -5
- package/{Code-derivation-tests → tests/code-derivation}/product.mjs +1 -1
- package/{tests.sh → tests/integration.sh} +3 -1
- package/{test-fingerprint.mjs → tests/test-fingerprint.mjs} +3 -3
- package/{test-hash-fuzz.mjs → tests/test-hash-fuzz.mjs} +1 -1
- package/{test-hash-normalization.mjs → tests/test-hash-normalization.mjs} +2 -2
- package/{test-ieee-arithmetic.mjs → tests/test-ieee-arithmetic.mjs} +14 -27
- package/{test-k-object.mjs → tests/test-k-object.mjs} +8 -8
- package/{test-repl.mjs → tests/test-repl.mjs} +22 -4
- package/{test.mjs → tests/test.mjs} +1 -1
- package/.codex +0 -0
- package/DOCS/a.html +0 -398
- package/DOCS/dependency-graph.html +0 -140
- package/DOCS/dependency-graph.md +0 -144
- package/NAT.k~ +0 -452
- package/UU/ta.k +0 -1
- package/UU/ta.k~ +0 -0
- package/UU/tb.k +0 -0
- package/UU/tc.k +0 -0
- package/a.k +0 -138
- package/a.klib +0 -1
- package/codecs/BINARY_FORMAT.html +0 -471
- package/codecs/POLYMORPHIC_BINARY_FORMAT.html +0 -355
- package/core.json +0 -1
- package/core.klib +0 -1
- package/core.klib~ +0 -0
- package/ieee.klib +0 -1
- package/k-vscode/package-lock.json +0 -4176
- package/kkk.k +0 -197
- package/kkk.klib +0 -0
- package/kkk.klib~ +0 -0
- package/nak.klib +0 -1
- package/nak2.klib +0 -1
- package/nat.k +0 -10
- package/nat2.k +0 -9
- package/p.json +0 -5475
- package/type_registry/registry.mjs~ +0 -105
- package/type_registry/typeParser.jison~ +0 -132
- /package/{Code-derivation-tests → tests/code-derivation}/blowup.mjs +0 -0
- /package/{Code-derivation-tests → tests/code-derivation}/bnat.mjs +0 -0
- /package/{Code-derivation-tests → tests/code-derivation}/loop.mjs +0 -0
- /package/{Code-derivation-tests → tests/code-derivation}/nat.mjs +0 -0
- /package/{Code-derivation-tests → tests/code-derivation}/not-not.mjs +0 -0
- /package/{Code-derivation-tests → tests/code-derivation}/rlz.mjs +0 -0
package/AGENTS.md
CHANGED
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
- `k_compiler/` contains the Python prototype compiler and supporting modules.
|
|
6
6
|
- `type_registry/` houses registry experiments and grammar artifacts.
|
|
7
7
|
- `Examples/` and `DOCS/` provide sample programs and design notes.
|
|
8
|
-
- Tests live in
|
|
8
|
+
- Tests live in `tests/`, with type-derivation cases in `tests/code-derivation/`.
|
|
9
9
|
|
|
10
10
|
## Build, Test, and Development Commands
|
|
11
11
|
- `npm install` installs dev dependencies and runs `prepare` to generate parsers.
|
|
12
12
|
- `npm run prepare` regenerates `parser.mjs` and `valueParser.mjs` from `.jison` grammars.
|
|
13
|
-
- `npm test` runs the full suite
|
|
13
|
+
- `npm test` runs the full suite through `scripts/run-tests.mjs`.
|
|
14
14
|
- `node repl.mjs` (or `k-repl`) starts the interactive REPL.
|
|
15
15
|
- `./k.mjs -k <file.k>` executes a k script on binary pattern+value stream input from stdin or a file; use `k-parse` and `k-print` at the boundaries.
|
|
16
16
|
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
- Grammar sources are `parser.jison` and `valueParser.jison`; generated files should not be hand-edited.
|
|
22
22
|
|
|
23
23
|
## Testing Guidelines
|
|
24
|
-
- Add runtime tests alongside `test.mjs` or new `test-*.mjs` files.
|
|
25
|
-
- Add type-derivation coverage in `
|
|
24
|
+
- Add runtime tests alongside `tests/test.mjs` or new `tests/test-*.mjs` files.
|
|
25
|
+
- Add type-derivation coverage in `tests/code-derivation/` (one case per file is typical).
|
|
26
26
|
- Verify locally with `npm test` before opening a PR.
|
|
27
27
|
|
|
28
28
|
## Commit & Pull Request Guidelines
|
package/CLAUDE.md
CHANGED
|
@@ -60,5 +60,5 @@ npm test # Run comprehensive test suite (unit tests, derivation tests, shell te
|
|
|
60
60
|
|
|
61
61
|
- No external runtime dependencies (only jiwson for parser generation)
|
|
62
62
|
- Uses ES6 modules (.mjs files) throughout
|
|
63
|
-
- Extensive test suite in `
|
|
63
|
+
- Extensive test suite in `tests/code-derivation/` for type system validation
|
|
64
64
|
- REPL supports commands like `:C name` (show canonical type), `:t name` (show relation type), and `:d name` (show relation definition)
|
|
@@ -305,3 +305,9 @@ shape is the same object payload shape with `main: null`:
|
|
|
305
305
|
When a library is compiled with `--lib`, the output is the merged library
|
|
306
306
|
closure. Imported codes, relations, aliases, and metadata are preserved, and the
|
|
307
307
|
new source adds its own origins.
|
|
308
|
+
|
|
309
|
+
The REPL `:klib` command uses active relation aliases as roots. It stores their
|
|
310
|
+
transitive relation closure and omits historical content-addressed relations
|
|
311
|
+
that remain in the live session after alias rebinding but are no longer
|
|
312
|
+
reachable from an active alias. Its `codes` field remains the registered code
|
|
313
|
+
snapshot needed to reload the library.
|
package/DOCS/REPL.md
CHANGED
|
@@ -11,9 +11,9 @@ The interpreter keeps a live `.klib`-style state in memory:
|
|
|
11
11
|
- metadata origins used to recover aliases
|
|
12
12
|
- the current value flowing through the session
|
|
13
13
|
|
|
14
|
-
Raw k snippets compile on top of that state. You can also export the
|
|
15
|
-
|
|
16
|
-
expression in the session context.
|
|
14
|
+
Raw k snippets compile on top of that state. You can also export the active
|
|
15
|
+
library closure as a `.klib` file or compile an executable `.ko` object from
|
|
16
|
+
an expression in the session context.
|
|
17
17
|
|
|
18
18
|
## Prompt Model
|
|
19
19
|
|
|
@@ -49,7 +49,7 @@ complete.
|
|
|
49
49
|
| `:codec list` | List loaded REPL codecs |
|
|
50
50
|
| `:input type [codec]` | Read the next line as codec input for a singleton type |
|
|
51
51
|
| `:load [--no-alias] file` | Load `.k` source or `.klib` into the current state |
|
|
52
|
-
| `:klib file` | Export
|
|
52
|
+
| `:klib file` | Export the active relation closure as a `.klib` library |
|
|
53
53
|
| `:ko file expr` | Export a `.ko` executable with `expr` as main |
|
|
54
54
|
| `:val` | Print current value and JSON form |
|
|
55
55
|
| `:reset` | Reset interpreter state |
|
|
@@ -62,7 +62,7 @@ Raw input is compiled as k source on top of the current state.
|
|
|
62
62
|
Examples:
|
|
63
63
|
|
|
64
64
|
```k
|
|
65
|
-
> {} |
|
|
65
|
+
> {} |ok
|
|
66
66
|
```
|
|
67
67
|
|
|
68
68
|
```k
|
|
@@ -107,6 +107,8 @@ The interpreter keeps:
|
|
|
107
107
|
|
|
108
108
|
Definitions are content-addressed. Rebinding an alias changes the name-to-hash
|
|
109
109
|
mapping, but older canonical definitions remain available by hash.
|
|
110
|
+
They stay available in the live session, but `:klib` omits historical
|
|
111
|
+
relations that are no longer reachable from an active relation alias.
|
|
110
112
|
|
|
111
113
|
## Alias Resolution
|
|
112
114
|
|
|
@@ -184,8 +186,11 @@ against that code before becoming the current value.
|
|
|
184
186
|
|
|
185
187
|
### `:klib file`
|
|
186
188
|
|
|
187
|
-
Writes
|
|
188
|
-
|
|
189
|
+
Writes a plain-JSON `.klib` library rooted at the current relation aliases.
|
|
190
|
+
Relations referenced by those aliases are included transitively. Historical
|
|
191
|
+
relations retained in the live session are omitted when no active alias
|
|
192
|
+
depends on them. The registered code snapshot is still included. The library
|
|
193
|
+
has `main: null`; it has no binary header and no object payload version.
|
|
189
194
|
|
|
190
195
|
### `:ko file expr`
|
|
191
196
|
|
|
@@ -197,7 +202,7 @@ writes the resulting executable `.ko` object.
|
|
|
197
202
|
Evaluated values print in k syntax together with the inferred envelope:
|
|
198
203
|
|
|
199
204
|
```text
|
|
200
|
-
{
|
|
205
|
+
{}|0|+1 ?<<{} 0, ...> +1, ...>
|
|
201
206
|
```
|
|
202
207
|
|
|
203
208
|
`undefined` prints as:
|
|
@@ -212,16 +217,16 @@ Evaluated values print in k syntax together with the inferred envelope:
|
|
|
212
217
|
## Example Session
|
|
213
218
|
|
|
214
219
|
```text
|
|
215
|
-
> :type nat = <{}
|
|
220
|
+
> :type nat = <{} 0, nat +1>
|
|
216
221
|
$ nat = @...
|
|
217
|
-
> :rel
|
|
218
|
-
|
|
219
|
-
> {} |
|
|
220
|
-
{
|
|
221
|
-
> :t
|
|
222
|
-
|
|
222
|
+
> :rel inc = |+1
|
|
223
|
+
inc = @...
|
|
224
|
+
> {} |0
|
|
225
|
+
{}|0 ?<{} 0, ...>
|
|
226
|
+
> :t inc
|
|
227
|
+
inc : ?X0 --> ?<X0 +1, ...> (@...)
|
|
223
228
|
> :klib nat.klib
|
|
224
229
|
saved nat.klib
|
|
225
|
-
> :ko
|
|
226
|
-
saved
|
|
230
|
+
> :ko inc.ko inc
|
|
231
|
+
saved inc.ko (inc)
|
|
227
232
|
```
|
package/README.md
CHANGED
|
@@ -55,8 +55,8 @@ from `x` to `y` and recurses. When that no longer applies, it returns `y`.
|
|
|
55
55
|
In the REPL:
|
|
56
56
|
|
|
57
57
|
```text
|
|
58
|
-
> {
|
|
59
|
-
{}|0|+1|+1|+1 ?<X0 +1, {} 0
|
|
58
|
+
> { 0 inc inc x, 0 inc y } add
|
|
59
|
+
{}|0|+1|+1|+1 ?<X0 +1, {} 0>=X0
|
|
60
60
|
```
|
|
61
61
|
|
|
62
62
|
That evaluates `2 + 1` to `3`: a value starts at `0`, and each `+1` tag adds
|
|
@@ -277,13 +277,14 @@ compose with `.result` when only the floating-point value is needed.
|
|
|
277
277
|
|
|
278
278
|
```bash
|
|
279
279
|
npm run prepare # regenerate parsers from .jison grammars
|
|
280
|
-
npm test # run the full suite
|
|
280
|
+
npm test # run the fail-fast full suite with per-test timings
|
|
281
281
|
```
|
|
282
282
|
|
|
283
|
-
The test
|
|
283
|
+
The test runner prints each test before execution and reports its elapsed time
|
|
284
|
+
afterward. It stops immediately when a test fails. The suite covers:
|
|
284
285
|
|
|
285
286
|
- core runtime and parser behavior
|
|
286
|
-
- type derivation cases in `
|
|
287
|
+
- type derivation cases in `tests/code-derivation/`
|
|
287
288
|
- hash/fingerprint stability
|
|
288
289
|
- object file round-trips
|
|
289
290
|
- REPL scripted interaction
|
package/export.mjs
CHANGED
|
@@ -113,6 +113,16 @@ function theID(alias, rel, scc, name) {
|
|
|
113
113
|
export function assignCanonicalNames(scc, rels, relAlias) {
|
|
114
114
|
const newAlias = scc.reduce( (newAlias,relName) => {
|
|
115
115
|
const relDef = rels[relName];
|
|
116
|
+
// Rehashing an imported recursive relation would create a wrapper around its canonical hash.
|
|
117
|
+
if (
|
|
118
|
+
relDef.def.op == "ref" &&
|
|
119
|
+
relDef.def.ref.startsWith("@") &&
|
|
120
|
+
rels[relDef.def.ref]?._library
|
|
121
|
+
) {
|
|
122
|
+
rels[relName] = rels[relDef.def.ref];
|
|
123
|
+
newAlias[relName] = relDef.def.ref;
|
|
124
|
+
return newAlias;
|
|
125
|
+
}
|
|
116
126
|
if (relDef.def.op == "ref" && rels[relDef.def.ref] != undefined) {
|
|
117
127
|
// inlining if direct alias to a non built-in relation
|
|
118
128
|
// relDef.def = rels[relDef.def.ref]; // simplifyRel(rels[relDef.def.ref],rels);
|
package/k-vscode/README.md
CHANGED
|
@@ -16,6 +16,13 @@ unions).
|
|
|
16
16
|
- Canonical content-addressed references: `@base58hash`
|
|
17
17
|
- Quoted label strings: `"label"`, `'label'` (with escape sequences)
|
|
18
18
|
- The `...` any/open pattern marker
|
|
19
|
+
- **Code-definition backgrounds** applied uniformly from the opening `$` through
|
|
20
|
+
the terminating `;`
|
|
21
|
+
- **Nested expression backgrounds** for filters and `$` code expressions inside
|
|
22
|
+
relations, with code-expression backgrounds layered over filter backgrounds
|
|
23
|
+
- **k Contrast color theme** with:
|
|
24
|
+
- Separate foreground colors for type names, relation identifiers, labels, tags,
|
|
25
|
+
filter variables, canonical type names, and canonical relation names
|
|
19
26
|
- **Snippets** for every common pattern (trigger via `Tab` after prefix):
|
|
20
27
|
|
|
21
28
|
| Prefix | Inserts |
|
|
@@ -48,13 +55,15 @@ unions).
|
|
|
48
55
|
|
|
49
56
|
1. Open the `k-vscode/` folder in VS Code.
|
|
50
57
|
2. Press **F5** — this opens an Extension Development Host with the extension loaded.
|
|
58
|
+
3. Expression backgrounds activate automatically. Run **Preferences: Color Theme**
|
|
59
|
+
and select **k Contrast** to use the bundled foreground token palette.
|
|
51
60
|
|
|
52
61
|
### Build and install a VSIX
|
|
53
62
|
|
|
54
63
|
```bash
|
|
55
64
|
cd k-vscode
|
|
56
65
|
npm install
|
|
57
|
-
npx vsce package
|
|
66
|
+
npx vsce package --no-dependencies # produces k-language-0.2.0.vsix
|
|
58
67
|
```
|
|
59
68
|
|
|
60
69
|
Then in VS Code: **Extensions → ⋯ → Install from VSIX…** and select the generated file.
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
const vscode = require("vscode");
|
|
2
|
+
|
|
3
|
+
const NAME_START = /[a-zA-Z0-9_+\-]/;
|
|
4
|
+
const NAME_PART = /[a-zA-Z0-9_?!+\-]/;
|
|
5
|
+
const OPEN_TO_CLOSE = new Map([
|
|
6
|
+
["{", "}"],
|
|
7
|
+
["<", ">"],
|
|
8
|
+
["(", ")"]
|
|
9
|
+
]);
|
|
10
|
+
const CLOSERS = new Set(OPEN_TO_CLOSE.values());
|
|
11
|
+
|
|
12
|
+
function lex(text) {
|
|
13
|
+
const tokens = [];
|
|
14
|
+
let index = 0;
|
|
15
|
+
|
|
16
|
+
while (index < text.length) {
|
|
17
|
+
const char = text[index];
|
|
18
|
+
const next = text[index + 1];
|
|
19
|
+
|
|
20
|
+
if (/\s/.test(char)) {
|
|
21
|
+
index++;
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (char === "/" && next === "*") {
|
|
26
|
+
const end = text.indexOf("*/", index + 2);
|
|
27
|
+
index = end === -1 ? text.length : end + 2;
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (
|
|
32
|
+
(char === "/" && next === "/") ||
|
|
33
|
+
(char === "-" && next === "-") ||
|
|
34
|
+
(char === "\\" && next === "\\") ||
|
|
35
|
+
char === "#" ||
|
|
36
|
+
char === "%"
|
|
37
|
+
) {
|
|
38
|
+
const end = text.indexOf("\n", index + 1);
|
|
39
|
+
index = end === -1 ? text.length : end + 1;
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (char === "\"" || char === "'") {
|
|
44
|
+
const start = index++;
|
|
45
|
+
while (index < text.length) {
|
|
46
|
+
const current = text[index++];
|
|
47
|
+
if (current === "\\") {
|
|
48
|
+
index++;
|
|
49
|
+
} else if (current === char) {
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
tokens.push({ value: text.slice(start, index), start, end: index });
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (NAME_START.test(char)) {
|
|
58
|
+
const start = index++;
|
|
59
|
+
while (index < text.length && NAME_PART.test(text[index])) index++;
|
|
60
|
+
tokens.push({ value: text.slice(start, index), start, end: index });
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
tokens.push({ value: char, start: index, end: index + 1 });
|
|
65
|
+
index++;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return tokens;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function isName(token) {
|
|
72
|
+
return token != null && NAME_START.test(token.value[0]);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function findDefinitionEnd(tokens, startIndex) {
|
|
76
|
+
const stack = [];
|
|
77
|
+
|
|
78
|
+
for (let index = startIndex; index < tokens.length; index++) {
|
|
79
|
+
const value = tokens[index].value;
|
|
80
|
+
const closer = OPEN_TO_CLOSE.get(value);
|
|
81
|
+
if (closer) {
|
|
82
|
+
stack.push(closer);
|
|
83
|
+
} else if (CLOSERS.has(value)) {
|
|
84
|
+
if (value !== stack.at(-1)) return -1;
|
|
85
|
+
stack.pop();
|
|
86
|
+
} else if (value === ";" && stack.length === 0) {
|
|
87
|
+
return index;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return -1;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function findMatching(tokens, startIndex) {
|
|
95
|
+
const firstCloser = OPEN_TO_CLOSE.get(tokens[startIndex]?.value);
|
|
96
|
+
if (!firstCloser) return -1;
|
|
97
|
+
|
|
98
|
+
const stack = [firstCloser];
|
|
99
|
+
for (let index = startIndex + 1; index < tokens.length; index++) {
|
|
100
|
+
const value = tokens[index].value;
|
|
101
|
+
const closer = OPEN_TO_CLOSE.get(value);
|
|
102
|
+
if (closer) {
|
|
103
|
+
stack.push(closer);
|
|
104
|
+
} else if (CLOSERS.has(value)) {
|
|
105
|
+
if (value !== stack.at(-1)) return -1;
|
|
106
|
+
stack.pop();
|
|
107
|
+
if (stack.length === 0) return index;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return -1;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function parseCodeEnd(tokens, startIndex) {
|
|
115
|
+
const token = tokens[startIndex];
|
|
116
|
+
if (!token) return -1;
|
|
117
|
+
|
|
118
|
+
if (isName(token)) return startIndex + 1;
|
|
119
|
+
|
|
120
|
+
if (token.value === "@" && isName(tokens[startIndex + 1])) {
|
|
121
|
+
return startIndex + 2;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (token.value === "{" || token.value === "<") {
|
|
125
|
+
const matching = findMatching(tokens, startIndex);
|
|
126
|
+
return matching === -1 ? -1 : matching + 1;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return -1;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function parseFilterEnd(tokens, startIndex) {
|
|
133
|
+
const token = tokens[startIndex];
|
|
134
|
+
if (!token) return -1;
|
|
135
|
+
|
|
136
|
+
let endIndex;
|
|
137
|
+
if (token.value === "$") {
|
|
138
|
+
endIndex = parseCodeEnd(tokens, startIndex + 1);
|
|
139
|
+
} else if (token.value === "(" || token.value === "{" || token.value === "<") {
|
|
140
|
+
const matching = findMatching(tokens, startIndex);
|
|
141
|
+
endIndex = matching === -1 ? -1 : matching + 1;
|
|
142
|
+
} else if (isName(token)) {
|
|
143
|
+
endIndex = startIndex + 1;
|
|
144
|
+
} else {
|
|
145
|
+
return -1;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (
|
|
149
|
+
endIndex !== -1 &&
|
|
150
|
+
tokens[endIndex]?.value === "=" &&
|
|
151
|
+
isName(tokens[endIndex + 1])
|
|
152
|
+
) {
|
|
153
|
+
endIndex += 2;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return endIndex;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function collectBackgroundRanges(text) {
|
|
160
|
+
const tokens = lex(text);
|
|
161
|
+
const type = [];
|
|
162
|
+
const filter = [];
|
|
163
|
+
|
|
164
|
+
let index = tokens[0]?.value === "~" ? 1 : 0;
|
|
165
|
+
while (index < tokens.length) {
|
|
166
|
+
const isTypeDefinition =
|
|
167
|
+
tokens[index]?.value === "$" &&
|
|
168
|
+
isName(tokens[index + 1]) &&
|
|
169
|
+
tokens[index + 2]?.value === "=";
|
|
170
|
+
const isRelationDefinition =
|
|
171
|
+
isName(tokens[index]) &&
|
|
172
|
+
tokens[index + 1]?.value === "=";
|
|
173
|
+
|
|
174
|
+
if (!isTypeDefinition && !isRelationDefinition) break;
|
|
175
|
+
|
|
176
|
+
const equalsIndex = index + (isTypeDefinition ? 2 : 1);
|
|
177
|
+
const endIndex = findDefinitionEnd(tokens, equalsIndex + 1);
|
|
178
|
+
if (endIndex === -1) break;
|
|
179
|
+
|
|
180
|
+
if (isTypeDefinition) {
|
|
181
|
+
type.push({
|
|
182
|
+
start: tokens[index].start,
|
|
183
|
+
end: tokens[endIndex].end
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
index = endIndex + 1;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
for (let tokenIndex = 0; tokenIndex < tokens.length; tokenIndex++) {
|
|
190
|
+
if (tokens[tokenIndex].value === "?") {
|
|
191
|
+
const endIndex = parseFilterEnd(tokens, tokenIndex + 1);
|
|
192
|
+
if (endIndex !== -1) {
|
|
193
|
+
filter.push({
|
|
194
|
+
start: tokens[tokenIndex].start,
|
|
195
|
+
end: tokens[endIndex - 1].end
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (tokens[tokenIndex].value !== "$") continue;
|
|
202
|
+
|
|
203
|
+
const isDefinition =
|
|
204
|
+
isName(tokens[tokenIndex + 1]) &&
|
|
205
|
+
tokens[tokenIndex + 2]?.value === "=";
|
|
206
|
+
if (isDefinition) continue;
|
|
207
|
+
|
|
208
|
+
const endIndex = parseCodeEnd(tokens, tokenIndex + 1);
|
|
209
|
+
if (endIndex !== -1) {
|
|
210
|
+
type.push({
|
|
211
|
+
start: tokens[tokenIndex].start,
|
|
212
|
+
end: tokens[endIndex - 1].end
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return { type, filter };
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function toVscodeRanges(document, ranges) {
|
|
221
|
+
return ranges.map(({ start, end }) => new vscode.Range(
|
|
222
|
+
document.positionAt(start),
|
|
223
|
+
document.positionAt(end)
|
|
224
|
+
));
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function activate(context) {
|
|
228
|
+
const filterDecoration = vscode.window.createTextEditorDecorationType({
|
|
229
|
+
backgroundColor: "rgba(58, 45, 32, 0.82)"
|
|
230
|
+
});
|
|
231
|
+
const typeDecoration = vscode.window.createTextEditorDecorationType({
|
|
232
|
+
backgroundColor: "rgba(38, 53, 39, 0.92)"
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
context.subscriptions.push(filterDecoration, typeDecoration);
|
|
236
|
+
|
|
237
|
+
function updateEditor(editor) {
|
|
238
|
+
if (editor.document.languageId !== "k") return;
|
|
239
|
+
|
|
240
|
+
const ranges = collectBackgroundRanges(editor.document.getText());
|
|
241
|
+
editor.setDecorations(
|
|
242
|
+
filterDecoration,
|
|
243
|
+
toVscodeRanges(editor.document, ranges.filter)
|
|
244
|
+
);
|
|
245
|
+
editor.setDecorations(
|
|
246
|
+
typeDecoration,
|
|
247
|
+
toVscodeRanges(editor.document, ranges.type)
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function updateVisibleEditors() {
|
|
252
|
+
for (const editor of vscode.window.visibleTextEditors) updateEditor(editor);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
context.subscriptions.push(
|
|
256
|
+
vscode.window.onDidChangeVisibleTextEditors(updateVisibleEditors),
|
|
257
|
+
vscode.workspace.onDidChangeTextDocument(({ document }) => {
|
|
258
|
+
for (const editor of vscode.window.visibleTextEditors) {
|
|
259
|
+
if (editor.document === document) updateEditor(editor);
|
|
260
|
+
}
|
|
261
|
+
})
|
|
262
|
+
);
|
|
263
|
+
|
|
264
|
+
updateVisibleEditors();
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function deactivate() {}
|
|
268
|
+
|
|
269
|
+
module.exports = {
|
|
270
|
+
activate,
|
|
271
|
+
collectBackgroundRanges,
|
|
272
|
+
deactivate
|
|
273
|
+
};
|
package/k-vscode/package.json
CHANGED
|
@@ -23,6 +23,21 @@
|
|
|
23
23
|
"categories": [
|
|
24
24
|
"Programming Languages"
|
|
25
25
|
],
|
|
26
|
+
"main": "./extension.js",
|
|
27
|
+
"activationEvents": [
|
|
28
|
+
"onLanguage:k"
|
|
29
|
+
],
|
|
30
|
+
"files": [
|
|
31
|
+
"extension.js",
|
|
32
|
+
"language-configuration.json",
|
|
33
|
+
"README.md",
|
|
34
|
+
"snippets/k.json",
|
|
35
|
+
"syntaxes/k.tmLanguage.json",
|
|
36
|
+
"themes/k-contrast-color-theme.json"
|
|
37
|
+
],
|
|
38
|
+
"scripts": {
|
|
39
|
+
"test": "node test/background-ranges.test.js"
|
|
40
|
+
},
|
|
26
41
|
"contributes": {
|
|
27
42
|
"languages": [
|
|
28
43
|
{
|
|
@@ -44,6 +59,13 @@
|
|
|
44
59
|
"path": "./syntaxes/k.tmLanguage.json"
|
|
45
60
|
}
|
|
46
61
|
],
|
|
62
|
+
"themes": [
|
|
63
|
+
{
|
|
64
|
+
"label": "k Contrast",
|
|
65
|
+
"uiTheme": "vs-dark",
|
|
66
|
+
"path": "./themes/k-contrast-color-theme.json"
|
|
67
|
+
}
|
|
68
|
+
],
|
|
47
69
|
"snippets": [
|
|
48
70
|
{
|
|
49
71
|
"language": "k",
|