"use strict"; // "Structures": Simple named-tuple-like records. var Immutable = require("immutable"); var $Special = require('./special.js'); /* Defined here rather than in trie.js because we need it in makeConstructor. */ var __ = new $Special("wildcard"); /* wildcard marker */ function StructureType(label, arity) { this.label = label; this.arity = arity; this.pattern = this.instantiate(Immutable.Repeat(__, arity).toArray()); var self = this; this.ctor = function () { return self.instantiate(Array.prototype.slice.call(arguments)); }; this.ctor.meta = this; this.ctor.pattern = this.pattern; this.ctor.isClassOf = function (v) { return self.isClassOf(v); }; } function makeConstructor(label, fieldNames) { return new StructureType(label, fieldNames.length).ctor; } StructureType.prototype.equals = function (other) { if (!(other instanceof StructureType)) return false; return this.arity === other.arity && this.label === other.label; }; StructureType.prototype.instantiate = function (fields) { return new Structure(this, fields); }; StructureType.prototype.isClassOf = function (v) { return v && (v instanceof Structure) && (v.meta.equals(this)); }; function Structure(meta, fields) { if (!isStructureType(meta)) { throw new Error("Structure: requires structure type"); } if (fields.length !== meta.arity) { throw new Error("Structure: cannot instantiate meta "+JSON.stringify(meta.label)+ " expecting "+meta.arity+" fields with "+fields.length+" fields"); } this.meta = meta; this.length = meta.arity; this.fields = fields.slice(0); for (var i = 0; i < fields.length; i++) { this[i] = fields[i]; } } Structure.prototype.clone = function () { return new Structure(this.meta, this.fields); }; Structure.prototype.get = function (index) { return this[index]; }; Structure.prototype.set = function (index, value) { var s = this.clone(); s[index] = s.fields[index] = value; }; function reviveStructs(j) { if (Array.isArray(j)) { return j.map(reviveStructs); } if ((j !== null) && typeof j === 'object') { if ((typeof j['@type'] === 'string') && Array.isArray(j['fields'])) { return (new StructureType(j['@type'], j['fields'].length)).instantiate(j['fields']); } else { for (var k in j) { if (Object.prototype.hasOwnProperty.call(j, k)) { j[k] = reviveStructs(j[k]); } } return j; } } return j; } function reviver(k, v) { if (k === '') { return reviveStructs(v); } return v; }; Structure.prototype.toJSON = function () { return { '@type': this.meta.label, 'fields': this.fields }; }; function isStructureType(v) { return v && (v instanceof StructureType); } function isStructure(v) { return v && (v instanceof Structure); } /////////////////////////////////////////////////////////////////////////// module.exports.__ = __; module.exports.StructureType = StructureType; module.exports.makeConstructor = makeConstructor; module.exports.Structure = Structure; module.exports.reviveStructs = reviveStructs; module.exports.reviver = reviver; module.exports.isStructureType = isStructureType; module.exports.isStructure = isStructure;