Last active
May 4, 2021 14:27
-
-
Save kellywoo/9bd664eb38c174e058368203681efea0 to your computer and use it in GitHub Desktop.
6th homework
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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}; | |
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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'; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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