90 lines
2.2 KiB
JavaScript
90 lines
2.2 KiB
JavaScript
"use strict";
|
|
// Preserves Annotations.
|
|
|
|
if (require('./singletonmodule.js')('leastfixedpoint.com/preserves',
|
|
require('../package.json').version,
|
|
'annotations.js',
|
|
module)) return;
|
|
|
|
const { Record, List, Map, Set, is, hash } = require('./values.js');
|
|
const { PreserveOn, AsPreserve } = require('./symbols.js');
|
|
|
|
function Annotated(item) {
|
|
this.annotations = [];
|
|
this.item = item;
|
|
}
|
|
|
|
Annotated.prototype[AsPreserve] = function () {
|
|
return this;
|
|
};
|
|
|
|
Annotated.prototype[PreserveOn] = function (encoder) {
|
|
for (const a of this.annotations) {
|
|
encoder.header(0, 0, 5);
|
|
encoder.push(a);
|
|
}
|
|
encoder.push(this.item);
|
|
};
|
|
|
|
Annotated.prototype.strip = function (depth) {
|
|
return stripAnnotations(this, depth);
|
|
};
|
|
|
|
Annotated.prototype.peel = function () {
|
|
return stripAnnotations(this, 1);
|
|
};
|
|
|
|
Annotated.prototype.equals = function (other) {
|
|
return isAnnotated(other) && is(this.item, other.item);
|
|
};
|
|
|
|
Annotated.prototype.hashCode = function () {
|
|
return hash(this.item);
|
|
};
|
|
|
|
function isAnnotated(v) {
|
|
return (v instanceof Annotated);
|
|
}
|
|
|
|
function stripAnnotations(v, depth) {
|
|
function step(v, depth) {
|
|
if (depth === 0) return v;
|
|
if (!isAnnotated(v)) return v;
|
|
|
|
const nextDepth = depth - 1;
|
|
function walk(v) { return step(v, nextDepth); }
|
|
|
|
if (v.item instanceof Record) {
|
|
return new Record(step(v.item.label, depth), v.item.fields.map(walk));
|
|
} else if (List.isList(v.item)) {
|
|
return v.item.map(walk);
|
|
} else if (Set.isSet(v.item)) {
|
|
return v.item.map(walk);
|
|
} else if (Map.isMap(v.item)) {
|
|
return v.item.mapEntries((e) => [walk(e[0]), walk(e[1])]);
|
|
} else if (isAnnotated(v.item)) {
|
|
const e = new Error("Improper annotation structure");
|
|
e.irritant = v;
|
|
throw e;
|
|
} else {
|
|
return v.item;
|
|
}
|
|
}
|
|
return step(v, (depth === void 0) ? Infinity : depth);
|
|
}
|
|
|
|
function annotate(v, ...anns) {
|
|
if (!isAnnotated(v)) {
|
|
v = new Annotated(v);
|
|
}
|
|
anns.forEach((a) => v.annotations.push(a));
|
|
return v;
|
|
}
|
|
|
|
Object.assign(module.exports, {
|
|
Annotated,
|
|
isAnnotated,
|
|
stripAnnotations,
|
|
annotate,
|
|
});
|