|
| 1 | +/** @satisfies {PyretModule} */ |
| 2 | +/* |
| 3 | + * This deals with the module return value from the Pyret runtime. |
| 4 | + * |
| 5 | + * Due to the representation of pyret values, we cannot pass values resulting from |
| 6 | + * the repl to the host without first serializing them. The `load-lib` module is |
| 7 | + * intended to do this, but doesn't provide very rich error displaying, nor give |
| 8 | + * complete raw information about the checks that were run. |
| 9 | + * |
| 10 | + * All errors will be rendered |
| 11 | + */ |
| 12 | +({ |
| 13 | + requires: [ |
| 14 | + {"import-type": "dependency", protocol: "js-file", args: ["./bridge"]}, |
| 15 | + ], |
| 16 | + provides: { |
| 17 | + values: { |
| 18 | + "extract-check-results": ["arrow", ["Any"], ["List", "Any"]], |
| 19 | + }, |
| 20 | + }, |
| 21 | + nativeRequires: ["pyret-base/js/exn-stack-parser"], |
| 22 | + theModule: function (runtime, _namespace, _uri, bridge, stackLib) { |
| 23 | + "use strict"; |
| 24 | + const EXIT_SUCCESS = 0; |
| 25 | + const EXIT_ERROR = 1; |
| 26 | + const EXIT_ERROR_RENDERING_ERROR = 2; |
| 27 | + const EXIT_ERROR_DISPLAYING_ERROR = 3; |
| 28 | + const EXIT_ERROR_CHECK_FAILURES = 4; |
| 29 | + const EXIT_ERROR_JS = 5; |
| 30 | + const EXIT_ERROR_UNKNOWN = 6; |
| 31 | + |
| 32 | + /** @typedef {{val: { runtime: PyretRuntime; result: any; program: any; realm: any; } }} ModuleReturn */ |
| 33 | + |
| 34 | + /** |
| 35 | + * @param {ModuleReturn} mr |
| 36 | + * @param {string} field |
| 37 | + */ |
| 38 | + function checkSuccess(mr, field) { |
| 39 | + if (!mr.val) { |
| 40 | + console.error(mr); |
| 41 | + runtime.ffi.throwMessageException(`Tried to get ${field} of non-successful module compilation.`); |
| 42 | + } |
| 43 | + if (!mr.val.runtime.isSuccessResult(mr.val.result)) { |
| 44 | + console.error(mr.val.result); |
| 45 | + console.error(mr.val.result.exn); |
| 46 | + runtime.ffi.throwMessageException(`Tried to get ${field} of non-successful module execution.`); |
| 47 | + } |
| 48 | + } |
| 49 | + |
| 50 | + /** |
| 51 | + * @param {ModuleReturn} mr |
| 52 | + */ |
| 53 | + function getModuleResultChecks(mr) { |
| 54 | + checkSuccess(mr, "checks"); |
| 55 | + const checks = mr.val.runtime.getField(mr.val.result.result, "checks"); |
| 56 | + if (mr.val.runtime.ffi.isList(checks)) { |
| 57 | + return checks; |
| 58 | + } else { |
| 59 | + return mr.val.runtime.ffi.makeList([]); |
| 60 | + } |
| 61 | + } |
| 62 | + |
| 63 | + /** |
| 64 | + * @param {ModuleReturn} mr |
| 65 | + */ |
| 66 | + function extractCheckResults(mr) { |
| 67 | + runtime.checkArity(1, arguments, "extract-check-results", false); |
| 68 | + runtime.checkOpaque(/** @type {any} */ (mr)); |
| 69 | + return runtime.pauseStack(function (restarter) { |
| 70 | + const execRt = mr.val.runtime; |
| 71 | + const gf = execRt.getField; |
| 72 | + const checkerMod = execRt.modules["builtin://checker"]; |
| 73 | + const checker = gf(checkerMod, "provide-plus-types"); |
| 74 | + const checkerVals = gf(checker, "values"); |
| 75 | + const renderCheckResults = gf(checkerVals, "render-check-results-stack"); |
| 76 | + const realm = runtime.getField(mr.val.realm, "realm").val; |
| 77 | + const getStack = execRt.makeFunction((/** @type {any} */ err) => { |
| 78 | + const pyretStack = stackLib.convertExceptionToPyretStackTrace(err.val, realm); |
| 79 | + const locArray = pyretStack.map(execRt.makeSrcloc); |
| 80 | + const locList = execRt.ffi.makeList(locArray); |
| 81 | + return locList; |
| 82 | + }, "get-stack"); |
| 83 | + |
| 84 | + const blockResults = getModuleResultChecks(mr); |
| 85 | + |
| 86 | + // const results = []; |
| 87 | + // for (const blockResult of execRt.ffi.toArray(blockResults)) { |
| 88 | + // const name = gf(blockResult, "name"); |
| 89 | + // const loc = gf(blockResult, "loc"); |
| 90 | + // const kwCheck = gf(blockResult, "keyword-check"); |
| 91 | + // const testRes = gf(blockResult, "test-results"); |
| 92 | + // const maybeError = gf(blockResult, "maybe-err"); |
| 93 | + // |
| 94 | + // const bridged = { |
| 95 | + // name: name, |
| 96 | + // loc: bridge.translateSrcloc(execRt, loc), |
| 97 | + // |
| 98 | + // } |
| 99 | + // |
| 100 | + // results.push(bridged) |
| 101 | + // |
| 102 | + // |
| 103 | + // console.log("Block result:"); |
| 104 | + // console.dir(blockResult) |
| 105 | + // console.dir(execRt.toRepr(blockResult)); |
| 106 | + // } |
| 107 | + |
| 108 | + |
| 109 | + |
| 110 | + |
| 111 | + // edBridge.translateErrorDisplay(execRt, ...) |
| 112 | + |
| 113 | + execRt.runThunk( |
| 114 | + function() {return renderCheckResults.app(blockResults, getStack, "json")}, |
| 115 | + function (/** @type {any} */ renderedCheckResults) { |
| 116 | + runtime.console.dir(renderedCheckResults) |
| 117 | + const resumeWith = { |
| 118 | + message: "Unknown error!", |
| 119 | + "exit-code": EXIT_ERROR_UNKNOWN, |
| 120 | + }; |
| 121 | + |
| 122 | + if (execRt.isSuccessResult(renderedCheckResults)) { |
| 123 | + resumeWith.message = execRt.unwrap( |
| 124 | + execRt.getField(renderedCheckResults.result, "message") |
| 125 | + ); |
| 126 | + const errs = execRt.getField(renderedCheckResults.result, "errored"); |
| 127 | + const failed = execRt.getField(renderedCheckResults.result, "failed"); |
| 128 | + if (errs !== 0 || failed !== 0) { |
| 129 | + resumeWith["exit-code"] = EXIT_ERROR_CHECK_FAILURES; |
| 130 | + } else { |
| 131 | + resumeWith["exit-code"] = EXIT_SUCCESS; |
| 132 | + } |
| 133 | + } else if (execRt.isFailureResult(renderedCheckResults)) { |
| 134 | + console.error(renderedCheckResults.exn); |
| 135 | + resumeWith.message = "There was an exception while formatting the check results"; |
| 136 | + resumeWith["exit-code"] = EXIT_ERROR_RENDERING_ERROR; |
| 137 | + } |
| 138 | + |
| 139 | + restarter.resume( |
| 140 | + runtime.makeObject({ |
| 141 | + message: runtime.makeString(resumeWith.message), |
| 142 | + "exit-code": runtime.makeNumber(resumeWith["exit-code"]), |
| 143 | + }) |
| 144 | + ); |
| 145 | + } |
| 146 | + ); |
| 147 | + }); |
| 148 | + } |
| 149 | + return runtime.makeModuleReturn({ |
| 150 | + "extract-check-results": runtime.makeFunction(extractCheckResults, "extract-check-results"), |
| 151 | + }, {}); |
| 152 | + }, |
| 153 | +}) |
0 commit comments