@fraczak/k 6.1.2 → 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.
Files changed (76) hide show
  1. package/AGENTS.md +4 -4
  2. package/CLAUDE.md +1 -1
  3. package/DOCS/BIG_PICTURE.md +10 -10
  4. package/DOCS/DIVERGENCE_DETECTION.md +1 -1
  5. package/DOCS/OBJECT_FILE_AND_PATTERN.md +6 -0
  6. package/DOCS/REPL.md +22 -17
  7. package/DOCS/TYPE_DERIVATION.md +12 -12
  8. package/DOCS/book/01-introduction.md +2 -2
  9. package/DOCS/book/02-syntax-and-values.md +8 -8
  10. package/DOCS/book/03-types-as-finite-automata.md +2 -2
  11. package/DOCS/book/04-partial-functions-and-composition.md +2 -2
  12. package/DOCS/book/05-typing-filters-and-normalization.md +3 -3
  13. package/DOCS/book/06-values-in-memory.md +3 -3
  14. package/DOCS/book/07-the-partial-function-abi.md +1 -1
  15. package/DOCS/book/08-operational-semantics-and-execution.md +1 -1
  16. package/DOCS/book/09-compiler-architecture.md +2 -2
  17. package/DOCS/book/appendix-b-incorporating-external-predefined-types-and-functions.md +1 -0
  18. package/README.md +13 -13
  19. package/codecs/BINARY_FORMAT.md +1 -1
  20. package/codecs/POLYMORPHIC_BINARY_FORMAT.md +1 -1
  21. package/codes.mjs +14 -33
  22. package/export.mjs +13 -3
  23. package/k-vscode/README.md +10 -1
  24. package/k-vscode/extension.js +273 -0
  25. package/k-vscode/package.json +22 -0
  26. package/k-vscode/syntaxes/k.tmLanguage.json +493 -137
  27. package/k-vscode/test/background-ranges.test.js +50 -0
  28. package/k-vscode/themes/k-contrast-color-theme.json +104 -0
  29. package/object.mjs +20 -7
  30. package/package.json +3 -2
  31. package/repl.mjs +43 -2
  32. package/scripts/benchmark-idempotency.mjs +72 -0
  33. package/scripts/run-tests.mjs +54 -0
  34. package/{Code-derivation-tests → tests/code-derivation}/codec-witness-pattern.mjs +3 -3
  35. package/{Code-derivation-tests → tests/code-derivation}/convergence-strategy.mjs +1 -1
  36. package/{Code-derivation-tests → tests/code-derivation}/dot.mjs +1 -1
  37. package/{Code-derivation-tests → tests/code-derivation}/filter-syntax.mjs +1 -1
  38. package/{Code-derivation-tests → tests/code-derivation}/index.mjs +1 -1
  39. package/{Code-derivation-tests → tests/code-derivation}/pattern-envelope.mjs +5 -5
  40. package/{Code-derivation-tests → tests/code-derivation}/product.mjs +1 -1
  41. package/{tests.sh → tests/integration.sh} +3 -1
  42. package/{test-fingerprint.mjs → tests/test-fingerprint.mjs} +3 -3
  43. package/{test-hash-fuzz.mjs → tests/test-hash-fuzz.mjs} +1 -1
  44. package/{test-hash-normalization.mjs → tests/test-hash-normalization.mjs} +2 -2
  45. package/{test-ieee-arithmetic.mjs → tests/test-ieee-arithmetic.mjs} +14 -27
  46. package/{test-k-object.mjs → tests/test-k-object.mjs} +26 -7
  47. package/{test-repl.mjs → tests/test-repl.mjs} +22 -4
  48. package/{test.mjs → tests/test.mjs} +1 -1
  49. package/.codex +0 -0
  50. package/DOCS/a.html +0 -398
  51. package/DOCS/dependency-graph.html +0 -140
  52. package/DOCS/dependency-graph.md +0 -144
  53. package/NAT.k~ +0 -452
  54. package/UU/ta.k +0 -1
  55. package/UU/ta.k~ +0 -0
  56. package/UU/tb.k +0 -0
  57. package/UU/tc.k +0 -0
  58. package/codecs/BINARY_FORMAT.html +0 -471
  59. package/codecs/POLYMORPHIC_BINARY_FORMAT.html +0 -355
  60. package/core.json +0 -1
  61. package/core.klib +0 -1
  62. package/core.klib~ +0 -0
  63. package/ieee.klib +0 -1
  64. package/k-vscode/package-lock.json +0 -4176
  65. package/kkk.k +0 -197
  66. package/kkk.klib +0 -0
  67. package/kkk.klib~ +0 -0
  68. package/p.json +0 -5475
  69. package/type_registry/registry.mjs~ +0 -105
  70. package/type_registry/typeParser.jison~ +0 -132
  71. /package/{Code-derivation-tests → tests/code-derivation}/blowup.mjs +0 -0
  72. /package/{Code-derivation-tests → tests/code-derivation}/bnat.mjs +0 -0
  73. /package/{Code-derivation-tests → tests/code-derivation}/loop.mjs +0 -0
  74. /package/{Code-derivation-tests → tests/code-derivation}/nat.mjs +0 -0
  75. /package/{Code-derivation-tests → tests/code-derivation}/not-not.mjs +0 -0
  76. /package/{Code-derivation-tests → tests/code-derivation}/rlz.mjs +0 -0
package/export.mjs CHANGED
@@ -87,13 +87,13 @@ function theID(alias, rel, scc, name) {
87
87
  break;
88
88
  case "ref": {
89
89
  const n = rel.ref;
90
- if (alias[n] != undefined) {
91
- newRel.ref = alias[n];
92
- } else if (auxNames[n] != undefined) {
90
+ if (auxNames[n] != undefined) {
93
91
  newRel.ref = auxNames[n];
94
92
  } else if (sccNames.has(n)) {
95
93
  auxNames[n] = `X${Object.keys(auxNames).length}`;
96
94
  newRel.ref = auxNames[n];
95
+ } else if (alias[n] != undefined) {
96
+ newRel.ref = alias[n];
97
97
  };
98
98
  }; break;
99
99
  default:
@@ -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);
@@ -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 # produces k-language-0.2.0.vsix
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
+ };
@@ -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",