js-slang
Version:
Javascript-based implementations of Source, written in Typescript
201 lines • 8.03 kB
JavaScript
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
;