117 lines
3 KiB
JavaScript
117 lines
3 KiB
JavaScript
|
import { printTree } from "./utils.mjs"
|
||
|
|
||
|
/**
|
||
|
* Child {
|
||
|
* char: 'a',
|
||
|
* children: [Child, Child],
|
||
|
* path: null / 'full/path',
|
||
|
* count: 0
|
||
|
* }
|
||
|
*/
|
||
|
function Child(char) {
|
||
|
this.char = char
|
||
|
this.children = []
|
||
|
this.path = null
|
||
|
this.count = 0
|
||
|
}
|
||
|
|
||
|
function buildChild(i, arr) {
|
||
|
let letter = new Child(arr[0][i])
|
||
|
let consume = []
|
||
|
if (arr[0].length === i + 1) {
|
||
|
letter.path = arr[0]
|
||
|
letter.count += 1
|
||
|
} else {
|
||
|
consume = [arr[0]]
|
||
|
}
|
||
|
|
||
|
for (let y = 1; y < arr.length; y++) {
|
||
|
if (arr[y][i] !== letter.char) break
|
||
|
consume.push(arr[y])
|
||
|
}
|
||
|
|
||
|
letter.count += consume.length
|
||
|
while (consume.length) {
|
||
|
letter.children.push(buildChild(i + 1, consume))
|
||
|
consume.splice(0, letter.children[letter.children.length - 1].count)
|
||
|
}
|
||
|
return letter
|
||
|
}
|
||
|
|
||
|
export function buildTree(all) {
|
||
|
let paths = Array.from(new Set(all)).sort()
|
||
|
let builder = []
|
||
|
while (paths.length) {
|
||
|
builder.push(buildChild(0, paths))
|
||
|
paths.splice(0, builder[builder.length - 1].count)
|
||
|
}
|
||
|
printTree(builder)
|
||
|
return builder
|
||
|
}
|
||
|
|
||
|
function IfTreeBranch(branches, indent = 0) {
|
||
|
let output = ''
|
||
|
let indentation = ''.padStart(indent * 2)
|
||
|
|
||
|
for (let i = 0; i < branches.length; i++) {
|
||
|
let branch = branches[i]
|
||
|
output += `${i > 0 ? 'else ': ''}if (str.charCodeAt(${indent}) === ${branch.char.charCodeAt(0)}) { // ${branch.char}`
|
||
|
|
||
|
if (branch.path) {
|
||
|
output += '\n' + indentation + ` if (str.length === ${branch.path.length}) {`
|
||
|
output += '\n' + indentation + ` return "${branch.path}"`
|
||
|
output += '\n' + indentation + ` }`
|
||
|
}
|
||
|
if (branch.children.length) {
|
||
|
if (branch.path) {
|
||
|
output += ' else '
|
||
|
} else {
|
||
|
output += '\n' + indentation + ' '
|
||
|
}
|
||
|
output += IfTreeBranch(branch.children, indent + 1)
|
||
|
}
|
||
|
output += '\n' + indentation + '} '
|
||
|
}
|
||
|
return output
|
||
|
}
|
||
|
|
||
|
export function compileTreeIntoIfs(tree) {
|
||
|
let output = IfTreeBranch(tree)
|
||
|
output += '\nreturn null'
|
||
|
return new Function('str', output)
|
||
|
}
|
||
|
|
||
|
|
||
|
function IfTreeBranchBuffer(branches, indent = 0) {
|
||
|
let output = ''
|
||
|
let indentation = ''.padStart(indent * 2)
|
||
|
|
||
|
for (let i = 0; i < branches.length; i++) {
|
||
|
let branch = branches[i]
|
||
|
output += `${i > 0 ? 'else ': ''}if (uint[${indent}] === ${branch.char.charCodeAt(0)}) { // ${branch.char}`
|
||
|
|
||
|
if (branch.path) {
|
||
|
output += '\n' + indentation + ` if (uint.length === ${branch.path.length}) {`
|
||
|
output += '\n' + indentation + ` return "${branch.path}"`
|
||
|
output += '\n' + indentation + ` }`
|
||
|
}
|
||
|
if (branch.children.length) {
|
||
|
if (branch.path) {
|
||
|
output += ' else '
|
||
|
} else {
|
||
|
output += '\n' + indentation + ' '
|
||
|
}
|
||
|
output += IfTreeBranchBuffer(branch.children, indent + 1)
|
||
|
}
|
||
|
output += '\n' + indentation + '} '
|
||
|
}
|
||
|
return output
|
||
|
}
|
||
|
|
||
|
export function compileTreeIntoIfsWithBuffer(tree) {
|
||
|
let output = `var uint = Buffer.from(str)\n`
|
||
|
output += IfTreeBranchBuffer(tree)
|
||
|
output += '\nreturn null'
|
||
|
return new Function('str', output)
|
||
|
}
|