diff --git a/src/index.ts b/src/index.ts index 788b774..75e6c24 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,7 +4,7 @@ import { Glosser } from './morphology/gloss'; import yargs from 'yargs'; import { pngGlossSentence } from './modes/png-gloss'; import { Tree } from './tree'; -import { recover } from './core/recover'; +import { recover } from './syntax/recover'; import { trimTree } from './tree/trim'; import { drawTreeToCanvas } from './tree/draw'; import { parse } from './modes/parse'; diff --git a/src/modes/boxes.ts b/src/modes/boxes.ts index 5b62d2d..8fa4282 100644 --- a/src/modes/boxes.ts +++ b/src/modes/boxes.ts @@ -1,6 +1,6 @@ import { inTone } from '../morphology/tokenize'; import { Tree, assertBranch, skipFree, treeText } from '../tree'; -import { Tone } from '../core/types'; +import { Tone } from '../morphology/tone'; import { Impossible, Ungrammatical, Unimplemented } from '../core/error'; export interface PostField { diff --git a/src/morphology/dictionary.ts b/src/morphology/dictionary.ts index a616ed2..bfdacdc 100644 --- a/src/morphology/dictionary.ts +++ b/src/morphology/dictionary.ts @@ -1,5 +1,5 @@ import { inTone } from './tokenize'; -import { Tone } from '../core/types'; +import { Tone } from './tone'; export const verbTypes = [ 'name quote', diff --git a/src/morphology/gloss.ts b/src/morphology/gloss.ts index 9da5516..0c02b6a 100644 --- a/src/morphology/gloss.ts +++ b/src/morphology/gloss.ts @@ -1,6 +1,6 @@ import { Entry, dictionary } from './dictionary'; import { bare, clean, splitPrefixes, tone } from './tokenize'; -import { Tone } from '../core/types'; +import { Tone } from './tone'; import toaduaGlossesJson from '../../data/toadua/toadua.json'; interface Gloss { diff --git a/src/morphology/tokenize.test.ts b/src/morphology/tokenize.test.ts index 7bb30d3..f3142d4 100644 --- a/src/morphology/tokenize.test.ts +++ b/src/morphology/tokenize.test.ts @@ -9,7 +9,7 @@ import { splitPrefixes, ToaqTokenizer, } from './tokenize'; -import { Tone } from '../core/types'; +import { Tone } from './tone'; test('it cleans up Toaq words', () => { expect(clean('gi')).toEqual('gı'); diff --git a/src/morphology/tokenize.ts b/src/morphology/tokenize.ts index f062f7f..d04cfc8 100644 --- a/src/morphology/tokenize.ts +++ b/src/morphology/tokenize.ts @@ -1,6 +1,6 @@ import { dictionary, underscoredWordTypes } from './dictionary'; import { Impossible, Ungrammatical } from '../core/error'; -import { Tone } from '../core/types'; +import { Tone } from './tone'; // Vyái → ꝡáı export function clean(word: string): string { diff --git a/src/core/types.ts b/src/morphology/tone.ts similarity index 100% rename from src/core/types.ts rename to src/morphology/tone.ts diff --git a/src/semantics/denote.test.ts b/src/semantics/denote.test.ts index 0039584..6ffe5c4 100644 --- a/src/semantics/denote.test.ts +++ b/src/semantics/denote.test.ts @@ -1,6 +1,6 @@ import { test, expect } from 'vitest'; import { parse } from '../modes/parse'; -import { recover } from '../core/recover'; +import { recover } from '../syntax/recover'; import { denote } from './denote'; import { Expr } from './model'; import { toPlainText } from './render'; diff --git a/src/semantics/denote.ts b/src/semantics/denote.ts index e1f8947..81abe48 100644 --- a/src/semantics/denote.ts +++ b/src/semantics/denote.ts @@ -15,7 +15,7 @@ import { Word, effectiveLabel, } from '../tree'; -import { Tone } from '../core/types'; +import { Tone } from '../morphology/tone'; import { compose } from './compose'; import { adjuncts, diff --git a/src/core/recover.ts b/src/syntax/recover.ts similarity index 90% rename from src/core/recover.ts rename to src/syntax/recover.ts index 81acd3f..be1b472 100644 --- a/src/core/recover.ts +++ b/src/syntax/recover.ts @@ -8,10 +8,10 @@ import { assertLeaf, effectiveLabel, } from '../tree'; -import { Impossible } from './error'; -import { reverse } from './misc'; +import { Impossible } from '../core/error'; +import { reverse } from '../core/misc'; import { inTone } from '../morphology/tokenize'; -import { Tone } from './types'; +import { Tone } from '../morphology/tone'; interface Quantification { type: 'quantification'; @@ -166,20 +166,27 @@ class Scope { } } +/** + * Recurses down a parsed syntax tree to recover the deep structure. + */ class Recoverer { private nextBinding = 0; private nextCoindex = 0; constructor() {} - private newBinding(): number { - return this.nextBinding++; - } - private newCoindex(): string { return String.fromCodePoint('𝑖'.codePointAt(0)! + this.nextCoindex++); } + private newScope(): Scope { + return new Scope(() => this.nextBinding++); + } + + private fixSerial(serial: Tree, terms: Tree[]): Tree { + return fixSerial(serial, terms, () => this.newCoindex()); + } + recover(tree: Tree, scope: Scope | undefined): StrictTree { if ('children' in tree) { if (tree.label === '*𝘷P') { @@ -190,9 +197,7 @@ class Recoverer { } if (!('children' in serial)) throw new Impossible('strange *Serial'); - const vP = fixSerial(serial, tree.children.slice(1), () => - this.newCoindex(), - ); + const vP = this.fixSerial(serial, tree.children.slice(1)); return this.recover(vP, scope); } else { throw new Impossible('unexpected non-binary tree: ' + tree.label); @@ -200,9 +205,7 @@ class Recoverer { } 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(), - ); + const vP = this.fixSerial(tree.left, [pro(), tree.right]); assertBranch(vP); assertBranch(vP.right); return this.recover(vP.right.right, undefined); @@ -210,7 +213,7 @@ class Recoverer { // Subclauses open a new scope if (tree.label === 'CP' || tree.label === 'CPrel') { - const newScope = new Scope(() => this.newBinding()); + const newScope = this.newScope(); const right = this.recover(tree.right, newScope); return { label: tree.label, @@ -221,9 +224,9 @@ class Recoverer { // Conjoined clauses each get a new scope of their own if (tree.label === '&P' && effectiveLabel(tree) !== 'DP') { - const leftScope = new Scope(() => this.newBinding()); + const leftScope = this.newScope(); const left = this.recover(tree.left, leftScope); - const rightScope = new Scope(() => this.newBinding()); + const rightScope = this.newScope(); assertBranch(tree.right); const conjunction = this.recover(tree.right.left, scope); const right = this.recover(tree.right.right, rightScope); @@ -260,7 +263,8 @@ class Recoverer { } /** - * Recover a deep-structure Toaq syntax tree by undoing movement. + * Recover a deep-structure Toaq syntax tree by undoing movement and creating + * QP/FocAdvP around scope boundaries. * * @param tree A surface-structure tree parsed by the Nearley grammar. * @returns A strictly binary deep-structure syntax tree. diff --git a/src/core/serial.ts b/src/syntax/serial.ts similarity index 98% rename from src/core/serial.ts rename to src/syntax/serial.ts index 53fee75..ae40b8d 100644 --- a/src/core/serial.ts +++ b/src/syntax/serial.ts @@ -1,5 +1,5 @@ -import { Impossible, Ungrammatical, Unimplemented } from './error'; -import { splitNonEmpty } from './misc'; +import { Impossible, Ungrammatical, Unimplemented } from '../core/error'; +import { splitNonEmpty } from '../core/misc'; import { Branch, Label, Leaf, Tree, effectiveLabel, makeNull } from '../tree'; /** diff --git a/src/tree/productions.ts b/src/tree/productions.ts index 2de545e..b138f38 100644 --- a/src/tree/productions.ts +++ b/src/tree/productions.ts @@ -1,5 +1,5 @@ import { dictionary } from '../morphology/dictionary'; -import { getFrame } from '../core/serial'; +import { getFrame } from '../syntax/serial'; import { toadua } from '../morphology/toadua'; import { bare, ToaqToken, tone } from '../morphology/tokenize'; import { diff --git a/src/tree/types.ts b/src/tree/types.ts index e7b7e7d..b9fc2dd 100644 --- a/src/tree/types.ts +++ b/src/tree/types.ts @@ -1,6 +1,6 @@ import { Entry } from '../morphology/dictionary'; import { Impossible } from '../core/error'; -import { Tone } from '../core/types'; +import { Tone } from '../morphology/tone'; export interface Word { covert: false; diff --git a/src/web/Main.tsx b/src/web/Main.tsx index 9e578d5..55da7f2 100644 --- a/src/web/Main.tsx +++ b/src/web/Main.tsx @@ -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 { recover } from '../core/recover'; +import { recover } from '../syntax/recover'; import { Glosser } from '../morphology/gloss'; import { parse } from '../modes/parse'; import { denote } from '../semantics/denote'; diff --git a/src/web/Sentences.tsx b/src/web/Sentences.tsx index d8ae060..4a617a9 100644 --- a/src/web/Sentences.tsx +++ b/src/web/Sentences.tsx @@ -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 { recover } from '../core/recover'; +import { recover } from '../syntax/recover'; import { denote } from '../semantics/denote'; const rSentences: string[] = refgramSentencesTxt.split('\n');