Skip to content

Commit

Permalink
Rename fix() to recover(), refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
lynn committed May 10, 2024
1 parent f65f045 commit 2b05c0c
Show file tree
Hide file tree
Showing 8 changed files with 101 additions and 95 deletions.
166 changes: 86 additions & 80 deletions src/core/fix.ts → src/core/recover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ class Scope {
}

/**
* Wrap the given CompCP (probably TP) in the binding sites for this scope.
* Wrap the given CompCP (probably ΣP) in the binding sites for this scope.
*/
wrap(tree: StrictTree): StrictTree {
for (const [b, index] of reverse(this.bindings)) {
Expand Down Expand Up @@ -166,82 +166,96 @@ class Scope {
}
}

function fix_(
tree: Tree,
newBinding: () => number,
scope: Scope | undefined,
newCoindex: () => string,
): StrictTree {
if ('children' in tree) {
if (tree.label === '*𝘷P') {
const serial = tree.children[0];
if (!serial) throw new Impossible('*𝘷P without children');
if (serial.label !== '*Serial') {
throw new Impossible('*𝘷P without *Serial, instead: ' + serial.label);
}
if (!('children' in serial)) throw new Impossible('strange *Serial');
class Recoverer {
private nextBinding = 0;
private nextCoindex = 0;

const vP = fixSerial(serial, tree.children.slice(1), newCoindex);
return fix_(vP, newBinding, scope, newCoindex);
} else {
throw new Impossible('unexpected non-binary tree: ' + tree.label);
}
} else if ('left' in tree) {
if (tree.label === 'VP' && tree.left.label === '*Serial') {
// Tiny hack to extract a VP from fixSerial:
const vP = fixSerial(tree.left, [pro(), tree.right], newCoindex);
assertBranch(vP);
assertBranch(vP.right);
return fix_(vP.right.right, newBinding, undefined, newCoindex);
}
constructor() {}

// Subclauses open a new scope
if (tree.label === 'CP' || tree.label === 'CPrel') {
const newScope = new Scope(newBinding);
const right = fix_(tree.right, newBinding, newScope, newCoindex);
return {
label: tree.label,
left: fix_(tree.left, newBinding, scope, newCoindex),
right: newScope.wrap(right),
};
}
private newBinding(): number {
return this.nextBinding++;
}

// Conjoined clauses each get a new scope of their own
if (tree.label === '&P' && effectiveLabel(tree) !== 'DP') {
const leftScope = new Scope(newBinding);
const left = fix_(tree.left, newBinding, leftScope, newCoindex);
const rightScope = new Scope(newBinding);
assertBranch(tree.right);
const conjunction = fix_(tree.right.left, newBinding, scope, newCoindex);
const right = fix_(tree.right.right, newBinding, rightScope, newCoindex);
return {
label: tree.label,
left: leftScope.wrap(left),
right: {
label: tree.right.label,
left: conjunction,
right: rightScope.wrap(right),
},
};
}
private newCoindex(): string {
return String.fromCodePoint('𝑖'.codePointAt(0)! + this.nextCoindex++);
}

const left = fix_(tree.left, newBinding, scope, newCoindex);
const right = fix_(tree.right, newBinding, scope, newCoindex);
const fixed = { label: tree.label, left, right };
recover(tree: Tree, scope: Scope | undefined): StrictTree {
if ('children' in tree) {
if (tree.label === '*𝘷P') {
const serial = tree.children[0];
if (!serial) throw new Impossible('*𝘷P without children');
if (serial.label !== '*Serial') {
throw new Impossible('*𝘷P without *Serial, instead: ' + serial.label);
}
if (!('children' in serial)) throw new Impossible('strange *Serial');

if (scope !== undefined && effectiveLabel(tree) === 'DP') {
if (tree.label === 'DP') {
scope.quantify(fixed);
} else if (tree.label === 'FocusP') {
scope.focus(fixed);
} else if (tree.label === '&P') {
scope.conjoin(fixed);
const vP = fixSerial(serial, tree.children.slice(1), () =>
this.newCoindex(),
);
return this.recover(vP, scope);
} else {
throw new Impossible('unexpected non-binary tree: ' + tree.label);
}
} else if ('left' in tree) {
if (tree.label === 'VP' && tree.left.label === '*Serial') {
// Tiny hack to extract a VP from fixSerial:
const vP = fixSerial(tree.left, [pro(), tree.right], () =>
this.newCoindex(),
);
assertBranch(vP);
assertBranch(vP.right);
return this.recover(vP.right.right, undefined);
}
}

return fixed;
} else {
return tree;
// Subclauses open a new scope
if (tree.label === 'CP' || tree.label === 'CPrel') {
const newScope = new Scope(() => this.newBinding());
const right = this.recover(tree.right, newScope);
return {
label: tree.label,
left: this.recover(tree.left, scope),
right: newScope.wrap(right),
};
}

// Conjoined clauses each get a new scope of their own
if (tree.label === '&P' && effectiveLabel(tree) !== 'DP') {
const leftScope = new Scope(() => this.newBinding());
const left = this.recover(tree.left, leftScope);
const rightScope = new Scope(() => this.newBinding());
assertBranch(tree.right);
const conjunction = this.recover(tree.right.left, scope);
const right = this.recover(tree.right.right, rightScope);
return {
label: tree.label,
left: leftScope.wrap(left),
right: {
label: tree.right.label,
left: conjunction,
right: rightScope.wrap(right),
},
};
}

const left = this.recover(tree.left, scope);
const right = this.recover(tree.right, scope);
const fixed = { label: tree.label, left, right };

if (scope !== undefined && effectiveLabel(tree) === 'DP') {
if (tree.label === 'DP') {
scope.quantify(fixed);
} else if (tree.label === 'FocusP') {
scope.focus(fixed);
} else if (tree.label === '&P') {
scope.conjoin(fixed);
}
}

return fixed;
} else {
return tree;
}
}
}

Expand All @@ -251,14 +265,6 @@ function fix_(
* @param tree A surface-structure tree parsed by the Nearley grammar.
* @returns A strictly binary deep-structure syntax tree.
*/
export function fix(tree: Tree): StrictTree {
let nextBinding = 0;
let coindexCount = 0;

return fix_(
tree,
() => nextBinding++,
undefined,
() => String.fromCodePoint('𝑖'.codePointAt(0)! + coindexCount++),
);
export function recover(tree: Tree): StrictTree {
return new Recoverer().recover(tree, undefined);
}
6 changes: 3 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Glosser } from './morphology/gloss';
import yargs from 'yargs';
import { pngGlossSentence } from './modes/png-gloss';
import { Tree } from './tree';
import { fix } from './core/fix';
import { recover } from './core/recover';
import { trimTree } from './tree/trim';
import { drawTreeToCanvas } from './tree/draw';
import { parse } from './modes/parse';
Expand All @@ -23,9 +23,9 @@ function getTrees(argv: {
}): Tree[] {
let trees = parse(argv.sentence!);
if (argv.semantics) {
trees = trees.map(t => fix(t)).map(denote);
trees = trees.map(t => recover(t)).map(denote);
} else if (!argv.surface) {
trees = trees.map(t => fix(t));
trees = trees.map(t => recover(t));
}
if (argv.compact) {
trees = trees.map(trimTree);
Expand Down
4 changes: 2 additions & 2 deletions src/morphology/dictionary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,8 @@ export class Dictionary {

private initialize() {
const entries: Entry[] = [
...require('../dictionary/dictionary.json'),
...require('../data/unofficial.json'),
...require('../../dictionary/dictionary.json'),
...require('../../data/unofficial.json'),
] as Entry[];

for (const e of entries) {
Expand Down
2 changes: 1 addition & 1 deletion src/morphology/gloss.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { test, expect } from 'vitest';
import { Glosser } from './morphology/gloss';
import { Glosser } from './gloss';

test('it glosses Toaq words', () => {
const glosser = new Glosser(false);
Expand Down
2 changes: 1 addition & 1 deletion src/morphology/toadua.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ export interface ToaduaEntry {
let _toadua: Record<string, ToaduaEntry>;

export function toadua(): Record<string, ToaduaEntry> {
return (_toadua ??= require('../data/toadua/toadua.json'));
return (_toadua ??= require('../../data/toadua/toadua.json'));
}
4 changes: 2 additions & 2 deletions src/semantics/denote.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { test, expect } from 'vitest';
import { parse } from '../modes/parse';
import { fix } from '../core/fix';
import { recover } from '../core/recover';
import { denote } from './denote';
import { Expr } from './model';
import { toPlainText } from './render';
Expand All @@ -13,7 +13,7 @@ function d(sentence: string): string {
expect(trees.length).toBe(1);
const [tree] = trees;

const { denotation } = denote(fix(tree));
const { denotation } = denote(recover(tree));
if (denotation === null) throw new Impossible('Null denotation');
const denotationText = toPlainText(denotation);

Expand Down
6 changes: 3 additions & 3 deletions src/web/Main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useDarkMode, useLocalStorage } from 'usehooks-ts';
import { boxify } from '../modes/boxes';
import { trimTree } from '../tree/trim';
import { treeToEnglish } from '../english/tree';
import { fix } from '../core/fix';
import { recover } from '../core/recover';
import { Glosser } from '../morphology/gloss';
import { parse } from '../modes/parse';
import { denote } from '../semantics/denote';
Expand Down Expand Up @@ -124,7 +124,7 @@ export function Main(props: MainProps) {

function getTree(mode: TreeMode): ReactElement {
let tree = parseInput();
if (mode !== 'raw-tree') tree = fix(tree);
if (mode !== 'raw-tree') tree = recover(tree);
if (mode.includes('semantics')) tree = denote(tree as any);
if (trimmed) tree = trimTree(tree);
switch (treeFormat) {
Expand Down Expand Up @@ -197,7 +197,7 @@ export function Main(props: MainProps) {
renderer: (e: CompactExpr) => string,
compact: boolean,
): ReactElement {
let expr: any = denote(fix(parseInput())).denotation;
let expr: any = denote(recover(parseInput())).denotation;
if (!expr) return <>No denotation</>;
if (compact) expr = compactDenotation(expr);
return <>{renderer(expr)}</>;
Expand Down
6 changes: 3 additions & 3 deletions src/web/Sentences.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { useInView } from 'react-intersection-observer';
import refgramSentencesTxt from '../../sentences/refgram.txt?raw';
// @ts-ignore
import aSentencesTxt from '../../sentences/a.txt?raw';
import { fix } from '../core/fix';
import { recover } from '../core/recover';
import { denote } from '../semantics/denote';

const rSentences: string[] = refgramSentencesTxt.split('\n');
Expand Down Expand Up @@ -43,9 +43,9 @@ function checkParse(sentence: string): ParseStatus {
if (n > 1) return { status: 'ambiguous', count: n };
if (n === 0) return { status: 'no parse' };
try {
const fixed = fix(trees[0]);
const deepStructure = recover(trees[0]);
try {
denote(fixed);
denote(deepStructure);
return { status: 'ok' };
} catch {
return { status: 'denote failed' };
Expand Down

0 comments on commit 2b05c0c

Please sign in to comment.