diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 6ea05af..d244386 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -13,7 +13,7 @@ jobs: strategy: matrix: - node-version: [18.x, latest] + node-version: [24.x, latest] fail-fast: false steps: diff --git a/.github/workflows/ovsxstore.yaml b/.github/workflows/ovsxstore.yaml index 0adbe41..39d7574 100644 --- a/.github/workflows/ovsxstore.yaml +++ b/.github/workflows/ovsxstore.yaml @@ -22,7 +22,7 @@ jobs: - name: Install Node.js uses: actions/setup-node@v3 with: - node-version: 18.x + node-version: 24.x - run: npm install -g vsce - run: npm install diff --git a/.github/workflows/vcstore.yaml b/.github/workflows/vcstore.yaml index e897ae8..98ab4ce 100644 --- a/.github/workflows/vcstore.yaml +++ b/.github/workflows/vcstore.yaml @@ -22,7 +22,7 @@ jobs: - name: Install Node.js uses: actions/setup-node@v3 with: - node-version: 18.x + node-version: 24.x - run: npm install -g vsce - run: npm install diff --git a/CHANGELOG.md b/CHANGELOG.md index 8600f85..8bc1f1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log + +### 0.3.2 + +- No more shiki +- Support multiple trace versions + ### 0.3.1 - Syntax for Elpi 3.0 diff --git a/media/main.js b/media/main.js index fd9379d..4bd02c8 100644 --- a/media/main.js +++ b/media/main.js @@ -22,7 +22,7 @@ break; case 'trace': clear(); - trace(message.trace, message.enable_highlighting); + trace(message.trace); $("#trace-information").val(message.file + ' on ' + new Date().toISOString()); break; case 'clear': @@ -44,7 +44,7 @@ function elide(i, str) { - if (str.length < i) + if (str.length < 2*i) return str; return str.replace(str.slice(i,-i),' ... '); @@ -656,12 +656,6 @@ ${step.value.findall_solution_text}
`; - if(window.enable_highlighting) - vscode.postMessage({ - command: 'highlight_inline', - id: rule_id, - value: step.value.suspend_sibling.goal_text - }); contents += format_stack(step.value.suspend_stack, r_id, s_id); @@ -706,15 +700,9 @@ ${step.value.findall_solution_text}
${step.value[i].goal_text}
`; - - if(window.enable_highlighting) vscode.postMessage({ - command: 'highlight_inline', - id: rule_id, - value: step.value[i].goal_text - }); } - contents += ` + contents += ` @@ -985,19 +973,29 @@ ${step.value.findall_solution_text} function format_rule(element, r_id, s_id, g_id) { - // console.log('Formatting rule', JSON.stringify(element)); + + //return('
' + JSON.stringify(element) + '
'); + //element = {"kind":"BuiltinRule","value":{"name":"implication","kind":{"kind":"Logic"},"payload":[]}} const rule_type = element.kind; let rule_text = ""; + let rule_text_full = ""; let rule_id = r_id + '-' + s_id + '-' + g_id + '-' + window.rnb++; - if (rule_type == "UserRule") + if (rule_type == "UserRule") { rule_text = element.value.rule_text; + rule_text_full = rule_text + } if (rule_type == "BuiltinRule") - rule_text = element.value.kind + ' - ' + element.value.value; - + if (element.value.name) {// v2 + rule_text = element.value.kind.kind + ' - ' + element.value.name + ': ' + element.value.payload.join('\n'); + rule_text_full = element.value.payload.join('\n'); + } else { //v1 + rule_text = element.value.kind + ' - ' + element.value.value; + rule_text_full = rule_text + } // rule_text = rule_text.trim(); let fmt = ` @@ -1059,14 +1057,8 @@ class="has-tooltip-arrow has-tooltip-bottom" data-tooltip="${rule_loc_file} (${r
-
${rule_text}
+
${rule_text_full}
`; - - if(window.enable_highlighting) vscode.postMessage({ - command: 'highlight_inline', - id: rule_id, - value: rule_text - }); return fmt; } @@ -1099,11 +1091,6 @@ class="has-tooltip-arrow has-tooltip-bottom" data-tooltip="${rule_loc_file} (${r
${element[i].value}
`; - if(window.enable_highlighting) vscode.postMessage({ - command: 'highlight_inline', - id: rule_id, - value: element[i].value - }); } return fmt; @@ -1171,11 +1158,6 @@ class="has-tooltip-arrow has-tooltip-bottom" data-tooltip="${rule_loc_file} (${r `; } - if(window.enable_highlighting) vscode.postMessage({ - command: 'highlight_inline', - id: rule_id, - value: element[i].goal_text - }); } return fmt; @@ -1217,12 +1199,6 @@ class="has-tooltip-arrow has-tooltip-bottom" data-tooltip="${attempt_loc_file} (
${attempt_text}
`; - - if(window.enable_highlighting) vscode.postMessage({ - command: 'highlight_inline', - id: rule_id, - value: attempt_text - }); return fmt; } @@ -1272,12 +1248,6 @@ class="has-tooltip-arrow has-tooltip-bottom" data-tooltip="${attempt_loc_file} ( `; - if(window.enable_highlighting) - vscode.postMessage({ - command: 'highlight_inline', - id: rule_id, - value: element.chr_new_goals[i].goal_text - }); } return fmt; @@ -1319,12 +1289,6 @@ class="has-tooltip-arrow has-tooltip-bottom" data-tooltip="${attempt_loc_file} ( `; - if(window.enable_highlighting) - vscode.postMessage({ - command: 'highlight_inline', - id: rule_id, - value: element[i].goal_text - }); } fmt += ` @@ -1373,12 +1337,6 @@ class="has-tooltip-arrow has-tooltip-bottom" data-tooltip="${attempt_loc_file} ( `; - if(window.enable_highlighting) - vscode.postMessage({ - command: 'highlight_inline', - id: rule_id, - value: element[i].goal_text - }); } fmt += ` @@ -1422,11 +1380,10 @@ class="has-tooltip-arrow has-tooltip-bottom" data-tooltip="${attempt_loc_file} ( // Main entry point // ///////////////////////////////////////////////////////////////////////////// - function trace(data, enable_highlighting) { + function trace(data) { // console.log('Tracing ...'); - window.enable_highlighting = enable_highlighting; window.trace = data; window.inbox = {}; @@ -1695,23 +1652,9 @@ class="has-tooltip-arrow has-tooltip-bottom" data-tooltip="${attempt_loc_file} ( window.inbox[i].goal_text_elided = elide(25, window.inbox[i].goal_text); - if(window.enable_highlighting) - vscode.postMessage({ - command: 'highlight', - index: i, - value: window.inbox[i].goal_text - }); - else - window.inbox[i].goal_text_highlighted = '
' + window.inbox[i].goal_text + '
'; - - if(window.enable_highlighting) - vscode.postMessage({ - command: 'highlight_elided', - index: i, - value: window.inbox[i].goal_text_elided - }); - else - window.inbox[i].goal_text_highlighted_elided = '
' + window.inbox[i].goal_text_elided + '
'; + window.inbox[i].goal_text_highlighted = '
' + window.inbox[i].goal_text + '
'; + + window.inbox[i].goal_text_highlighted_elided = '
' + window.inbox[i].goal_text_elided + '
'; // ///////////////////////////////////////////////////////////////////////////// } diff --git a/package-lock.json b/package-lock.json index 4be694c..06b37f2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "elpi-lang", - "version": "0.2.8", + "version": "0.3.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "elpi-lang", - "version": "0.2.8", + "version": "0.3.2", "license": "MIT", "dependencies": { "@creativebulma/bulma-collapsible": "^1.0.4", @@ -19,7 +19,6 @@ "chokidar": "^3.5.3", "fuzzball": "^2.1.2", "jquery": "^3.6.1", - "shiki": "^0.10.1", "vue": "^2.7.0" }, "devDependencies": { @@ -245,6 +244,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.46.0.tgz", "integrity": "sha512-joNO6zMGUZg+C73vwrKXCd8usnsmOYmgW/w5ZW0pG0RGvqeznjtGDk61EqqTpNrFLUYBW2RSBFrxdAZMqA4OZA==", "dev": true, + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "5.46.0", "@typescript-eslint/types": "5.46.0", @@ -458,6 +458,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", "dev": true, + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -1045,6 +1046,7 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.29.0.tgz", "integrity": "sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg==", "dev": true, + "peer": true, "dependencies": { "@eslint/eslintrc": "^1.3.3", "@humanwhocodes/config-array": "^0.11.6", @@ -1836,7 +1838,8 @@ "node_modules/jsonc-parser": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==" + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true }, "node_modules/keytar": { "version": "7.9.0", @@ -2630,16 +2633,6 @@ "node": ">=8" } }, - "node_modules/shiki": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.10.1.tgz", - "integrity": "sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng==", - "dependencies": { - "jsonc-parser": "^3.0.0", - "vscode-oniguruma": "^1.6.1", - "vscode-textmate": "5.2.0" - } - }, "node_modules/side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", @@ -2924,6 +2917,7 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", "dev": true, + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -2966,16 +2960,6 @@ "dev": true, "optional": true }, - "node_modules/vscode-oniguruma": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", - "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==" - }, - "node_modules/vscode-textmate": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-5.2.0.tgz", - "integrity": "sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ==" - }, "node_modules/vue": { "version": "2.7.16", "resolved": "https://registry.npmjs.org/vue/-/vue-2.7.16.tgz", @@ -3229,6 +3213,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.46.0.tgz", "integrity": "sha512-joNO6zMGUZg+C73vwrKXCd8usnsmOYmgW/w5ZW0pG0RGvqeznjtGDk61EqqTpNrFLUYBW2RSBFrxdAZMqA4OZA==", "dev": true, + "peer": true, "requires": { "@typescript-eslint/scope-manager": "5.46.0", "@typescript-eslint/types": "5.46.0", @@ -3357,7 +3342,8 @@ "version": "8.8.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", - "dev": true + "dev": true, + "peer": true }, "acorn-jsx": { "version": "5.3.2", @@ -3787,6 +3773,7 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.29.0.tgz", "integrity": "sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg==", "dev": true, + "peer": true, "requires": { "@eslint/eslintrc": "^1.3.3", "@humanwhocodes/config-array": "^0.11.6", @@ -4377,7 +4364,8 @@ "jsonc-parser": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==" + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true }, "keytar": { "version": "7.9.0", @@ -4927,16 +4915,6 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, - "shiki": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.10.1.tgz", - "integrity": "sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng==", - "requires": { - "jsonc-parser": "^3.0.0", - "vscode-oniguruma": "^1.6.1", - "vscode-textmate": "5.2.0" - } - }, "side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", @@ -5138,7 +5116,8 @@ "version": "4.9.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", - "dev": true + "dev": true, + "peer": true }, "uc.micro": { "version": "1.0.6", @@ -5174,16 +5153,6 @@ "dev": true, "optional": true }, - "vscode-oniguruma": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", - "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==" - }, - "vscode-textmate": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-5.2.0.tgz", - "integrity": "sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ==" - }, "vue": { "version": "2.7.16", "resolved": "https://registry.npmjs.org/vue/-/vue-2.7.16.tgz", diff --git a/package.json b/package.json index 32a5650..cd47d1f 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "displayName": "Elpi lang", "publisher": "gares", "description": "Elpi programming language support", - "version": "0.3.1", + "version": "0.3.2", "homepage": "https://github.com/LPCIC/elpi-lang", "repository": { "type": "git", @@ -88,11 +88,6 @@ "type": "string", "default": "elpi-trace-elaborator", "markdownDescription": "Path to `elpi-trace-elaborator` (or elpi from `$PATH`)" - }, - "elpi.elpi_trace_view.syntax_highlighting": { - "type": "boolean", - "default": "false", - "markdownDescription": "Highlight elpi code statements" } } }, @@ -176,7 +171,7 @@ }, "scripts": { "build": "mustache elpiLexicalConventions.js syntaxes/elpi.tmLanguage.mustache > syntaxes/elpi.tmLanguage.json", - "vscode:prepublish": "npm run compile && rm -rf node_modules/shiki/languages/*", + "vscode:prepublish": "npm run compile", "compile": "tsc -p ./", "lint": "eslint . --ext .ts,.tsx", "watch": "tsc -w -p ./", @@ -204,7 +199,6 @@ "chokidar": "^3.5.3", "fuzzball": "^2.1.2", "jquery": "^3.6.1", - "shiki": "^0.10.1", "vue": "^2.7.0" } } diff --git a/src/provider.ts b/src/provider.ts index 5b894d0..cb1b6f8 100644 --- a/src/provider.ts +++ b/src/provider.ts @@ -1,15 +1,37 @@ import * as vscode from 'vscode'; -import * as parser from './trace'; +import * as parser_v1 from './trace_v1'; +import * as parser_v2 from './trace_v2'; import * as path from 'path'; import os = require('node:os'); import cp = require('child_process'); import fs = require('fs'); -// import tmp = require('tmp'); -import shiki = require('shiki'); import chokidar = require('chokidar'); +type TraceParser = { + readTrace: (x: any, context?: any) => any; +}; + +const traceParsers: TraceParser[] = [parser_v2, parser_v1]; + +function any_parser_readTrace(x: any) { + let lastError: unknown; + + for (const parser of traceParsers) { + try { + return parser.readTrace(x); + } catch (error) { + lastError = error; + } + } + + if (lastError instanceof Error) + throw lastError; + + throw new Error('Failed to parse trace with all available parser versions.'); +} + export class TraceProvider implements vscode.WebviewViewProvider { public static readonly viewType = 'elpi.tracer'; @@ -17,7 +39,6 @@ export class TraceProvider implements vscode.WebviewViewProvider { private _cat: string; private _elpi: string; private _elpi_trace_elaborator: string; - private _highlighter: shiki.Highlighter | undefined; private _options: string; private _options_default: string; private _view?: vscode.WebviewView; @@ -70,11 +91,6 @@ export class TraceProvider implements vscode.WebviewViewProvider { this._watcher_target = this._target_dir + "traced.tmp.json"; this._watcher_target_elaborated = this._target_dir + "traced.json"; - shiki.getHighlighter({theme: 'css-variables'}).then(highlighter => { - this._highlighter = highlighter; - this._highlighter.loadLanguage(elpi_lang); - }); - if (os.platform().toString().toLowerCase() == "win32") this._cat = "type"; else @@ -107,9 +123,6 @@ export class TraceProvider implements vscode.WebviewViewProvider { const indx = message.index; let html = undefined; - if (this._highlighter) - html = this._highlighter.codeToHtml(code, { lang: 'elpi' }); - if (this._view) this._view.webview.postMessage({ type: 'highlight', @@ -124,10 +137,7 @@ export class TraceProvider implements vscode.WebviewViewProvider { const code = message.value; const indx = message.index; let html = undefined; - - if (this._highlighter) - html = this._highlighter.codeToHtml(code, { lang: 'elpi' }); - + if (this._view) this._view.webview.postMessage({ type: 'highlight_elided', @@ -142,10 +152,7 @@ export class TraceProvider implements vscode.WebviewViewProvider { const code = message.value; const id = message.id; let html = undefined; - - if (this._highlighter) - html = this._highlighter.codeToHtml(code, { lang: 'elpi' }); - + if (this._view) this._view.webview.postMessage({ type: 'highlight_inline', @@ -284,14 +291,12 @@ export class TraceProvider implements vscode.WebviewViewProvider { this.exec(this._cat + " " + fileUri[0].fsPath + " | " + this._elpi_trace_elaborator + " > " + this._target); - const trace = parser.readTrace(JSON.parse(fs.readFileSync(this._target, 'utf8'))); + const trace = any_parser_readTrace(JSON.parse(fs.readFileSync(this._target, 'utf8'))); this._source = fileUri[0].fsPath; - let enable_highlighting = configuration.elpi_trace_view.syntax_highlighting; - if (this._view) - this._view.webview.postMessage({ type: 'trace', trace: trace, file: fileUri[0].fsPath, enable_highlighting: enable_highlighting }); + this._view.webview.postMessage({ type: 'trace', trace: trace, file: fileUri[0].fsPath }); if (this._view) this._view.webview.postMessage({ type: 'progress', state: 'off' }); @@ -358,8 +363,6 @@ export class TraceProvider implements vscode.WebviewViewProvider { return; } - let enable_highlighting = configuration.elpi_trace_view.syntax_highlighting; - message = `File ${path} has been changed`; vscode.window.showInformationMessage(message); @@ -368,12 +371,12 @@ export class TraceProvider implements vscode.WebviewViewProvider { this.exec("eval $(opam env) && cat " + this._watcher_target + " | " + this._elpi_trace_elaborator + " > " + this._watcher_target_elaborated); - const trace = parser.readTrace(JSON.parse(fs.readFileSync(this._watcher_target_elaborated, 'utf8'))); + const trace = any_parser_readTrace(JSON.parse(fs.readFileSync(this._watcher_target_elaborated, 'utf8'))); this._source = this._watcher_target; if (this._view) - this._view.webview.postMessage({ type: 'trace', trace: trace, file: 'Watched', enable_highlighting: enable_highlighting }); + this._view.webview.postMessage({ type: 'trace', trace: trace, file: 'Watched' }); }); message = "Me watch has started. Try me by touching " + this._watcher_target; @@ -432,8 +435,6 @@ export class TraceProvider implements vscode.WebviewViewProvider { this._options_default = configuration.elpi.options; - let enable_highlighting = configuration.elpi_trace_view.syntax_highlighting; - if(vscode.window.activeTextEditor == undefined) return; @@ -470,12 +471,12 @@ export class TraceProvider implements vscode.WebviewViewProvider { // -- - const trace = parser.readTrace(JSON.parse(fs.readFileSync(this._target, 'utf8'))) + const trace = any_parser_readTrace(JSON.parse(fs.readFileSync(this._target, 'utf8'))) // --- Send message to the view backend if (this._view) - this._view.webview.postMessage({ type: 'trace', trace: trace, file: current_file, enable_highlighting: enable_highlighting }); + this._view.webview.postMessage({ type: 'trace', trace: trace, file: current_file }); } private _getHtmlForWebview(webview: vscode.Webview) { diff --git a/src/trace.atd b/src/trace_v1.atd similarity index 100% rename from src/trace.atd rename to src/trace_v1.atd diff --git a/src/trace.ts b/src/trace_v1.ts similarity index 100% rename from src/trace.ts rename to src/trace_v1.ts diff --git a/src/trace_v2.atd b/src/trace_v2.atd new file mode 100644 index 0000000..79302a3 --- /dev/null +++ b/src/trace_v2.atd @@ -0,0 +1,143 @@ +(* This file describes the format of the trace generated by elpi + and the format of the elaborate trace generated by elpi-trace-elaborator + + home: https://github.com/ahrefs/atd + doc: https://atd.readthedocs.io/en/latest/index.html + + +*) + +(* input: raw events *) + +type item = { + kind : kind list; + goal_id : int; + runtime_id : int; + step : int; + name : string; + payload : string list; +} +type kind = [ Start | Info | Stop of stop ] +type stop = { cause : string; time : float } +type raw_trace = item list + +(* **** output: cards to be displayed ************************************** *) + +type trace = card list + +(* Note: step_id + runtime_id form a unique identified for the card *) +type card = { + step_id : step_id; (* sequential, but local to the runtime *) + runtime_id : runtime_id; (* each runtime has an id, 0 for the main one *) + step : step; (* the computation step *) + color : color; +} + +type color = [ Red | Green | Grey | YellowGreen | YellowRed ] + +type step = + [ Inference of inference (* The goal is solved by a rule, most common case *) + | Findall of findall (* A sub runtime computes all solutions to a goal *) + | Cut of cut (* Some alternatives are dropped *) + | Suspend of suspend (* A new constraint is generated *) + | Resume of resume (* A constraint is resumed *) + | CHR of chr (* Some constraint handling rules fires *) + | Init of goal (* The initial goal is set *) + ] + +(* Inference step operates on a goal with a bunch of rules: first a bunch of + rules which fail, and then some which succeed. If no rule succeeds, then + the inference fails. If a rule succeeds, but some sibling fails, then + there may be more rules to be attempted later *) +type inference = { + current_goal_id : goal_id; + current_goal_text : goal_text; + current_goal_predicate : string; (* string to search/filter steps *) + failed_attempts : attempt list; + successful_attempts : successful_attempt list; + more_successful_attempts : step_id list; + ~more_failing_attempts : step_id list; (* optional, for backward compatibility *) + stack : stack; +} + +type attempt = { + rule : rule; + events : event list; +} +type rule = [ BuiltinRule of builtin_rule | UserRule of user_rule ] +type user_rule = { rule_text : rule_text; rule_loc : location } +type builtin_kind = [ Logic | FFI ] +type builtin_rule = { name : string; kind : builtin_kind; payload : string list } +type location = [ File of file_location | Context of step_id ] +type file_location = { filename : string; line : int; column : int; character : int } +type event = [ Assign of string | Fail of string | ResumeGoal of goal_id list] +type rule_text = string (* Todo: use a formattable data, e.g. box language *) + +type successful_attempt = { + attempt : attempt; + siblings : goal list; + siblings_aggregated_outcome : outcome; +} +type goal = { goal_text : string; goal_id : goal_id } +type outcome = [ Fail | Success ] + +type stack = frame list +type frame = { rule : rule; step_id : step_id; runtime_id : runtime_id } + +type goal_id = int +type step_id = int +type runtime_id = int +type goal_text = string (* Todo: use a formattable data, e.g. box language *) + + +(* Findall step *) +type findall = { + findall_goal_id : goal_id; + findall_goal_text : goal_text; + findall_cards : trace; (* The sub trace computing all solutions to the goal *) + findall_solution_text : solution_text; + findall_stack : stack; +} +type solution_text = string list (* Todo: use a formattable data, e.g. box language *) + +(* This goal generates a suspended sibling *) +type suspend = { + suspend_goal_id : goal_id; + suspend_goal_text : goal_text; + suspend_sibling : goal; + suspend_stack : stack; +} + +(* The ! operator eliminates some rules (for some goal) *) +type cut = { + cut_goal_id : goal_id; + cut_victims : cutted list; +} +type cutted = { + cut_branch_for_goal : goal; + cut_branch : user_rule +} + +(* Resumption activaes suspended goals *) +type resume = goal list + +(* A CHR step is like an inference step, it is made of some failed and some + successful attempts. It acts on the store. *) +type chr = { + chr_failed_attempts : chr_attempt list; + chr_successful_attempts : successful_chr_attempt list; + chr_store_before : goal list; + chr_store_after : goal list; +} +type chr_attempt = { + chr_text : chr_text; (* the rule text *) + chr_loc : file_location; (* the rule loc *) + chr_condition_cards : trace; (* the rule has a condition, which is an elpi + program running in a dedicated runtime *) +} +type successful_chr_attempt = { + chr_attempt : chr_attempt; + chr_removed_goals : goal_id list; + chr_new_goals : goal list; +} +type chr_text = string (* Todo: use a formattable data, e.g. box language *) diff --git a/src/trace_v2.ts b/src/trace_v2.ts new file mode 100644 index 0000000..e0bde14 --- /dev/null +++ b/src/trace_v2.ts @@ -0,0 +1,1178 @@ +/* + Generated by atdts from type definitions in 'trace.atd'. + + Type-safe translations from/to JSON + + For each type 'Foo', there is a pair of functions: + - 'writeFoo': convert a 'Foo' value into a JSON-compatible value. + - 'readFoo': convert a JSON-compatible value into a TypeScript value + of type 'Foo'. +*/ + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-nocheck +/* tslint:disable */ +/* eslint-disable */ + +export type Item = { + kind: Kind[]; + goal_id: number /*int*/; + runtime_id: number /*int*/; + step: number /*int*/; + name: string; + payload: string[]; +} + +export type Kind = +| { kind: 'Start' } +| { kind: 'Info' } +| { kind: 'Stop'; value: Stop } + +export type Stop = { + cause: string; + time: number; +} + +export type RawTrace = Item[] + +export type Trace = Card[] + +export type Card = { + step_id: StepId; + runtime_id: RuntimeId; + step: Step; + color: Color; +} + +export type Color = +| { kind: 'Red' } +| { kind: 'Green' } +| { kind: 'Grey' } +| { kind: 'YellowGreen' } +| { kind: 'YellowRed' } + +export type Step = +| { kind: 'Inference'; value: Inference } +| { kind: 'Findall'; value: Findall } +| { kind: 'Cut'; value: Cut } +| { kind: 'Suspend'; value: Suspend } +| { kind: 'Resume'; value: Resume } +| { kind: 'CHR'; value: Chr } +| { kind: 'Init'; value: Goal } + +export type Inference = { + current_goal_id: GoalId; + current_goal_text: GoalText; + current_goal_predicate: string; + failed_attempts: Attempt[]; + successful_attempts: SuccessfulAttempt[]; + more_successful_attempts: StepId[]; + more_failing_attempts: StepId[]; + stack: Stack; +} + +export type Attempt = { + rule: Rule; + events: Event[]; +} + +export type Rule = +| { kind: 'BuiltinRule'; value: BuiltinRule } +| { kind: 'UserRule'; value: UserRule } + +export type UserRule = { + rule_text: RuleText; + rule_loc: Location; +} + +export type BuiltinKind = +| { kind: 'Logic' } +| { kind: 'FFI' } + +export type BuiltinRule = { + name: string; + kind: BuiltinKind; + payload: string[]; +} + +export type Location = +| { kind: 'File'; value: FileLocation } +| { kind: 'Context'; value: StepId } + +export type FileLocation = { + filename: string; + line: number /*int*/; + column: number /*int*/; + character: number /*int*/; +} + +export type Event = +| { kind: 'Assign'; value: string } +| { kind: 'Fail'; value: string } +| { kind: 'ResumeGoal'; value: GoalId[] } + +export type RuleText = string + +export type SuccessfulAttempt = { + attempt: Attempt; + siblings: Goal[]; + siblings_aggregated_outcome: Outcome; +} + +export type Goal = { + goal_text: string; + goal_id: GoalId; +} + +export type Outcome = +| { kind: 'Fail' } +| { kind: 'Success' } + +export type Stack = Frame[] + +export type Frame = { + rule: Rule; + step_id: StepId; + runtime_id: RuntimeId; +} + +export type GoalId = number /*int*/ + +export type StepId = number /*int*/ + +export type RuntimeId = number /*int*/ + +export type GoalText = string + +export type Findall = { + findall_goal_id: GoalId; + findall_goal_text: GoalText; + findall_cards: Trace; + findall_solution_text: SolutionText; + findall_stack: Stack; +} + +export type SolutionText = string[] + +export type Suspend = { + suspend_goal_id: GoalId; + suspend_goal_text: GoalText; + suspend_sibling: Goal; + suspend_stack: Stack; +} + +export type Cut = { + cut_goal_id: GoalId; + cut_victims: Cutted[]; +} + +export type Cutted = { + cut_branch_for_goal: Goal; + cut_branch: UserRule; +} + +export type Resume = Goal[] + +export type Chr = { + chr_failed_attempts: ChrAttempt[]; + chr_successful_attempts: SuccessfulChrAttempt[]; + chr_store_before: Goal[]; + chr_store_after: Goal[]; +} + +export type ChrAttempt = { + chr_text: ChrText; + chr_loc: FileLocation; + chr_condition_cards: Trace; +} + +export type SuccessfulChrAttempt = { + chr_attempt: ChrAttempt; + chr_removed_goals: GoalId[]; + chr_new_goals: Goal[]; +} + +export type ChrText = string + +export function writeItem(x: Item, context: any = x): any { + return { + 'kind': _atd_write_required_field('Item', 'kind', _atd_write_array(writeKind), x.kind, x), + 'goal_id': _atd_write_required_field('Item', 'goal_id', _atd_write_int, x.goal_id, x), + 'runtime_id': _atd_write_required_field('Item', 'runtime_id', _atd_write_int, x.runtime_id, x), + 'step': _atd_write_required_field('Item', 'step', _atd_write_int, x.step, x), + 'name': _atd_write_required_field('Item', 'name', _atd_write_string, x.name, x), + 'payload': _atd_write_required_field('Item', 'payload', _atd_write_array(_atd_write_string), x.payload, x), + }; +} + +export function readItem(x: any, context: any = x): Item { + return { + kind: _atd_read_required_field('Item', 'kind', _atd_read_array(readKind), x['kind'], x), + goal_id: _atd_read_required_field('Item', 'goal_id', _atd_read_int, x['goal_id'], x), + runtime_id: _atd_read_required_field('Item', 'runtime_id', _atd_read_int, x['runtime_id'], x), + step: _atd_read_required_field('Item', 'step', _atd_read_int, x['step'], x), + name: _atd_read_required_field('Item', 'name', _atd_read_string, x['name'], x), + payload: _atd_read_required_field('Item', 'payload', _atd_read_array(_atd_read_string), x['payload'], x), + }; +} + +export function writeKind(x: Kind, context: any = x): any { + switch (x.kind) { + case 'Start': + return 'Start' + case 'Info': + return 'Info' + case 'Stop': + return ['Stop', writeStop(x.value, x)] + } +} + +export function readKind(x: any, context: any = x): Kind { + if (typeof x === 'string') { + switch (x) { + case 'Start': + return { kind: 'Start' } + case 'Info': + return { kind: 'Info' } + default: + _atd_bad_json('Kind', x, context) + throw new Error('impossible') + } + } + else { + _atd_check_json_tuple(2, x, context) + switch (x[0]) { + case 'Stop': + return { kind: 'Stop', value: readStop(x[1], x) } + default: + _atd_bad_json('Kind', x, context) + throw new Error('impossible') + } + } +} + +export function writeStop(x: Stop, context: any = x): any { + return { + 'cause': _atd_write_required_field('Stop', 'cause', _atd_write_string, x.cause, x), + 'time': _atd_write_required_field('Stop', 'time', _atd_write_float, x.time, x), + }; +} + +export function readStop(x: any, context: any = x): Stop { + return { + cause: _atd_read_required_field('Stop', 'cause', _atd_read_string, x['cause'], x), + time: _atd_read_required_field('Stop', 'time', _atd_read_float, x['time'], x), + }; +} + +export function writeRawTrace(x: RawTrace, context: any = x): any { + return _atd_write_array(writeItem)(x, context); +} + +export function readRawTrace(x: any, context: any = x): RawTrace { + return _atd_read_array(readItem)(x, context); +} + +export function writeTrace(x: Trace, context: any = x): any { + return _atd_write_array(writeCard)(x, context); +} + +export function readTrace(x: any, context: any = x): Trace { + return _atd_read_array(readCard)(x, context); +} + +export function writeCard(x: Card, context: any = x): any { + return { + 'step_id': _atd_write_required_field('Card', 'step_id', writeStepId, x.step_id, x), + 'runtime_id': _atd_write_required_field('Card', 'runtime_id', writeRuntimeId, x.runtime_id, x), + 'step': _atd_write_required_field('Card', 'step', writeStep, x.step, x), + 'color': _atd_write_required_field('Card', 'color', writeColor, x.color, x), + }; +} + +export function readCard(x: any, context: any = x): Card { + return { + step_id: _atd_read_required_field('Card', 'step_id', readStepId, x['step_id'], x), + runtime_id: _atd_read_required_field('Card', 'runtime_id', readRuntimeId, x['runtime_id'], x), + step: _atd_read_required_field('Card', 'step', readStep, x['step'], x), + color: _atd_read_required_field('Card', 'color', readColor, x['color'], x), + }; +} + +export function writeColor(x: Color, context: any = x): any { + switch (x.kind) { + case 'Red': + return 'Red' + case 'Green': + return 'Green' + case 'Grey': + return 'Grey' + case 'YellowGreen': + return 'YellowGreen' + case 'YellowRed': + return 'YellowRed' + } +} + +export function readColor(x: any, context: any = x): Color { + switch (x) { + case 'Red': + return { kind: 'Red' } + case 'Green': + return { kind: 'Green' } + case 'Grey': + return { kind: 'Grey' } + case 'YellowGreen': + return { kind: 'YellowGreen' } + case 'YellowRed': + return { kind: 'YellowRed' } + default: + _atd_bad_json('Color', x, context) + throw new Error('impossible') + } +} + +export function writeStep(x: Step, context: any = x): any { + switch (x.kind) { + case 'Inference': + return ['Inference', writeInference(x.value, x)] + case 'Findall': + return ['Findall', writeFindall(x.value, x)] + case 'Cut': + return ['Cut', writeCut(x.value, x)] + case 'Suspend': + return ['Suspend', writeSuspend(x.value, x)] + case 'Resume': + return ['Resume', writeResume(x.value, x)] + case 'CHR': + return ['CHR', writeChr(x.value, x)] + case 'Init': + return ['Init', writeGoal(x.value, x)] + } +} + +export function readStep(x: any, context: any = x): Step { + _atd_check_json_tuple(2, x, context) + switch (x[0]) { + case 'Inference': + return { kind: 'Inference', value: readInference(x[1], x) } + case 'Findall': + return { kind: 'Findall', value: readFindall(x[1], x) } + case 'Cut': + return { kind: 'Cut', value: readCut(x[1], x) } + case 'Suspend': + return { kind: 'Suspend', value: readSuspend(x[1], x) } + case 'Resume': + return { kind: 'Resume', value: readResume(x[1], x) } + case 'CHR': + return { kind: 'CHR', value: readChr(x[1], x) } + case 'Init': + return { kind: 'Init', value: readGoal(x[1], x) } + default: + _atd_bad_json('Step', x, context) + throw new Error('impossible') + } +} + +export function writeInference(x: Inference, context: any = x): any { + return { + 'current_goal_id': _atd_write_required_field('Inference', 'current_goal_id', writeGoalId, x.current_goal_id, x), + 'current_goal_text': _atd_write_required_field('Inference', 'current_goal_text', writeGoalText, x.current_goal_text, x), + 'current_goal_predicate': _atd_write_required_field('Inference', 'current_goal_predicate', _atd_write_string, x.current_goal_predicate, x), + 'failed_attempts': _atd_write_required_field('Inference', 'failed_attempts', _atd_write_array(writeAttempt), x.failed_attempts, x), + 'successful_attempts': _atd_write_required_field('Inference', 'successful_attempts', _atd_write_array(writeSuccessfulAttempt), x.successful_attempts, x), + 'more_successful_attempts': _atd_write_required_field('Inference', 'more_successful_attempts', _atd_write_array(writeStepId), x.more_successful_attempts, x), + 'more_failing_attempts': _atd_write_field_with_default(_atd_write_array(writeStepId), [], x.more_failing_attempts, x), + 'stack': _atd_write_required_field('Inference', 'stack', writeStack, x.stack, x), + }; +} + +export function readInference(x: any, context: any = x): Inference { + return { + current_goal_id: _atd_read_required_field('Inference', 'current_goal_id', readGoalId, x['current_goal_id'], x), + current_goal_text: _atd_read_required_field('Inference', 'current_goal_text', readGoalText, x['current_goal_text'], x), + current_goal_predicate: _atd_read_required_field('Inference', 'current_goal_predicate', _atd_read_string, x['current_goal_predicate'], x), + failed_attempts: _atd_read_required_field('Inference', 'failed_attempts', _atd_read_array(readAttempt), x['failed_attempts'], x), + successful_attempts: _atd_read_required_field('Inference', 'successful_attempts', _atd_read_array(readSuccessfulAttempt), x['successful_attempts'], x), + more_successful_attempts: _atd_read_required_field('Inference', 'more_successful_attempts', _atd_read_array(readStepId), x['more_successful_attempts'], x), + more_failing_attempts: _atd_read_field_with_default(_atd_read_array(readStepId), [], x['more_failing_attempts'], x), + stack: _atd_read_required_field('Inference', 'stack', readStack, x['stack'], x), + }; +} + +export function writeAttempt(x: Attempt, context: any = x): any { + return { + 'rule': _atd_write_required_field('Attempt', 'rule', writeRule, x.rule, x), + 'events': _atd_write_required_field('Attempt', 'events', _atd_write_array(writeEvent), x.events, x), + }; +} + +export function readAttempt(x: any, context: any = x): Attempt { + return { + rule: _atd_read_required_field('Attempt', 'rule', readRule, x['rule'], x), + events: _atd_read_required_field('Attempt', 'events', _atd_read_array(readEvent), x['events'], x), + }; +} + +export function writeRule(x: Rule, context: any = x): any { + switch (x.kind) { + case 'BuiltinRule': + return ['BuiltinRule', writeBuiltinRule(x.value, x)] + case 'UserRule': + return ['UserRule', writeUserRule(x.value, x)] + } +} + +export function readRule(x: any, context: any = x): Rule { + _atd_check_json_tuple(2, x, context) + switch (x[0]) { + case 'BuiltinRule': + return { kind: 'BuiltinRule', value: readBuiltinRule(x[1], x) } + case 'UserRule': + return { kind: 'UserRule', value: readUserRule(x[1], x) } + default: + _atd_bad_json('Rule', x, context) + throw new Error('impossible') + } +} + +export function writeUserRule(x: UserRule, context: any = x): any { + return { + 'rule_text': _atd_write_required_field('UserRule', 'rule_text', writeRuleText, x.rule_text, x), + 'rule_loc': _atd_write_required_field('UserRule', 'rule_loc', writeLocation, x.rule_loc, x), + }; +} + +export function readUserRule(x: any, context: any = x): UserRule { + return { + rule_text: _atd_read_required_field('UserRule', 'rule_text', readRuleText, x['rule_text'], x), + rule_loc: _atd_read_required_field('UserRule', 'rule_loc', readLocation, x['rule_loc'], x), + }; +} + +export function writeBuiltinKind(x: BuiltinKind, context: any = x): any { + switch (x.kind) { + case 'Logic': + return 'Logic' + case 'FFI': + return 'FFI' + } +} + +export function readBuiltinKind(x: any, context: any = x): BuiltinKind { + switch (x) { + case 'Logic': + return { kind: 'Logic' } + case 'FFI': + return { kind: 'FFI' } + default: + _atd_bad_json('BuiltinKind', x, context) + throw new Error('impossible') + } +} + +export function writeBuiltinRule(x: BuiltinRule, context: any = x): any { + return { + 'name': _atd_write_required_field('BuiltinRule', 'name', _atd_write_string, x.name, x), + 'kind': _atd_write_required_field('BuiltinRule', 'kind', writeBuiltinKind, x.kind, x), + 'payload': _atd_write_required_field('BuiltinRule', 'payload', _atd_write_array(_atd_write_string), x.payload, x), + }; +} + +export function readBuiltinRule(x: any, context: any = x): BuiltinRule { + return { + name: _atd_read_required_field('BuiltinRule', 'name', _atd_read_string, x['name'], x), + kind: _atd_read_required_field('BuiltinRule', 'kind', readBuiltinKind, x['kind'], x), + payload: _atd_read_required_field('BuiltinRule', 'payload', _atd_read_array(_atd_read_string), x['payload'], x), + }; +} + +export function writeLocation(x: Location, context: any = x): any { + switch (x.kind) { + case 'File': + return ['File', writeFileLocation(x.value, x)] + case 'Context': + return ['Context', writeStepId(x.value, x)] + } +} + +export function readLocation(x: any, context: any = x): Location { + _atd_check_json_tuple(2, x, context) + switch (x[0]) { + case 'File': + return { kind: 'File', value: readFileLocation(x[1], x) } + case 'Context': + return { kind: 'Context', value: readStepId(x[1], x) } + default: + _atd_bad_json('Location', x, context) + throw new Error('impossible') + } +} + +export function writeFileLocation(x: FileLocation, context: any = x): any { + return { + 'filename': _atd_write_required_field('FileLocation', 'filename', _atd_write_string, x.filename, x), + 'line': _atd_write_required_field('FileLocation', 'line', _atd_write_int, x.line, x), + 'column': _atd_write_required_field('FileLocation', 'column', _atd_write_int, x.column, x), + 'character': _atd_write_required_field('FileLocation', 'character', _atd_write_int, x.character, x), + }; +} + +export function readFileLocation(x: any, context: any = x): FileLocation { + return { + filename: _atd_read_required_field('FileLocation', 'filename', _atd_read_string, x['filename'], x), + line: _atd_read_required_field('FileLocation', 'line', _atd_read_int, x['line'], x), + column: _atd_read_required_field('FileLocation', 'column', _atd_read_int, x['column'], x), + character: _atd_read_required_field('FileLocation', 'character', _atd_read_int, x['character'], x), + }; +} + +export function writeEvent(x: Event, context: any = x): any { + switch (x.kind) { + case 'Assign': + return ['Assign', _atd_write_string(x.value, x)] + case 'Fail': + return ['Fail', _atd_write_string(x.value, x)] + case 'ResumeGoal': + return ['ResumeGoal', _atd_write_array(writeGoalId)(x.value, x)] + } +} + +export function readEvent(x: any, context: any = x): Event { + _atd_check_json_tuple(2, x, context) + switch (x[0]) { + case 'Assign': + return { kind: 'Assign', value: _atd_read_string(x[1], x) } + case 'Fail': + return { kind: 'Fail', value: _atd_read_string(x[1], x) } + case 'ResumeGoal': + return { kind: 'ResumeGoal', value: _atd_read_array(readGoalId)(x[1], x) } + default: + _atd_bad_json('Event', x, context) + throw new Error('impossible') + } +} + +export function writeRuleText(x: RuleText, context: any = x): any { + return _atd_write_string(x, context); +} + +export function readRuleText(x: any, context: any = x): RuleText { + return _atd_read_string(x, context); +} + +export function writeSuccessfulAttempt(x: SuccessfulAttempt, context: any = x): any { + return { + 'attempt': _atd_write_required_field('SuccessfulAttempt', 'attempt', writeAttempt, x.attempt, x), + 'siblings': _atd_write_required_field('SuccessfulAttempt', 'siblings', _atd_write_array(writeGoal), x.siblings, x), + 'siblings_aggregated_outcome': _atd_write_required_field('SuccessfulAttempt', 'siblings_aggregated_outcome', writeOutcome, x.siblings_aggregated_outcome, x), + }; +} + +export function readSuccessfulAttempt(x: any, context: any = x): SuccessfulAttempt { + return { + attempt: _atd_read_required_field('SuccessfulAttempt', 'attempt', readAttempt, x['attempt'], x), + siblings: _atd_read_required_field('SuccessfulAttempt', 'siblings', _atd_read_array(readGoal), x['siblings'], x), + siblings_aggregated_outcome: _atd_read_required_field('SuccessfulAttempt', 'siblings_aggregated_outcome', readOutcome, x['siblings_aggregated_outcome'], x), + }; +} + +export function writeGoal(x: Goal, context: any = x): any { + return { + 'goal_text': _atd_write_required_field('Goal', 'goal_text', _atd_write_string, x.goal_text, x), + 'goal_id': _atd_write_required_field('Goal', 'goal_id', writeGoalId, x.goal_id, x), + }; +} + +export function readGoal(x: any, context: any = x): Goal { + return { + goal_text: _atd_read_required_field('Goal', 'goal_text', _atd_read_string, x['goal_text'], x), + goal_id: _atd_read_required_field('Goal', 'goal_id', readGoalId, x['goal_id'], x), + }; +} + +export function writeOutcome(x: Outcome, context: any = x): any { + switch (x.kind) { + case 'Fail': + return 'Fail' + case 'Success': + return 'Success' + } +} + +export function readOutcome(x: any, context: any = x): Outcome { + switch (x) { + case 'Fail': + return { kind: 'Fail' } + case 'Success': + return { kind: 'Success' } + default: + _atd_bad_json('Outcome', x, context) + throw new Error('impossible') + } +} + +export function writeStack(x: Stack, context: any = x): any { + return _atd_write_array(writeFrame)(x, context); +} + +export function readStack(x: any, context: any = x): Stack { + return _atd_read_array(readFrame)(x, context); +} + +export function writeFrame(x: Frame, context: any = x): any { + return { + 'rule': _atd_write_required_field('Frame', 'rule', writeRule, x.rule, x), + 'step_id': _atd_write_required_field('Frame', 'step_id', writeStepId, x.step_id, x), + 'runtime_id': _atd_write_required_field('Frame', 'runtime_id', writeRuntimeId, x.runtime_id, x), + }; +} + +export function readFrame(x: any, context: any = x): Frame { + return { + rule: _atd_read_required_field('Frame', 'rule', readRule, x['rule'], x), + step_id: _atd_read_required_field('Frame', 'step_id', readStepId, x['step_id'], x), + runtime_id: _atd_read_required_field('Frame', 'runtime_id', readRuntimeId, x['runtime_id'], x), + }; +} + +export function writeGoalId(x: GoalId, context: any = x): any { + return _atd_write_int(x, context); +} + +export function readGoalId(x: any, context: any = x): GoalId { + return _atd_read_int(x, context); +} + +export function writeStepId(x: StepId, context: any = x): any { + return _atd_write_int(x, context); +} + +export function readStepId(x: any, context: any = x): StepId { + return _atd_read_int(x, context); +} + +export function writeRuntimeId(x: RuntimeId, context: any = x): any { + return _atd_write_int(x, context); +} + +export function readRuntimeId(x: any, context: any = x): RuntimeId { + return _atd_read_int(x, context); +} + +export function writeGoalText(x: GoalText, context: any = x): any { + return _atd_write_string(x, context); +} + +export function readGoalText(x: any, context: any = x): GoalText { + return _atd_read_string(x, context); +} + +export function writeFindall(x: Findall, context: any = x): any { + return { + 'findall_goal_id': _atd_write_required_field('Findall', 'findall_goal_id', writeGoalId, x.findall_goal_id, x), + 'findall_goal_text': _atd_write_required_field('Findall', 'findall_goal_text', writeGoalText, x.findall_goal_text, x), + 'findall_cards': _atd_write_required_field('Findall', 'findall_cards', writeTrace, x.findall_cards, x), + 'findall_solution_text': _atd_write_required_field('Findall', 'findall_solution_text', writeSolutionText, x.findall_solution_text, x), + 'findall_stack': _atd_write_required_field('Findall', 'findall_stack', writeStack, x.findall_stack, x), + }; +} + +export function readFindall(x: any, context: any = x): Findall { + return { + findall_goal_id: _atd_read_required_field('Findall', 'findall_goal_id', readGoalId, x['findall_goal_id'], x), + findall_goal_text: _atd_read_required_field('Findall', 'findall_goal_text', readGoalText, x['findall_goal_text'], x), + findall_cards: _atd_read_required_field('Findall', 'findall_cards', readTrace, x['findall_cards'], x), + findall_solution_text: _atd_read_required_field('Findall', 'findall_solution_text', readSolutionText, x['findall_solution_text'], x), + findall_stack: _atd_read_required_field('Findall', 'findall_stack', readStack, x['findall_stack'], x), + }; +} + +export function writeSolutionText(x: SolutionText, context: any = x): any { + return _atd_write_array(_atd_write_string)(x, context); +} + +export function readSolutionText(x: any, context: any = x): SolutionText { + return _atd_read_array(_atd_read_string)(x, context); +} + +export function writeSuspend(x: Suspend, context: any = x): any { + return { + 'suspend_goal_id': _atd_write_required_field('Suspend', 'suspend_goal_id', writeGoalId, x.suspend_goal_id, x), + 'suspend_goal_text': _atd_write_required_field('Suspend', 'suspend_goal_text', writeGoalText, x.suspend_goal_text, x), + 'suspend_sibling': _atd_write_required_field('Suspend', 'suspend_sibling', writeGoal, x.suspend_sibling, x), + 'suspend_stack': _atd_write_required_field('Suspend', 'suspend_stack', writeStack, x.suspend_stack, x), + }; +} + +export function readSuspend(x: any, context: any = x): Suspend { + return { + suspend_goal_id: _atd_read_required_field('Suspend', 'suspend_goal_id', readGoalId, x['suspend_goal_id'], x), + suspend_goal_text: _atd_read_required_field('Suspend', 'suspend_goal_text', readGoalText, x['suspend_goal_text'], x), + suspend_sibling: _atd_read_required_field('Suspend', 'suspend_sibling', readGoal, x['suspend_sibling'], x), + suspend_stack: _atd_read_required_field('Suspend', 'suspend_stack', readStack, x['suspend_stack'], x), + }; +} + +export function writeCut(x: Cut, context: any = x): any { + return { + 'cut_goal_id': _atd_write_required_field('Cut', 'cut_goal_id', writeGoalId, x.cut_goal_id, x), + 'cut_victims': _atd_write_required_field('Cut', 'cut_victims', _atd_write_array(writeCutted), x.cut_victims, x), + }; +} + +export function readCut(x: any, context: any = x): Cut { + return { + cut_goal_id: _atd_read_required_field('Cut', 'cut_goal_id', readGoalId, x['cut_goal_id'], x), + cut_victims: _atd_read_required_field('Cut', 'cut_victims', _atd_read_array(readCutted), x['cut_victims'], x), + }; +} + +export function writeCutted(x: Cutted, context: any = x): any { + return { + 'cut_branch_for_goal': _atd_write_required_field('Cutted', 'cut_branch_for_goal', writeGoal, x.cut_branch_for_goal, x), + 'cut_branch': _atd_write_required_field('Cutted', 'cut_branch', writeUserRule, x.cut_branch, x), + }; +} + +export function readCutted(x: any, context: any = x): Cutted { + return { + cut_branch_for_goal: _atd_read_required_field('Cutted', 'cut_branch_for_goal', readGoal, x['cut_branch_for_goal'], x), + cut_branch: _atd_read_required_field('Cutted', 'cut_branch', readUserRule, x['cut_branch'], x), + }; +} + +export function writeResume(x: Resume, context: any = x): any { + return _atd_write_array(writeGoal)(x, context); +} + +export function readResume(x: any, context: any = x): Resume { + return _atd_read_array(readGoal)(x, context); +} + +export function writeChr(x: Chr, context: any = x): any { + return { + 'chr_failed_attempts': _atd_write_required_field('Chr', 'chr_failed_attempts', _atd_write_array(writeChrAttempt), x.chr_failed_attempts, x), + 'chr_successful_attempts': _atd_write_required_field('Chr', 'chr_successful_attempts', _atd_write_array(writeSuccessfulChrAttempt), x.chr_successful_attempts, x), + 'chr_store_before': _atd_write_required_field('Chr', 'chr_store_before', _atd_write_array(writeGoal), x.chr_store_before, x), + 'chr_store_after': _atd_write_required_field('Chr', 'chr_store_after', _atd_write_array(writeGoal), x.chr_store_after, x), + }; +} + +export function readChr(x: any, context: any = x): Chr { + return { + chr_failed_attempts: _atd_read_required_field('Chr', 'chr_failed_attempts', _atd_read_array(readChrAttempt), x['chr_failed_attempts'], x), + chr_successful_attempts: _atd_read_required_field('Chr', 'chr_successful_attempts', _atd_read_array(readSuccessfulChrAttempt), x['chr_successful_attempts'], x), + chr_store_before: _atd_read_required_field('Chr', 'chr_store_before', _atd_read_array(readGoal), x['chr_store_before'], x), + chr_store_after: _atd_read_required_field('Chr', 'chr_store_after', _atd_read_array(readGoal), x['chr_store_after'], x), + }; +} + +export function writeChrAttempt(x: ChrAttempt, context: any = x): any { + return { + 'chr_text': _atd_write_required_field('ChrAttempt', 'chr_text', writeChrText, x.chr_text, x), + 'chr_loc': _atd_write_required_field('ChrAttempt', 'chr_loc', writeFileLocation, x.chr_loc, x), + 'chr_condition_cards': _atd_write_required_field('ChrAttempt', 'chr_condition_cards', writeTrace, x.chr_condition_cards, x), + }; +} + +export function readChrAttempt(x: any, context: any = x): ChrAttempt { + return { + chr_text: _atd_read_required_field('ChrAttempt', 'chr_text', readChrText, x['chr_text'], x), + chr_loc: _atd_read_required_field('ChrAttempt', 'chr_loc', readFileLocation, x['chr_loc'], x), + chr_condition_cards: _atd_read_required_field('ChrAttempt', 'chr_condition_cards', readTrace, x['chr_condition_cards'], x), + }; +} + +export function writeSuccessfulChrAttempt(x: SuccessfulChrAttempt, context: any = x): any { + return { + 'chr_attempt': _atd_write_required_field('SuccessfulChrAttempt', 'chr_attempt', writeChrAttempt, x.chr_attempt, x), + 'chr_removed_goals': _atd_write_required_field('SuccessfulChrAttempt', 'chr_removed_goals', _atd_write_array(writeGoalId), x.chr_removed_goals, x), + 'chr_new_goals': _atd_write_required_field('SuccessfulChrAttempt', 'chr_new_goals', _atd_write_array(writeGoal), x.chr_new_goals, x), + }; +} + +export function readSuccessfulChrAttempt(x: any, context: any = x): SuccessfulChrAttempt { + return { + chr_attempt: _atd_read_required_field('SuccessfulChrAttempt', 'chr_attempt', readChrAttempt, x['chr_attempt'], x), + chr_removed_goals: _atd_read_required_field('SuccessfulChrAttempt', 'chr_removed_goals', _atd_read_array(readGoalId), x['chr_removed_goals'], x), + chr_new_goals: _atd_read_required_field('SuccessfulChrAttempt', 'chr_new_goals', _atd_read_array(readGoal), x['chr_new_goals'], x), + }; +} + +export function writeChrText(x: ChrText, context: any = x): any { + return _atd_write_string(x, context); +} + +export function readChrText(x: any, context: any = x): ChrText { + return _atd_read_string(x, context); +} + + +///////////////////////////////////////////////////////////////////// +// Runtime library +///////////////////////////////////////////////////////////////////// + +export type Option = null | { value: T } + +function _atd_missing_json_field(type_name: string, json_field_name: string) { + throw new Error(`missing field '${json_field_name}'` + + ` in JSON object of type '${type_name}'`) +} + +function _atd_missing_ts_field(type_name: string, ts_field_name: string) { + throw new Error(`missing field '${ts_field_name}'` + + ` in TypeScript object of type '${type_name}'`) +} + +function _atd_bad_json(expected_type: string, json_value: any, context: any) { + let value_str = JSON.stringify(json_value) + if (value_str.length > 200) + value_str = value_str.substring(0, 200) + '…'; + + throw new Error(`incompatible JSON value where` + + ` type '${expected_type}' was expected: '${value_str}'.` + + ` Occurs in '${JSON.stringify(context)}'.`) +} + +function _atd_bad_ts(expected_type: string, ts_value: any, context: any) { + let value_str = JSON.stringify(ts_value) + if (value_str.length > 200) + value_str = value_str.substring(0, 200) + '…'; + + throw new Error(`incompatible TypeScript value where` + + ` type '${expected_type}' was expected: '${value_str}'.` + + ` Occurs in '${JSON.stringify(context)}'.`) +} + +function _atd_check_json_tuple(len: number /*int*/, x: any, context: any) { + if (! Array.isArray(x) || x.length !== len) + _atd_bad_json('tuple of length ' + len, x, context); +} + +function _atd_read_unit(x: any, context: any): null { + if (x === null) + return null + else { + _atd_bad_json('null', x, context) + throw new Error('impossible') + } +} + +function _atd_read_bool(x: any, context: any): boolean { + if (typeof x === 'boolean') + return x + else { + _atd_bad_json('boolean', x, context) + throw new Error('impossible') + } +} + +function _atd_read_int(x: any, context: any): number /*int*/ { + if (Number.isInteger(x)) + return x + else { + _atd_bad_json('integer', x, context) + throw new Error('impossible') + } +} + +function _atd_read_float(x: any, context: any): number { + if (isFinite(x)) + return x + else { + _atd_bad_json('number', x, context) + throw new Error('impossible') + } +} + +function _atd_read_string(x: any, context: any): string { + if (typeof x === 'string') + return x + else { + _atd_bad_json('string', x, context) + throw new Error('impossible') + } +} + +function _atd_read_required_field(type_name: string, + field_name: string, + read_elt: (x: any, context: any) => T, + x: any, + context: any): T { + if (x === undefined) { + _atd_missing_json_field(type_name, field_name) + throw new Error('impossible') + } + else + return read_elt(x, context) +} + +function _atd_read_optional_field(read_elt: (x: any, context: any) => T, + x: any, + context: any): T { + if (x === undefined || x === null) + return x + else + return read_elt(x, context) +} + +function _atd_read_field_with_default(read_elt: (x: any, context: any) => T, + default_: T, + x: any, + context: any): T { + if (x === undefined || x === null) + return default_ + else + return read_elt(x, context) +} + +function _atd_read_option(read_elt: (x: any, context: any) => T): + (x: any, context: any) => Option { + function read_option(x: any, context: any): Option { + if (x === 'None') + return null + else { + _atd_check_json_tuple(2, x, context); + switch (x[0]) { + case 'Some': + return { value: read_elt(x[1], context) } + default: + _atd_bad_json('option', x, context) + throw new Error('impossible') + } + } + } + return read_option +} + +function _atd_read_nullable(read_elt: (x: any, context: any) => T): + (x: any, context: any) => T | null { + function read_nullable(x: any, context: any): T | null { + if (x === null) + return null + else + return read_elt(x, context) + } + return read_nullable +} + +function _atd_read_array(read_elt: (x: any, context: any) => T): + (elts: any, context: any) => T[] { + function read_array(elts: any, context: any): T[] { + if (Array.isArray(elts)) + return elts.map((x) => read_elt(x, elts)) + else { + _atd_bad_json('array', elts, context) + throw new Error('impossible') + } + } + return read_array +} + +function _atd_read_assoc_array_into_map( + read_key: (key: any, context: any) => K, + read_value: (value: any, context: any) => V + ): (x: any, context: any) => Map { + function read_assoc(elts: any, context: any): Map { + if (Array.isArray(elts)) { + const res = new Map([]) + for (const x of elts) { + if (Array.isArray(x) && x.length === 2) + res.set(read_key(x[0], x), read_value(x[1], x)) + else { + _atd_bad_json('pair', x, elts) + throw new Error('impossible') + } + } + return res + } + else { + _atd_bad_json('array', elts, context) + throw new Error('impossible') + } + } + return read_assoc +} + +function _atd_read_assoc_object_into_map( + read_value: (value: any, context: any) => T + ): (x: any, context: any) => Map { + function read_assoc(elts: any, context: any): Map { + if (typeof elts === 'object') { + const res = new Map([]) + for (const [key, value] of Object.entries(elts)) + res.set(key, read_value(value, elts)) + return res + } + else { + _atd_bad_json('object', elts, context) + throw new Error('impossible') + } + } + return read_assoc +} + +function _atd_read_assoc_object_into_array( + read_value: (value: any, context: any) => T + ): (x: any, context: any) => [string, T][] { + function read_assoc(elts: any, context: any): [string, T][] { + if (typeof elts === 'object') { + const res: [string, T][] = [] + for (const [key, value] of Object.entries(elts)) + res.push([key, read_value(value, elts)]) + return res + } + else { + _atd_bad_json('object', elts, context) + throw new Error('impossible') + } + } + return read_assoc +} + +function _atd_write_unit(x: any, context: any) { + if (x === null) + return x + else { + _atd_bad_ts('null', x, context) + throw new Error('impossible') + } +} + +function _atd_write_bool(x: any, context: any): boolean { + if (typeof x === 'boolean') + return x + else { + _atd_bad_ts('boolean', x, context) + throw new Error('impossible') + } +} + +function _atd_write_int(x: any, context: any): number /*int*/ { + if (Number.isInteger(x)) + return x + else { + _atd_bad_ts('integer', x, context) + throw new Error('impossible') + } +} + +function _atd_write_float(x: any, context: any): number { + if (isFinite(x)) + return x + else { + _atd_bad_ts('number', x, context) + throw new Error('impossible') + } +} + +function _atd_write_string(x: any, context: any): string { + if (typeof x === 'string') + return x + else { + _atd_bad_ts('string', x, context) + throw new Error('impossible') + } +} + +function _atd_write_option(write_elt: (x: T, context: any) => any): + (elts: Option, context: any) => any { + function write_option(x: Option, context: any): any { + if (x === null) + return 'None' + else + return ['Some', write_elt(x.value, context)] + } + return write_option +} + +function _atd_write_nullable(write_elt: (x: T, context: any) => any): + (x: T | null, context: any) => any { + function write_option(x: T | null, context: any): any { + if (x === null) + return null + else + return write_elt(x, context) + } + return write_option +} + +function _atd_write_array(write_elt: (elt: T, context: any) => any): + (elts: T[], context: any) => any { + return ((elts: T[], context: any): any => + elts.map((x) => write_elt(x, elts)) + ) +} + +function _atd_write_assoc_map_to_array( + write_key: (key: K, context: any) => any, + write_value: (value: V, context: any) => any + ): (elts: Map, context: any) => any { + function write_assoc(elts: Map, context: any): any { + const res: any = [] + elts.forEach((value: V, key: K) => + res.push([write_key(key, elts), write_value(value, elts)]) + ) + return res + } + return write_assoc +} + +function _atd_write_assoc_map_to_object( + write_value: (value: T, context: any) => any + ): (elts: Map, context: any) => any { + function write_assoc(elts: Map, context: any): any { + const res: any = {} + elts.forEach((value: T, key: string) => + res[key] = write_value(value, elts) + ) + return res + } + return write_assoc +} + +function _atd_write_assoc_array_to_object( + write_value: (value: T, context: any) => any + ): (elts: [string, T][], context: any) => any { + function write_assoc(elts: [string, T][], context: any): any { + const res: any = {} + for (const [key, value] of elts) + res[key] = write_value(value, elts) + return res + } + return write_assoc +} + +function _atd_write_required_field(type_name: string, + field_name: string, + write_elt: (x: T, context: any) => any, + x: T, + context: any): any { + if (x === undefined) { + _atd_missing_ts_field(type_name, field_name) + throw new Error('impossible') + } + else + return write_elt(x, context) +} + +function _atd_write_optional_field(write_elt: (x: T, context: any) => any, + x: T | undefined, + context: any): any { + if (x === undefined || x === null) + return x + else + return write_elt(x, context) +} + +function _atd_write_field_with_default( + write_elt: (x: T, context: any) => any, + default_: T, + x: T, + context: any +): T { + const value = (x === undefined || x === null) ? default_ : x + return write_elt(value, context) +} +