@fraczak/k 6.1.0 → 6.1.1

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.
@@ -0,0 +1,5 @@
1
+ <component name="ProjectCodeStyleConfiguration">
2
+ <state>
3
+ <option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
4
+ </state>
5
+ </component>
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="AgentMigrationStateService">
4
+ <option name="migrationStatus" value="COMPLETED" />
5
+ </component>
6
+ </project>
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="AskMigrationStateService">
4
+ <option name="migrationStatus" value="COMPLETED" />
5
+ </component>
6
+ </project>
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="Ask2AgentMigrationStateService">
4
+ <option name="migrationStatus" value="COMPLETED" />
5
+ </component>
6
+ </project>
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="EditMigrationStateService">
4
+ <option name="migrationStatus" value="COMPLETED" />
5
+ </component>
6
+ </project>
package/.idea/k.iml ADDED
@@ -0,0 +1,9 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <module type="JAVA_MODULE" version="4">
3
+ <component name="NewModuleRootManager" inherit-compiler-output="true">
4
+ <exclude-output />
5
+ <content url="file://$MODULE_DIR$" />
6
+ <orderEntry type="inheritedJdk" />
7
+ <orderEntry type="sourceFolder" forTests="false" />
8
+ </component>
9
+ </module>
package/.idea/misc.xml ADDED
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectRootManager">
4
+ <output url="file://$PROJECT_DIR$/out" />
5
+ </component>
6
+ </project>
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectModuleManager">
4
+ <modules>
5
+ <module fileurl="file://$PROJECT_DIR$/.idea/k.iml" filepath="$PROJECT_DIR$/.idea/k.iml" />
6
+ </modules>
7
+ </component>
8
+ </project>
package/.idea/vcs.xml ADDED
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="VcsDirectoryMappings">
4
+ <mapping directory="" vcs="Git" />
5
+ </component>
6
+ </project>
@@ -0,0 +1,205 @@
1
+ #include "runtime.h"
2
+
3
+ #include <stdio.h>
4
+ #include <stdlib.h>
5
+ #include <string.h>
6
+
7
+ typedef enum {
8
+ K_NODE_PRODUCT = 1,
9
+ K_NODE_VARIANT = 2
10
+ } KNodeKind;
11
+
12
+ typedef struct {
13
+ const char *label;
14
+ KValue value;
15
+ } KField;
16
+
17
+ struct KNode {
18
+ KNodeKind kind;
19
+ const char *type_id;
20
+ union {
21
+ struct {
22
+ int field_count;
23
+ KField *fields;
24
+ } product;
25
+ struct {
26
+ const char *tag;
27
+ KValue child;
28
+ } variant;
29
+ } as;
30
+ };
31
+
32
+ static char *krt_strdup(const char *value) {
33
+ size_t len = strlen(value);
34
+ char *result = (char *)malloc(len + 1);
35
+ memcpy(result, value, len + 1);
36
+ return result;
37
+ }
38
+
39
+ static const char *krt_infer_variant_type(const char *label, KValue child) {
40
+ if (child == NULL) return "";
41
+ if (child->type_id != NULL && child->type_id[0] != '\0') {
42
+ return child->type_id;
43
+ }
44
+ if (strcmp(label, "zero") == 0 || strcmp(label, "succ") == 0) {
45
+ return "@w8iSHeQQE738vEmWNGja3FQWk3XuExQKZ2pbm8ApEdkF";
46
+ }
47
+ return "";
48
+ }
49
+
50
+ static KOpt krt_ok(KValue value) {
51
+ KOpt result;
52
+ result.ok = 1;
53
+ result.value = value;
54
+ return result;
55
+ }
56
+
57
+ static const char *json_extract_string(const char *json, const char *key) {
58
+ static char buffer[256];
59
+ char pattern[64];
60
+ const char *cursor;
61
+ const char *start;
62
+ size_t length = 0;
63
+
64
+ snprintf(pattern, sizeof(pattern), "\"%s\":\"", key);
65
+ cursor = strstr(json, pattern);
66
+ if (cursor == NULL) return NULL;
67
+ start = cursor + strlen(pattern);
68
+
69
+ while (start[length] != '\0' && start[length] != '"') {
70
+ if (start[length] == '\\' && start[length + 1] != '\0') {
71
+ length += 2;
72
+ continue;
73
+ }
74
+ length += 1;
75
+ }
76
+
77
+ if (length >= sizeof(buffer)) {
78
+ length = sizeof(buffer) - 1;
79
+ }
80
+ memcpy(buffer, start, length);
81
+ buffer[length] = '\0';
82
+ return buffer;
83
+ }
84
+
85
+ static KValue product_field(KValue input, const char *label) {
86
+ int index;
87
+ if (input == NULL || input->kind != K_NODE_PRODUCT) return NULL;
88
+ for (index = 0; index < input->as.product.field_count; index += 1) {
89
+ if (strcmp(input->as.product.fields[index].label, label) == 0) {
90
+ return input->as.product.fields[index].value;
91
+ }
92
+ }
93
+ return NULL;
94
+ }
95
+
96
+ KOpt krt_fail(void) {
97
+ KOpt result;
98
+ result.ok = 0;
99
+ result.value = NULL;
100
+ return result;
101
+ }
102
+
103
+ KOpt krt_return_input(KValue input) {
104
+ return krt_ok(input);
105
+ }
106
+
107
+ KValue krt_new_product(const char *type_id, int field_count, const char *const *labels, KValue const *values) {
108
+ int index;
109
+ KNode *node = (KNode *)calloc(1, sizeof(KNode));
110
+ node->kind = K_NODE_PRODUCT;
111
+ node->type_id = krt_strdup(type_id == NULL ? "" : type_id);
112
+ node->as.product.field_count = field_count;
113
+ node->as.product.fields = field_count > 0 ? (KField *)calloc((size_t)field_count, sizeof(KField)) : NULL;
114
+
115
+ for (index = 0; index < field_count; index += 1) {
116
+ node->as.product.fields[index].label = krt_strdup(labels[index]);
117
+ node->as.product.fields[index].value = values[index];
118
+ }
119
+ return node;
120
+ }
121
+
122
+ KValue krt_new_variant(const char *type_id, const char *label, KValue child) {
123
+ KNode *node = (KNode *)calloc(1, sizeof(KNode));
124
+ node->kind = K_NODE_VARIANT;
125
+ node->type_id = krt_strdup(type_id == NULL ? "" : type_id);
126
+ node->as.variant.tag = krt_strdup(label);
127
+ node->as.variant.child = child;
128
+ return node;
129
+ }
130
+
131
+ KOpt krt_guard_code(KValue input, const char *type_id) {
132
+ if (input == NULL) return krt_fail();
133
+ if (type_id == NULL || type_id[0] == '\0') return krt_ok(input);
134
+ if (strcmp(input->type_id, type_id) == 0) return krt_ok(input);
135
+ return krt_fail();
136
+ }
137
+
138
+ KOpt krt_guard_type_var(KValue input, const char *var_name) {
139
+ (void)var_name;
140
+ if (input == NULL) return krt_fail();
141
+ return krt_ok(input);
142
+ }
143
+
144
+ KOpt krt_guard_shape(KValue input, const char *shape_descriptor_json) {
145
+ const char *shape;
146
+ if (input == NULL) return krt_fail();
147
+ shape = json_extract_string(shape_descriptor_json, "shape");
148
+ if (shape == NULL || strcmp(shape, "any") == 0) return krt_ok(input);
149
+ if (strcmp(shape, "product") == 0 && input->kind == K_NODE_PRODUCT) return krt_ok(input);
150
+ if (strcmp(shape, "union") == 0 && input->kind == K_NODE_VARIANT) return krt_ok(input);
151
+ return krt_fail();
152
+ }
153
+
154
+ KOpt krt_project_field(KValue input, const char *projection_descriptor_json) {
155
+ const char *label = json_extract_string(projection_descriptor_json, "label");
156
+ KValue child = product_field(input, label);
157
+ if (label == NULL || child == NULL) return krt_fail();
158
+ return krt_ok(child);
159
+ }
160
+
161
+ KOpt krt_project_variant(KValue input, const char *projection_descriptor_json) {
162
+ const char *label = json_extract_string(projection_descriptor_json, "label");
163
+ if (label == NULL || input == NULL || input->kind != K_NODE_VARIANT) return krt_fail();
164
+ if (strcmp(input->as.variant.tag, label) != 0) return krt_fail();
165
+ return krt_ok(input->as.variant.child);
166
+ }
167
+
168
+ KOpt krt_make_product(const char *type_id, int field_count, const char *const *labels, KValue const *values) {
169
+ return krt_ok(krt_new_product(type_id, field_count, labels, values));
170
+ }
171
+
172
+ KOpt krt_make_variant(KValue child, const char *label, const char *type_id) {
173
+ const char *resolved_type = type_id;
174
+ if (resolved_type == NULL || resolved_type[0] == '\0') {
175
+ resolved_type = krt_infer_variant_type(label, child);
176
+ }
177
+ return krt_ok(krt_new_variant(resolved_type, label, child));
178
+ }
179
+
180
+ void krt_print_value(KValue value) {
181
+ int index;
182
+ if (value == NULL) {
183
+ printf("<null>");
184
+ return;
185
+ }
186
+
187
+ if (value->kind == K_NODE_PRODUCT) {
188
+ if (value->as.product.field_count == 0) {
189
+ printf("{}");
190
+ return;
191
+ }
192
+ printf("{");
193
+ for (index = 0; index < value->as.product.field_count; index += 1) {
194
+ if (index > 0) printf(", ");
195
+ printf("%s:", value->as.product.fields[index].label);
196
+ krt_print_value(value->as.product.fields[index].value);
197
+ }
198
+ printf("}");
199
+ return;
200
+ }
201
+
202
+ printf("%s(", value->as.variant.tag);
203
+ krt_print_value(value->as.variant.child);
204
+ printf(")");
205
+ }
@@ -0,0 +1,34 @@
1
+ #ifndef K_COMPILER_RUNTIME_H
2
+ #define K_COMPILER_RUNTIME_H
3
+
4
+ #ifdef __cplusplus
5
+ extern "C" {
6
+ #endif
7
+
8
+ typedef struct KNode KNode;
9
+ typedef KNode *KValue;
10
+
11
+ typedef struct {
12
+ int ok;
13
+ KValue value;
14
+ } KOpt;
15
+
16
+ KOpt krt_fail(void);
17
+ KOpt krt_return_input(KValue input);
18
+ KOpt krt_guard_code(KValue input, const char *type_id);
19
+ KOpt krt_guard_type_var(KValue input, const char *var_name);
20
+ KOpt krt_guard_shape(KValue input, const char *shape_descriptor_json);
21
+ KOpt krt_project_field(KValue input, const char *projection_descriptor_json);
22
+ KOpt krt_project_variant(KValue input, const char *projection_descriptor_json);
23
+ KOpt krt_make_product(const char *type_id, int field_count, const char *const *labels, KValue const *values);
24
+ KOpt krt_make_variant(KValue child, const char *label, const char *type_id);
25
+
26
+ KValue krt_new_product(const char *type_id, int field_count, const char *const *labels, KValue const *values);
27
+ KValue krt_new_variant(const char *type_id, const char *label, KValue child);
28
+ void krt_print_value(KValue value);
29
+
30
+ #ifdef __cplusplus
31
+ }
32
+ #endif
33
+
34
+ #endif
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fraczak/k",
3
- "version": "6.1.0",
3
+ "version": "6.1.1",
4
4
  "description": "k — a language for composing first-order partial functions over algebraic data types (products and tagged unions); includes runtime, type derivation, REPL, and codec toolchain",
5
5
  "main": "index.mjs",
6
6
  "scripts": {
package/repl.mjs CHANGED
@@ -261,10 +261,18 @@ function listAliases(aliases) {
261
261
  return entries.map(([name, hash]) => `${name} = ${hash}`).join("\n");
262
262
  }
263
263
 
264
- function printValue(value = null) {
264
+ function printValue(value) {
265
265
  return valueWithEnvelopeToK(value);
266
266
  }
267
267
 
268
+ function commitResult(state, result, lastMain) {
269
+ if (result !== undefined) {
270
+ state.value = result;
271
+ state.lastMain = lastMain;
272
+ }
273
+ return [printValue(result)];
274
+ }
275
+
268
276
  function userDefinedNames(source) {
269
277
  let parsed;
270
278
  try {
@@ -347,6 +355,17 @@ function aliasNames(state) {
347
355
  ])].sort();
348
356
  }
349
357
 
358
+ function displayAliases(state) {
359
+ const aliases = {};
360
+ for (const [name, hash] of [
361
+ ...Object.entries(state.typeAliases),
362
+ ...Object.entries(state.relAliases)
363
+ ].sort(([a], [b]) => a.localeCompare(b))) {
364
+ if (!aliases[hash]) aliases[hash] = name;
365
+ }
366
+ return aliases;
367
+ }
368
+
350
369
  function expandHome(input) {
351
370
  if (input === "~") return os.homedir();
352
371
  if (input.startsWith("~/")) return path.join(os.homedir(), input.slice(2));
@@ -659,14 +678,14 @@ async function runExpression(input, state) {
659
678
  }
660
679
  const mainRel = annotated.rels.__main__;
661
680
  run.defs = annotated;
681
+ let result;
662
682
  try {
663
- state.value = run(codes.find, mainRel.def, state.value, mainRel.typePatternGraph);
683
+ result = run(codes.find, mainRel.def, state.value, mainRel.typePatternGraph);
664
684
  } catch (error) {
665
685
  throw remapError(error, preambleLineCount(preamble));
666
686
  }
667
- state.lastMain = expression;
668
687
  restoreCodes(state);
669
- return [printValue(state.value)];
688
+ return commitResult(state, result, expression);
670
689
  }
671
690
 
672
691
  async function runSnippet(input, state, options = {}) {
@@ -685,14 +704,14 @@ async function runSnippet(input, state, options = {}) {
685
704
 
686
705
  const mainRel = annotated.rels.__main__;
687
706
  run.defs = annotated;
707
+ let result;
688
708
  try {
689
- state.value = run(codes.find, mainRel.def, state.value, mainRel.typePatternGraph);
709
+ result = run(codes.find, mainRel.def, state.value, mainRel.typePatternGraph);
690
710
  } catch (error) {
691
711
  throw remapError(error, lineOffset);
692
712
  }
693
- state.lastMain = snippet;
694
713
  restoreCodes(state);
695
- return [printValue(state.value)];
714
+ return commitResult(state, result, snippet);
696
715
  }
697
716
 
698
717
  async function evaluateInput(input, state) {
@@ -803,13 +822,13 @@ async function evaluateCommand(line, state) {
803
822
  if (!arg) throw new Error(`${usagePrefix}d requires a relation name`);
804
823
  const { hash, rel } = resolveRel(state, arg);
805
824
  if (!rel) throw new Error(`Unknown relation '${arg}'`);
806
- return [`${arg} = ${prettyRelation(rel)}; -- ${hash}`];
825
+ return [`${arg} = ${prettyRelation(rel, displayAliases(state), state.relAliases)}; -- ${hash}`];
807
826
  }
808
827
  case "C": {
809
828
  if (!arg) throw new Error(`${usagePrefix}C requires a type name`);
810
829
  const hash = state.typeAliases[arg] || (arg.startsWith("@") ? arg : null);
811
830
  if (!hash || !(hash in state.codes)) throw new Error(`Unknown type '${arg}'`);
812
- return [`$ ${arg} = ${prettyCode({}, codes.find, codes.find(hash))}; -- ${hash}`];
831
+ return [`$ ${arg} = ${prettyCode(displayAliases(state), codes.find, codes.find(hash))}; -- ${hash}`];
813
832
  }
814
833
  default:
815
834
  throw new Error(`Unknown command ':${command}'. Try :help`);
package/test-repl.mjs CHANGED
@@ -36,6 +36,13 @@ assert.match(output[0], /^succ = @/m);
36
36
  output = await evaluateInput(":run succ", state);
37
37
  assert.equal(output[0], "{}|succ ?<{} succ, ...>");
38
38
 
39
+ output = await evaluateInput("/zero", state);
40
+ assert.equal(output[0], "... undefined");
41
+ assert.equal(state.value.toJSON(), "succ");
42
+
43
+ output = await evaluateInput("succ", state);
44
+ assert.match(output[0], /^\{\}\|succ\|succ \?</);
45
+
39
46
  output = await evaluateInput(":t succ", state);
40
47
  assert.match(output[0], /^succ : /);
41
48
 
@@ -97,7 +104,7 @@ const objectFn = objectToFunction(decodeObject(fs.readFileSync(koPath)));
97
104
  const objectResult = objectFn(new Product({}, [["closed-product", []]]));
98
105
  assert.equal(objectResult.toJSON(), "succ");
99
106
 
100
- fs.writeFileSync(sourcePath, "$ nat = <{} zero, nat succ>;\nsucc = |succ;\n");
107
+ fs.writeFileSync(sourcePath, "$ nat = <{} zero, nat succ>;\nsucc = $nat |succ $nat;\ntwice = succ succ;\n");
101
108
  const loadedSource = createState();
102
109
  output = await evaluateInput(`:load ${sourcePath}`, loadedSource);
103
110
  assert.equal(output[0], `loaded ${sourcePath}`);
@@ -105,6 +112,10 @@ output = await evaluateInput(":codes", loadedSource);
105
112
  assert.match(output[0], /^nat = @/m);
106
113
  output = await evaluateInput(":rels", loadedSource);
107
114
  assert.match(output[0], /^succ = @/m);
115
+ output = await evaluateInput(":d twice", loadedSource);
116
+ assert.match(output[0], /^twice = \$nat succ succ \$nat; -- @/);
117
+ output = await evaluateInput(":C nat", loadedSource);
118
+ assert.match(output[0], /^\$ nat = < nat succ, @[^ ]+ zero >; -- @/);
108
119
 
109
120
  const replPath = fileURLToPath(new URL("./repl.mjs", import.meta.url));
110
121
  try {
package/.codex DELETED
File without changes