Skip to content
Snippets Groups Projects
Commit c77116ba authored by Millicent Billette's avatar Millicent Billette
Browse files

WiP: dictionary-tree.getAlternative nearly work !

parent 5a3e371d
No related branches found
No related tags found
No related merge requests found
......@@ -5,12 +5,13 @@ export function buildTreeStruct(monoLineString) {
const stringAsArray = monoLineString.split('');
const rawTree = leftParser(stringAsArray);
const outOfScope = stringAsArray.length;
if (outOfScope) throw `fail to build tree from : "${monoLineString}" parsed: ${JSON.stringify(rawTree)} unparsed/failed: ${stringAsArray.join('')}`;
if (outOfScope) throw new Error(`fail to build tree from : "${monoLineString}" parsed: ${JSON.stringify(rawTree)} unparsed/failed: ${stringAsArray.join('')}`);
let lastTree, tree = rawTree;
do {
lastTree = JSON.stringify(tree);
tree = flattenTree(tree);
} while (JSON.stringify(tree) !== lastTree)
preRouteAlt(tree);
return tree;
}
......@@ -18,7 +19,7 @@ export function buildTreeStruct(monoLineString) {
* leftParser stuff
*/
function flushNoEmptyString(data) {
if (data.str.length) data.tree.alt[data.tree.alt.length - 1].step.push(data.str);
if (data.str.length) data.tree.alt[data.tree.alt.length - 1].step.push({str:data.str});
data.str = '';
}
......@@ -73,7 +74,7 @@ function concatStrings(array) {
tree: {alt: [{step: []}]}, // Output array
};
array.forEach(e => {
if (isString(e)) appendToString(e, data);
if (isString(e)) appendToString(e.str, data);
else {
flushNoEmptyString(data)
data.tree.alt[data.tree.alt.length - 1].step.push(e);
......@@ -87,7 +88,7 @@ function flattenTree(tree) {
if (isString(tree)) return tree;
const objType = isAlt(tree)?'alt':'step';
tree[objType] = tree[objType].map(flattenTree);
if (tree[objType].length === 0) return '';
if (tree[objType].length === 0) return {str:''};
if (tree[objType].length === 1) return tree[objType][0];
if (isAlt(tree)) {
......@@ -102,7 +103,7 @@ function flattenTree(tree) {
}
function isString(element) {
return typeof element === 'string';
return typeof element === 'object' && typeof element.str === 'string';
}
function isStep(element) {
......@@ -121,18 +122,63 @@ function trivialDedup(tree) {
}
export function serialize(treeStruct) {
if (isString(treeStruct)) return treeStruct;
if (isString(treeStruct)) return treeStruct.str;
if (isStep(treeStruct)) return treeStruct.step.map(serialize).join('');
if (isAlt(treeStruct)) return `(${treeStruct.alt.map(serialize).join('|')})`;
throw new Error(`Error: how to serialize ${JSON.stringify(treeStruct)} RAW: ${treeStruct}`);
}
function preRouteAlt(treeStruct){
if (isString(treeStruct)) {
treeStruct.altCount =1;
treeStruct.indexCost=1;
return 1;
}
if (isAlt(treeStruct)) {
treeStruct.altCount = treeStruct.alt.reduce((acc, cur) => acc + preRouteAlt(cur), 0);
treeStruct.indexCost = treeStruct.altCount-1;
return treeStruct.altCount;
}
if (isStep(treeStruct)) {
treeStruct.altCount = treeStruct.step.reduce((acc, cur) => acc * preRouteAlt(cur), 1);
// last alt indexCost*1, previous alt group indexCost * last alt altCount, firstAltGroup * nextAltGroup * nextAltGroup... * lastAltGroup
let weigth = 1;
for(let i = treeStruct.step.length-1;i>=0;i--){
const step = treeStruct.step[i];
if (isAlt(step)){
step.alt.forEach(alt=>applyCostWeigth(alt,weigth));
weigth*=step.altCount;
}
}
treeStruct.indexCost = treeStruct.altCount;
return treeStruct.altCount;
}
}
function applyCostWeigth(tree,weigth){
tree.indexCost*=weigth;
if (isStep(tree)) tree.step.forEach(subTree=>applyCostWeigth(subTree,weigth));
if (isAlt(tree)) tree.alt.forEach(subTree=>applyCostWeigth(subTree,weigth));
}
export function altCount(treeStruct) {
if (isString(treeStruct)) return 1;
if (isStep(treeStruct)) return treeStruct.step.reduce((acc, cur) => acc * altCount(cur), 1);
if (isAlt(treeStruct)) return treeStruct.reduce((acc, cur) => acc + altCount(cur), 0);
return treeStruct.altCount;
}
export function getAlternative(altNumber, tree) {
return 'abc';
export function getAlternative(altIndex, tree) {
const refAltIndex = {index:altIndex};
return _getAlternative(refAltIndex, tree);
}
export function _getAlternative(refAltIndex, tree) {
if (isString(tree)) return tree.str;
if (isStep(tree)) {
return tree.step.map(subTree =>_getAlternative(refAltIndex, subTree) ).join('');
}
if (isAlt(tree)){
for (const altTree of tree.alt){
// Keep me for debug case
// Keep console.debug(`In ${serialize(tree)} ${refAltIndex.index} < ${altTree.indexCost} ${refAltIndex.index < altTree.indexCost?'choose':'avoid'} ${serialize(altTree)}`);
if(refAltIndex.index < altTree.indexCost) return _getAlternative(refAltIndex, altTree);
else refAltIndex.index -= altTree.indexCost;
}
}
throw new Error(`index out of bound : ${refAltIndex.index+altCount(tree)}/${altCount(tree)} in ${serialize(tree)}`);
}
......@@ -5,7 +5,7 @@ const buildTreeThenSerialize = str => app.serialize(app.buildTreeStruct(str));
test('simple string still simple string', t => t.is(buildTreeThenSerialize('abc'), 'abc'));
test('(a|b) alt still (a|b)', t => t.is(buildTreeThenSerialize('(a|b)'), '(a|b)'));
test('a)b throw', t => t.throws(() => buildTreeStruct('a)b')));
test('a)b throw', t => t.throws(()=>app.buildTreeStruct('a)b')));
// Ok to be permissive test('(a throw',t=>t.throws(()=>buildTreeStruct('(a')));
// Ok to be permissive test('a|b throw',t=>t.throws(()=>buildTreeStruct('a|b')));
test('(|b) keep empty choice', t => t.is(buildTreeThenSerialize('(|b)'), '(|b)'));
......@@ -17,9 +17,25 @@ test('build complexe tree with (|) pattern', t => t.is(buildTreeThenSerialize('(
test('serialize incorrect tree throw', t => t.throws(() => app.serialize({plop: ['a']})));
const exampleTree = () => app.buildTreeStruct('a(b(c|d)|e(f|g|h)ij(k|l)|@@@@m)')
test.skip('mono altCount', t => t.is(app.altCount(app.buildTreeStruct('ipsum')), 1));
test.skip('simple altCount', t => t.is(app.altCount(app.buildTreeStruct('(lore|ipsu)m')), 2));
test.skip('multi altCount', t => t.is(app.altCount(app.buildTreeStruct('(a|b|c)(d|e|f)g(h|i|j|k)')), 36));
test.skip('multi level tree altCount', t => t.is(app.altCount(app.buildTreeStruct('a(b(c|d)|e(f|g|h)ij(k|l)|@@@@m)')), 9));
test.skip('getAlternative 0', t => t.is(app.getAlternative(0, exampleTree()), 'abc'));
test('mono altCount', t => t.is(app.altCount(app.buildTreeStruct('ipsum')), 1));
test('simple altCount', t => t.is(app.altCount(app.buildTreeStruct('(lore|ipsu)m')), 2));
test('multi altCount', t => t.is(app.altCount(app.buildTreeStruct('(a|b|c)(d|e|f)g(h|i|j|k)')), 36));
test('multi level tree altCount', t => t.is(app.altCount(app.buildTreeStruct('a(b(c|d)|e(f|g|h)ij(k|l)|@@@@m)')), 9));
const exampleTree = () => app.buildTreeStruct('a(b(c|d)|e(f|g(h|i)|j)kl(m|n(o|p)|q(r|s)|t)|(u|v)w)');
console.log(JSON.stringify(exampleTree()));
console.log(app.serialize(exampleTree()));
test('getAlternative 0', t => t.is(app.getAlternative(0, exampleTree()), 'abc'));
test('getAlternative 1', t => t.is(app.getAlternative(1, exampleTree()), 'abd'));
test('getAlternative 2', t => t.is(app.getAlternative(2, exampleTree()), 'aefklm'));
test('getAlternative 3', t => t.is(app.getAlternative(3, exampleTree()), 'aefklno'));
test('getAlternative 4', t => t.is(app.getAlternative(4, exampleTree()), 'aefklnp'));
test('getAlternative 5', t => t.is(app.getAlternative(5, exampleTree()), 'aefklqr'));
test('getAlternative 6', t => t.is(app.getAlternative(6, exampleTree()), 'aefklqs'));
test('getAlternative 7', t => t.is(app.getAlternative(7, exampleTree()), 'aefklt'));
test('getAlternative 8', t => t.is(app.getAlternative(8, exampleTree()), 'aeghklm'));
test('getAlternative 9', t => t.is(app.getAlternative(9, exampleTree()), 'aeghklno'));
test('getAlternative 14', t => t.is(app.getAlternative(14, exampleTree()), 'aegiklm'));
test('getAlternative 20', t => t.is(app.getAlternative(20, exampleTree()), 'aejklm'));
test.skip('getAlternative 26', t => t.is(app.getAlternative(26, exampleTree()), 'aqr'));
test('getAlternative 999 throw', t => t.throws(()=>app.getAlternative(999, exampleTree())));
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment