Skip to content

Instantly share code, notes, and snippets.

@kellywoo
Last active May 4, 2021 14:27
Show Gist options
  • Save kellywoo/9bd664eb38c174e058368203681efea0 to your computer and use it in GitHub Desktop.
Save kellywoo/9bd664eb38c174e058368203681efea0 to your computer and use it in GitHub Desktop.
6th homework
const {stringify} = (() => {
// simple
const strRegexp = [[/\\/g, '\\\\'], [/\n/g, '\\n'], [/\t/g, '\\t'], [/\v/g, '\\v'], [/[\b]/g, '\\b'], [/[\r]/g, '\\r'], [/"/g, '\\"']]
class ResultRecords {
constructor() {
this.data = [];
}
}
// complex
const complexType = {
array: 'array',
object: 'object',
itemRecord: 'itemRecord',
toJson: 'toJson',
}
const complexHandlers = {
[complexType.array]: {
createGen: function* (obj) {
for (const v of obj) yield {value: v};
},
createRecords: () => {
return new class extends ResultRecords {
join() {
return `[${this.data.join(',')}]`;
}
push(str) {
this.data.push(str)
}
}
},
},
[complexType.object]: {
createGen: function* (obj) {
for (const k in obj) if (obj.hasOwnProperty(k) && typeof obj[k] !== 'function') yield {
key: k,
value: obj[k]
};
},
createRecords: () => {
return new class extends ResultRecords {
join() {
return `{${this.data.map((m) => {
return `${typeHandler.string(m[0].toString())}:${m[1]}`;
}).join(',')}}`
}
push(str, key) {
this.data.push([key, str])
}
}
},
}
}
const typeHandler = {
default: () => 'null',
boolean: v => v.toString(),
number: v => {
if (Number.isNaN(v) || !Number.isFinite(v)) {
return typeHandler.default();
}
return v === 0 ? '0' : v.toString();
},
string: (s) => {
let str = s;
for (let i = 0; i < strRegexp.length; i++) {
if (!str.length) break;
str = str.replace(strRegexp[i][0], strRegexp[i][1]);
}
return `"${str}"`;
},
[complexType.itemRecord]: (record) => {
return record.join();
}
}
const typeRouter = (v) => {
const getType = (v, checkToJSON = false) => {
const t = typeof v
if (t === 'object') {
switch (true) {
case !v:
return 'null';
case v instanceof ResultRecords:
return complexType.itemRecord;
case checkToJSON && typeof v.toJSON === 'function':
return complexType.toJson;
case Array.isArray(v):
return complexType.array;
default:
return complexType.object;
}
} else {
return t;
}
}
let value = v;
let stack = null;
let key = null;
while (1) {
if (stack) {
const next = stack.gen.next();
if (next.done) {
const currentStr = stack.records.join();
if (stack.previous) {
key = stack.key;
stack = stack.previous;
stack.records.push(currentStr, key);
continue;
} else {
return currentStr;
}
} else {
const nextValue = next.value;
value = nextValue.value;
key = nextValue.key;
}
}
let t = getType(value, true);
if (t === complexType.toJson) {
value = value.toJSON();
t = getType(value);
}
if ([complexType.array, complexType.object].includes(t)) {
stack = {
gen: complexHandlers[t].createGen(value),
records: complexHandlers[t].createRecords(),
previous: stack,
key,
}
continue;
} else {
const str = (typeHandler[t] || typeHandler.default)(value);
if (stack) {
stack.records.push(str, key);
} else {
return str
}
}
}
}
const stringify = (v) => {
return typeRouter(v, null);
}
return {stringify};
})();
const parse = (str, storage) => {
if(!str) return storage ? storage.value : str;
let temp
switch (true) {
case str[0] === '[':
const value = [];
if (storage) {
storage.value.push(value);
}
return parse(str.slice(1), {type: 'array', value, prev: storage});
case Boolean(temp = str.match(/^\][\s|\n]*,?/)):
if (storage.prev) {
return parse(str.slice(temp[0].length), storage.prev);
} else {
return storage.value;
}
case Boolean(temp = str.match(/^[\s|\n]+/)):
return parse(str.slice(temp[0].length), storage);
case Boolean(temp = str.match(/(null|false|true)[\s|\n]*,?/)): {
const value = temp[1] === 'null' ? null : temp[1] === 'true';
if (storage) {
storage.value.push(value);
return parse(str.slice(temp[0].length), storage.prev);
} else {
return value;
}
}
case Boolean(temp = str.match(/^([+-]?([0-9]+|[0-9]*(.|e)?[0-9]+))[\s|\n]*,?/)): {
const value = Number(temp[1]);
if (storage) {
storage.value.push(value);
return parse(str.slice(temp[0].length), storage);
} else {
return value;
}
}
case Boolean(temp = str.match(/^"((?:\\"|[^"])*)"[\s|\n]*,?/)):{
if (storage) {
storage.value.push(temp[1].replace('\\"', '"'));
return parse(str.slice(temp[0].length), storage);
} else {
return temp[1];
}
}
default:
throw 'no support';
}
}
const {stringify} = (() => {
// simple
const strRegexp = [[/\\/g, '\\\\'], [/\n/g, '\\n'], [/\t/g, '\\t'], [/\v/g, '\\v'], [/[\b]/g, '\\b'], [/[\r]/g, '\\r'], [/"/g, '\\"']]
class ResultRecords {
constructor() {
this.data = [];
}
}
// complex
const complexType = {
array: 'array',
object: 'object',
itemRecord: 'itemRecord',
toJson: 'toJson',
}
const complexHandlers = {
[complexType.array]: {
createGen: function* (obj) {
for (const v of obj) yield {value: v};
},
createRecords: () => {
return new class extends ResultRecords {
join() {
return `[${this.data.join(',')}]`;
}
push(str) {
this.data.push(str)
}
}
},
},
[complexType.object]: {
createGen: function* (obj) {
for (const k in obj) if (obj.hasOwnProperty(k) && typeof obj[k] !== 'function') yield {key: k, value: obj[k]};
},
createRecords: () => {
return new class extends ResultRecords {
join() {
return `{${this.data.map((m) => {
return `${typeHandler.string(m[0].toString())}:${m[1]}`;
}).join(',')}}`
}
push(str, key) {
this.data.push([key, str])
}
}
},
}
}
const typeHandler = {
default: () => 'null',
boolean: v => v.toString(),
number: v => {
if (isNaN(v) || !isFinite(v)) {
return typeHandler.default();
}
return v === 0 ? '0' : v.toString();
},
string: (str, i = 0) => {
if (i === strRegexp.length) return `"${str}"`;
return str ? typeHandler.string(str.replace(strRegexp[i][0], strRegexp[i][1]), ++i) : typeHandler.string(str, strRegexp.length);
},
[complexType.itemRecord]: (record) => {
return record.join();
}
}
const processGenerator = (gen, records, stack = null) => {
const {value, done} = gen.next();
if (done) {
return typeRouter(records, stack);
} else {
const target = value.value;
const currentStack = {gen, records, key: value.key, previous: stack};
return typeRouter(target, currentStack);
}
}
const typeRouter = (v, stack) => {
const getType = (v, checkToJSON = false) => {
const t = typeof v
if (t === 'object') {
switch (true) {
case !v:
return 'null';
case v instanceof ResultRecords:
return complexType.itemRecord;
case checkToJSON && typeof v.toJSON === 'function':
return complexType.toJson;
case Array.isArray(v):
return complexType.array;
default:
return complexType.object;
}
} else {
return t;
}
}
let value = v;
let t = getType(value, true);
if (t === complexType.toJson) {
value = value.toJSON();
t = getType(value);
}
if ([complexType.array, complexType.object].includes(t)) {
const gen = complexHandlers[t].createGen(value);
const records = complexHandlers[t].createRecords();
return processGenerator(gen, records, stack);
}
const str = (typeHandler[t] || typeHandler.default)(value);
if (stack) {
const {gen, records, key, previous} = stack;
records.push(str, key);
return processGenerator(gen, records, previous);
} else {
return str
}
}
const stringify = (v) => {
return typeRouter(v);
}
return {stringify};
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment