UNPKG

js-slang

Version:

Javascript-based implementations of Source, written in Typescript

201 lines 8.03 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.decodeValue = exports.schemeVisualise = exports.showSchemeData = exports.mapErrorToScheme = exports.mapResultToScheme = void 0; const closure_1 = require("../../cse-machine/closure"); const src_1 = require("./scm-slang/src"); const source_scheme_library_1 = require("./scm-slang/src/stdlib/source-scheme-library"); const types_1 = require("../../types"); const mapper_1 = require("../mapper"); function mapResultToScheme(res) { if (res.status === "finished" || res.status === "suspended-non-det") { return { ...res, value: decodeValue(res.value), representation: showSchemeData(res.value) }; } return res; } exports.mapResultToScheme = mapResultToScheme; // Given an error, decode its message if and // only if an encoded value may exist in it. function mapErrorToScheme(error) { if (error.type === types_1.ErrorType.SYNTAX) { // Syntax errors are not encoded. return error; } const newExplain = decodeString(error.explain()); const newElaborate = decodeString(error.elaborate()); return { ...error, explain: () => newExplain, elaborate: () => newElaborate }; } exports.mapErrorToScheme = mapErrorToScheme; function showSchemeData(data) { return schemeVisualise(decodeValue(data)); } exports.showSchemeData = showSchemeData; function decodeString(str) { return str.replace(/\$scheme_[\w$]+|\$\d+\$/g, match => { return (0, src_1.decode)(match); }); } // Given any value, change the representation of it to // the required scheme representation. function schemeVisualise(x) { // hack: builtins are represented using an object with a toString method // and minArgsNeeded. // so to detect these, we use a function that checks for these function isBuiltinFunction(x) { return x.minArgsNeeded !== undefined && x.toString !== undefined; } function stringify(x) { if ((0, source_scheme_library_1.null$63$)(x)) { return '()'; } else if (x === undefined) { return 'undefined'; } else if (typeof x === 'string') { return `"${x}"`; } else if ((0, source_scheme_library_1.number$63$)(x)) { return x.toString(); } else if ((0, source_scheme_library_1.boolean$63$)(x)) { return x ? '#t' : '#f'; } else if (x instanceof closure_1.default) { const node = x.originalNode; const parameters = node.params.map((param) => param.type === "Identifier" ? param.name : ". " + param.argument.name) .join(' ') .trim(); return `#<procedure (${parameters})>`; } else if (isBuiltinFunction(x) || typeof x === 'function') { function decodeParams(params) { // if parameter starts with ... then it is a rest parameter const convertedparams = params .map(param => { if (param.startsWith('...')) { return `. ${param.slice(3)}`; } return param; }) .map(decodeString); return convertedparams.join(' '); } // take the name and parameter out of the defined function name const name = decodeString(x.funName); const parameters = decodeParams(x.funParameters); return `#<builtin-procedure ${name} (${parameters})>`; } else if ((0, source_scheme_library_1.circular$45$list$63$)(x)) { return '(circular list)'; } else if ((0, source_scheme_library_1.dotted$45$list$63$)(x) && (0, source_scheme_library_1.pair$63$)(x)) { let string = '('; let current = x; while ((0, source_scheme_library_1.pair$63$)(current)) { string += `${schemeVisualise((0, source_scheme_library_1.car)(current))} `; current = (0, source_scheme_library_1.cdr)(current); } return string.trim() + ` . ${schemeVisualise(current)})`; } else if ((0, source_scheme_library_1.proper$45$list$63$)(x)) { let string = '('; let current = x; while (current !== null) { string += `${schemeVisualise((0, source_scheme_library_1.car)(current))} `; current = (0, source_scheme_library_1.cdr)(current); } return string.trim() + ')'; } else if ((0, source_scheme_library_1.vector$63$)(x)) { let string = '#('; for (let i = 0; i < x.length; i++) { string += `${schemeVisualise(x[i])} `; } return string.trim() + ')'; } else { return x.toString(); } } // return an object with a toString method that returns the stringified version of x return new mapper_1.Representation(stringify(x)); } exports.schemeVisualise = schemeVisualise; // Given any value, decode it if and // only if an encoded value may exist in it. // this function is used to accurately display // values in the REPL. function decodeValue(x) { // helper version of list_tail that assumes non-null return value function list_tail(xs, i) { if (i === 0) { return xs; } else { return list_tail((0, source_scheme_library_1.list$45$tail)(xs), i - 1); } } if ((0, source_scheme_library_1.circular$45$list$63$)(x)) { // May contain encoded strings. let circular_pair_index = -1; const all_pairs = []; // iterate through all pairs in the list until we find the circular pair let current = x; while (current !== null) { if (all_pairs.includes(current)) { circular_pair_index = all_pairs.indexOf(current); break; } all_pairs.push(current); current = (0, source_scheme_library_1.cdr)(current); } // assemble a new list using the elements in all_pairs let new_list = null; for (let i = all_pairs.length - 1; i >= 0; i--) { new_list = (0, source_scheme_library_1.cons)(decodeValue((0, source_scheme_library_1.car)(all_pairs[i])), new_list); } // finally we can set the last cdr of the new list to the circular-pair itself const circular_pair = list_tail(new_list, circular_pair_index); (0, source_scheme_library_1.set$45$cdr$33$)((0, source_scheme_library_1.last$45$pair)(new_list), circular_pair); return new_list; } else if ((0, source_scheme_library_1.pair$63$)(x)) { // May contain encoded strings. return (0, source_scheme_library_1.cons)(decodeValue((0, source_scheme_library_1.car)(x)), decodeValue((0, source_scheme_library_1.cdr)(x))); } else if ((0, source_scheme_library_1.vector$63$)(x)) { // May contain encoded strings. return x.map(decodeValue); } else if (x instanceof closure_1.default) { const newNode = (0, src_1.estreeDecode)(x.originalNode); // not a big fan of mutation, but we assert we will never need the original node again anyway x.node = newNode; x.originalNode = newNode; return x; } else if (typeof x === 'function') { // copy x to avoid modifying the original object const newX = { ...x }; const newString = decodeString(x.toString()); // change the toString method to return the decoded string newX.toString = () => newString; return newX; } else { // string, number, boolean, null, undefined // no need to decode. return x; } } exports.decodeValue = decodeValue; //# sourceMappingURL=scheme-mapper.js.map