From d4d1b3ba9305a70b9b1837bc61eed4618585a582 Mon Sep 17 00:00:00 2001 From: Lynn Date: Tue, 5 Sep 2023 21:36:17 +0200 Subject: [PATCH 1/6] Handle covert leaves differently, add "PRO", remove "v0" --- src/boxes.ts | 6 +++--- src/draw-tree.ts | 7 +------ src/english.ts | 3 +-- src/grammar.ts | 3 +-- src/latex.ts | 3 --- src/semantics/denote.ts | 30 ++++++++++-------------------- src/serial.ts | 22 +++++++++++----------- src/textual-tree.ts | 6 +----- src/toaq.ne | 3 +-- src/tree.ts | 35 ++++++++++++++++------------------- 10 files changed, 45 insertions(+), 73 deletions(-) diff --git a/src/boxes.ts b/src/boxes.ts index 182f380..a13ac22 100644 --- a/src/boxes.ts +++ b/src/boxes.ts @@ -46,7 +46,7 @@ function skipFree(tree: Tree): Tree { function words(tree: Tree): string { if ('word' in tree) { - if (tree.word === 'covert' || tree.word === 'functional') { + if (tree.word === 'covert') { return ''; } else { return tree.word.text; @@ -91,7 +91,7 @@ function boxifyClause(tree: Tree): BoxClause { if (!('left' in cp)) throw new Error('bad CP?'); const c = cp.left; if (!('word' in c)) throw new Error('C without word?'); - if (c.word !== 'covert' && c.word !== 'functional') { + if (c.word !== 'covert') { complementizer = c.word.text; } for (let node = cp.right; ; ) { @@ -149,7 +149,7 @@ export function boxify(tree: Tree): BoxSentence { const sa = tree.right; if (sa.label !== 'SA') throw new Error('SAP without SA?'); if (!('word' in sa)) throw new Error('SA without word?'); - if (sa.word !== 'covert' && sa.word !== 'functional') { + if (sa.word !== 'covert') { speechAct = sa.word.text; } const cp = tree.left; diff --git a/src/draw-tree.ts b/src/draw-tree.ts index b5b490a..2775587 100644 --- a/src/draw-tree.ts +++ b/src/draw-tree.ts @@ -53,12 +53,7 @@ export function placeLeaf( const gloss = typeof leaf.word === 'string' ? undefined : leaf.word.entry?.gloss; const label = getLabel(leaf); - const word = - leaf.word === 'functional' - ? undefined - : leaf.word === 'covert' - ? 'โˆ…' - : leaf.word.text; + const word = leaf.word === 'covert' ? leaf.value : leaf.word.text; const denotation = 'denotation' in leaf && leaf.denotation !== null ? toPlainText(leaf.denotation) diff --git a/src/english.ts b/src/english.ts index c4dc22b..4371ffe 100644 --- a/src/english.ts +++ b/src/english.ts @@ -14,7 +14,6 @@ function leafText(tree: Tree): string { throw new Error('Unexpected non-leaf ' + tree.label); } if (tree.word === 'covert') return ''; - if (tree.word === 'functional') return ''; return tree.word.text; } @@ -364,7 +363,7 @@ function branchToEnglish(tree: Branch): Constituent { { she: 'necessarily', ao: 'would', daฤฑ: 'possibly', ea: 'could' }[ bare(leafText(modal)) ] ?? '?'; - if (c.word === 'covert' || c.word === 'functional') { + if (c.word === 'covert') { return { text: eng }; } else { return { diff --git a/src/grammar.ts b/src/grammar.ts index b001e24..24190a7 100644 --- a/src/grammar.ts +++ b/src/grammar.ts @@ -45,7 +45,6 @@ const { makeAdjunctPT, makeBranch, makeBranchCovertLeft, - makeBranchFunctionalLeft, makeConn, makeCovertLeaf, makeLeaf, @@ -110,7 +109,7 @@ const grammar: Grammar = { {"name": "DP", "symbols": ["D", "nP"], "postprocess": makeBranch('DP')}, {"name": "DP", "symbols": ["Focus", "DP"], "postprocess": makeBranch('FocusP')}, {"name": "nP", "symbols": ["nP", "CPrel"], "postprocess": makeBranch('nP')}, - {"name": "nP", "symbols": ["CPdet"], "postprocess": makeBranchFunctionalLeft('nP', 'n')}, + {"name": "nP", "symbols": ["CPdet"], "postprocess": makeBranchCovertLeft('nP', 'n')}, {"name": "Clause", "symbols": ["term", "Bi", "Clause"], "postprocess": make3L('TopicP', "Topic'")}, {"name": "Clause", "symbols": ["MTP"], "postprocess": id}, {"name": "Clause", "symbols": ["DP", "Na", "CPrelna"], "postprocess": make3L('๐˜ทP', "๐˜ท'")}, diff --git a/src/latex.ts b/src/latex.ts index 6e6600b..1eace57 100644 --- a/src/latex.ts +++ b/src/latex.ts @@ -26,9 +26,6 @@ export function toLatex(tree: Tree | DTree): string { const children = tree.children.map(toLatex).join(' '); return `[${label} ${children}]`; } else { - if (tree.word === 'functional') { - return `[${label}]`; - } if (tree.word === 'covert') { return `[${label} [$\\varnothing$]]`; } diff --git a/src/semantics/denote.ts b/src/semantics/denote.ts index 4e0d3d8..9411d42 100644 --- a/src/semantics/denote.ts +++ b/src/semantics/denote.ts @@ -351,10 +351,12 @@ const littleVAgent = ฮป('e', ['s'], c => // ฮป๐˜—. ๐˜— const na = ฮป(['e', 't'], [], c => v(0, c)); -function denoteLittleV(toaq: string | null): Expr { +function denoteLittleV(toaq: string | null): Expr | null { switch (toaq) { - case null: + case 'CAUSE': return littleVAgent; + case 'BE': + return null; case 'nรค': return na; default: @@ -415,9 +417,7 @@ function denoteLeaf(leaf: Leaf, cCommand: StrictTree | null): DTree { denotation = denoteVerb(entry.toaq, entry.frame.split(' ').length); } else if (leaf.label === 'DP') { - if (leaf.word === 'functional') { - throw new Error('Functional DP'); - } else if (leaf.word === 'covert') { + if (leaf.word === 'covert') { denotation = hoa; bindings = covertHoaBindings; } else if (leaf.word.entry === undefined) { @@ -518,22 +518,17 @@ function denoteLeaf(leaf: Leaf, cCommand: StrictTree | null): DTree { }; } else if (leaf.label === '๐˜ท') { let toaq: string | null; - if (typeof leaf.word === 'string') { - toaq = null; + if (leaf.word === 'covert') { + toaq = leaf.value; } else if (leaf.word.entry === undefined) { throw new Error(`Unrecognized ๐˜ท: ${leaf.word.text}`); } else { toaq = leaf.word.entry.toaq; } - denotation = denoteLittleV(toaq); - } else if (leaf.label === '๐˜ท0') { - denotation = null; } else if (leaf.label === 'Asp') { let toaq: string; - if (leaf.word === 'functional') { - throw new Error('Functional Asp'); - } else if (leaf.word === 'covert') { + if (leaf.word === 'covert') { toaq = 'tam'; } else if (leaf.word.entry === undefined) { throw new Error(`Unrecognized Asp: ${leaf.word.text}`); @@ -543,9 +538,7 @@ function denoteLeaf(leaf: Leaf, cCommand: StrictTree | null): DTree { denotation = denoteAspect(toaq); } else if (leaf.label === 'T') { - if (leaf.word === 'functional') { - throw new Error('Functional T'); - } else if (leaf.word === 'covert') { + if (leaf.word === 'covert') { denotation = defaultTense; } else if (leaf.word.entry === undefined) { throw new Error(`Unrecognized T: ${leaf.word.text}`); @@ -556,9 +549,7 @@ function denoteLeaf(leaf: Leaf, cCommand: StrictTree | null): DTree { denotation = null; } else if (leaf.label === 'SA') { let toaq: string; - if (leaf.word === 'functional') { - throw new Error('Functional SA'); - } else if (leaf.word === 'covert') { + if (leaf.word === 'covert') { toaq = 'da'; // TODO: covert mรณq } else if (leaf.word.entry === undefined) { throw new Error(`Unrecognized SA: ${leaf.word.text}`); @@ -771,7 +762,6 @@ function getCompositionRule(left: DTree, right: DTree): CompositionRule { switch (left.label) { case 'V': case 'Asp': - case '๐˜ท0': case 'n': return functionalApplication; case 'T': diff --git a/src/serial.ts b/src/serial.ts index 9670ba9..397265d 100644 --- a/src/serial.ts +++ b/src/serial.ts @@ -2,12 +2,11 @@ import { Branch, Label, Tree } from './tree'; const arityPreservingVerbPrefixes: Label[] = ['buP', 'muP', 'buqP', 'geP']; -const pro: Tree = { label: 'DP', word: 'covert' }; +const pro: Tree = { label: 'DP', word: 'covert', value: 'PRO' }; export function getFrame(verb: Tree): string { if ('word' in verb) { if (verb.word === 'covert') throw new Error('covert verb?'); - if (verb.word === 'functional') throw new Error('functional verb?'); if (verb.word.entry?.type === 'predicate') { return verb.word.entry.frame; } else { @@ -42,7 +41,7 @@ function serialTovP(verbs: Tree[], args: Tree[]): Tree { if (arity === 1) { return { label: '๐˜ทP', - left: { label: '๐˜ท0', word: 'functional' }, + left: { label: '๐˜ท', word: 'covert', value: 'BE' }, right: { label: 'VP', left: verbs[0], right: args[0] }, }; } else if (arity === 2) { @@ -51,7 +50,7 @@ function serialTovP(verbs: Tree[], args: Tree[]): Tree { left: args[0], right: { label: "๐˜ท'", - left: { label: '๐˜ท', word: 'functional' }, + left: { label: '๐˜ท', word: 'covert', value: 'CAUSE' }, right: { label: 'VP', left: verbs[0], right: args[1] }, }, }; @@ -61,7 +60,7 @@ function serialTovP(verbs: Tree[], args: Tree[]): Tree { left: args[0], right: { label: "๐˜ท'", - left: { label: '๐˜ท', word: 'functional' }, + left: { label: '๐˜ท', word: 'covert', value: 'CAUSE' }, right: { label: 'VP', left: args[1], @@ -95,7 +94,7 @@ function serialTovP(verbs: Tree[], args: Tree[]): Tree { if (arity === 1) { return { label: '๐˜ทP', - left: { label: '๐˜ท0', word: 'functional' }, + left: { label: '๐˜ท', word: 'covert', value: 'BE' }, right: { label: 'VP', left: verbs[0], right: inner }, }; } else if (arity === 2) { @@ -104,7 +103,7 @@ function serialTovP(verbs: Tree[], args: Tree[]): Tree { left: args[0], right: { label: "๐˜ท'", - left: { label: '๐˜ท', word: 'functional' }, + left: { label: '๐˜ท', word: 'covert', value: 'CAUSE' }, right: { label: 'VP', left: verbs[0], right: inner }, }, }; @@ -114,7 +113,7 @@ function serialTovP(verbs: Tree[], args: Tree[]): Tree { left: args[0], right: { label: "๐˜ท'", - left: { label: '๐˜ท', word: 'functional' }, + left: { label: '๐˜ท', word: 'covert', value: 'CAUSE' }, right: { label: 'VP', left: args[1], @@ -137,18 +136,19 @@ function attachAdjective(VP: Tree, vP: Tree): Tree { left: { label: 'a', word: 'covert', // TODO ki + value: 'โˆ…', }, right: { // TODO: oh god, adjectives can have T and Asp? // needs rework in nearley grammar label: 'CPrel', - left: { label: 'C', word: 'covert' }, + left: { label: 'C', word: 'covert', value: 'โˆ…' }, right: { label: 'TP', - left: { label: 'T', word: 'covert' }, + left: { label: 'T', word: 'covert', value: 'โˆ…' }, right: { label: 'AspP', - left: { label: 'Asp', word: 'covert' }, + left: { label: 'Asp', word: 'covert', value: 'โˆ…' }, right: vP, }, }, diff --git a/src/textual-tree.ts b/src/textual-tree.ts index f4d9c7f..ab82ec8 100644 --- a/src/textual-tree.ts +++ b/src/textual-tree.ts @@ -3,11 +3,7 @@ import { Tree } from './tree'; function ttree_converted(data: Tree): { label: string; branches: any } { if ('word' in data) { const b = - data.word === 'covert' - ? 'โˆ…' - : data.word === 'functional' - ? '๐Ÿ…ต' - : data.word.text.toLowerCase(); + data.word === 'covert' ? data.value : data.word.text.toLowerCase(); return { label: data.label, branches: [b] }; } else if ('left' in data) { return { diff --git a/src/toaq.ne b/src/toaq.ne index 45bab96..987a753 100644 --- a/src/toaq.ne +++ b/src/toaq.ne @@ -8,7 +8,6 @@ const { makeAdjunctPT, makeBranch, makeBranchCovertLeft, - makeBranchFunctionalLeft, makeConn, makeCovertLeaf, makeLeaf, @@ -61,7 +60,7 @@ DP -> Focus DP {% makeBranch('FocusP') %} # (sรก) ๊กรซ hao nP -> nP CPrel {% makeBranch('nP') %} # (sรก) โˆ… hao -nP -> CPdet {% makeBranchFunctionalLeft('nP', 'n') %} +nP -> CPdet {% makeBranchCovertLeft('nP', 'n') %} # nรญ bรฏ pu hao Clause -> term Bi Clause {% make3L('TopicP', "Topic'") %} diff --git a/src/tree.ts b/src/tree.ts index 620cc3d..3f7aab8 100644 --- a/src/tree.ts +++ b/src/tree.ts @@ -62,7 +62,6 @@ export type Label = | "Topic'" | 'TopicP' | '๐˜ท' - | '๐˜ท0' | "๐˜ท'" | 'V' | "V'" @@ -87,11 +86,7 @@ export function containsWords( stopLabels: Label[], ): boolean { if ('word' in tree) { - return ( - tree.word !== 'covert' && - tree.word !== 'functional' && - words.includes(clean(tree.word.text)) - ); + return tree.word !== 'covert' && words.includes(clean(tree.word.text)); } else if ('left' in tree) { return ( (!stopLabels.includes(tree.left.label) && @@ -116,13 +111,25 @@ export function isQuestion(tree: Tree): boolean { ); } -export interface Leaf { +export interface OvertLeaf { label: Label; id?: string; movedTo?: string; - word: Word | 'covert' | 'functional'; + word: Word; } +type CovertValue = 'โˆ…' | 'BE' | 'CAUSE' | 'PRO'; + +export interface CovertLeaf { + label: Label; + id?: string; + movedTo?: string; + word: 'covert'; + value: CovertValue; +} + +export type Leaf = OvertLeaf | CovertLeaf; + export interface Branch { label: Label; left: T; @@ -189,16 +196,6 @@ export function makeBranch(label: Label) { }; } -export function makeBranchFunctionalLeft(label: Label, functionalLabel: Label) { - return ([right]: [Tree, Tree]) => { - return { - label, - left: { label: functionalLabel, word: 'functional' }, - right, - }; - }; -} - export function makeBranchCovertLeft(label: Label, covertLabel: Label) { return ([right]: [Tree, Tree]) => { return { @@ -366,7 +363,7 @@ export function makeT1ModalvP([modal, tp]: [Tree, Tree]) { label: "๐˜ท'", left: { label: '๐˜ท', - word: 'functional', + word: 'covert', }, right: tp, }, From 6b67a276db2b38bcf906da051693459aeb9fe255 Mon Sep 17 00:00:00 2001 From: Lynn Date: Tue, 5 Sep 2023 22:13:42 +0200 Subject: [PATCH 2/6] The `convert: boolean` approach --- src/boxes.ts | 6 +++--- src/compact.ts | 2 +- src/draw-tree.ts | 5 ++--- src/english.ts | 6 +++--- src/latex.ts | 2 +- src/semantics/denote.ts | 14 ++++++------ src/serial.ts | 25 +++++++++++----------- src/textual-tree.ts | 3 +-- src/tree.ts | 47 +++++++++++++++++++++-------------------- 9 files changed, 54 insertions(+), 56 deletions(-) diff --git a/src/boxes.ts b/src/boxes.ts index a13ac22..6dbe217 100644 --- a/src/boxes.ts +++ b/src/boxes.ts @@ -46,7 +46,7 @@ function skipFree(tree: Tree): Tree { function words(tree: Tree): string { if ('word' in tree) { - if (tree.word === 'covert') { + if (tree.word.covert) { return ''; } else { return tree.word.text; @@ -91,7 +91,7 @@ function boxifyClause(tree: Tree): BoxClause { if (!('left' in cp)) throw new Error('bad CP?'); const c = cp.left; if (!('word' in c)) throw new Error('C without word?'); - if (c.word !== 'covert') { + if (!c.word.covert) { complementizer = c.word.text; } for (let node = cp.right; ; ) { @@ -149,7 +149,7 @@ export function boxify(tree: Tree): BoxSentence { const sa = tree.right; if (sa.label !== 'SA') throw new Error('SAP without SA?'); if (!('word' in sa)) throw new Error('SA without word?'); - if (sa.word !== 'covert') { + if (!sa.word.covert) { speechAct = sa.word.text; } const cp = tree.left; diff --git a/src/compact.ts b/src/compact.ts index b74bb46..fd06c72 100644 --- a/src/compact.ts +++ b/src/compact.ts @@ -1,7 +1,7 @@ import { Branch, Leaf, Tree, nodeType } from './tree'; function isCovert(tree: Tree): boolean { - return 'word' in tree && typeof tree.word === 'string'; + return 'word' in tree && tree.word.covert; } export function compact(tree: Tree): Tree { diff --git a/src/draw-tree.ts b/src/draw-tree.ts index 2775587..6905476 100644 --- a/src/draw-tree.ts +++ b/src/draw-tree.ts @@ -50,10 +50,9 @@ export function placeLeaf( ctx: CanvasRenderingContext2D, leaf: Leaf | (Leaf & { denotation: Expr | null }), ): PlacedLeaf { - const gloss = - typeof leaf.word === 'string' ? undefined : leaf.word.entry?.gloss; + const gloss = leaf.word.covert ? undefined : leaf.word.entry?.gloss; const label = getLabel(leaf); - const word = leaf.word === 'covert' ? leaf.value : leaf.word.text; + const word = leaf.word.covert ? leaf.word.value : leaf.word.text; const denotation = 'denotation' in leaf && leaf.denotation !== null ? toPlainText(leaf.denotation) diff --git a/src/english.ts b/src/english.ts index 4371ffe..8bf886f 100644 --- a/src/english.ts +++ b/src/english.ts @@ -13,7 +13,7 @@ function leafText(tree: Tree): string { if (!('word' in tree)) { throw new Error('Unexpected non-leaf ' + tree.label); } - if (tree.word === 'covert') return ''; + if (tree.word.covert) return ''; return tree.word.text; } @@ -47,7 +47,7 @@ function verbToEnglish(tree: Tree): string { } function serialToEnglish(serial: Tree): string { - if ('word' in serial && serial.word === 'covert') return ''; + if ('word' in serial && serial.word.covert) return ''; if (serial.label !== '*Serial') throw new Error('non-*Serial serial'); if (!('children' in serial)) throw new Error('non-Rose serial'); return serial.children.map(x => verbToEnglish(x)).join('-'); @@ -363,7 +363,7 @@ function branchToEnglish(tree: Branch): Constituent { { she: 'necessarily', ao: 'would', daฤฑ: 'possibly', ea: 'could' }[ bare(leafText(modal)) ] ?? '?'; - if (c.word === 'covert') { + if (c.word.covert) { return { text: eng }; } else { return { diff --git a/src/latex.ts b/src/latex.ts index 1eace57..35b02ec 100644 --- a/src/latex.ts +++ b/src/latex.ts @@ -26,7 +26,7 @@ export function toLatex(tree: Tree | DTree): string { const children = tree.children.map(toLatex).join(' '); return `[${label} ${children}]`; } else { - if (tree.word === 'covert') { + if (tree.word.covert) { return `[${label} [$\\varnothing$]]`; } diff --git a/src/semantics/denote.ts b/src/semantics/denote.ts index 9411d42..76fea1e 100644 --- a/src/semantics/denote.ts +++ b/src/semantics/denote.ts @@ -410,14 +410,14 @@ function denoteLeaf(leaf: Leaf, cCommand: StrictTree | null): DTree { let bindings = noBindings; if (leaf.label === 'V') { - if (typeof leaf.word === 'string') throw new Error(); + if (leaf.word.covert) throw new Error('covert V'); const entry = leaf.word.entry; if (!entry) throw new Error(); if (entry.type !== 'predicate') throw new Error(); denotation = denoteVerb(entry.toaq, entry.frame.split(' ').length); } else if (leaf.label === 'DP') { - if (leaf.word === 'covert') { + if (leaf.word.covert) { denotation = hoa; bindings = covertHoaBindings; } else if (leaf.word.entry === undefined) { @@ -518,8 +518,8 @@ function denoteLeaf(leaf: Leaf, cCommand: StrictTree | null): DTree { }; } else if (leaf.label === '๐˜ท') { let toaq: string | null; - if (leaf.word === 'covert') { - toaq = leaf.value; + if (leaf.word.covert) { + toaq = leaf.word.value; } else if (leaf.word.entry === undefined) { throw new Error(`Unrecognized ๐˜ท: ${leaf.word.text}`); } else { @@ -528,7 +528,7 @@ function denoteLeaf(leaf: Leaf, cCommand: StrictTree | null): DTree { denotation = denoteLittleV(toaq); } else if (leaf.label === 'Asp') { let toaq: string; - if (leaf.word === 'covert') { + if (leaf.word.covert) { toaq = 'tam'; } else if (leaf.word.entry === undefined) { throw new Error(`Unrecognized Asp: ${leaf.word.text}`); @@ -538,7 +538,7 @@ function denoteLeaf(leaf: Leaf, cCommand: StrictTree | null): DTree { denotation = denoteAspect(toaq); } else if (leaf.label === 'T') { - if (leaf.word === 'covert') { + if (leaf.word.covert) { denotation = defaultTense; } else if (leaf.word.entry === undefined) { throw new Error(`Unrecognized T: ${leaf.word.text}`); @@ -549,7 +549,7 @@ function denoteLeaf(leaf: Leaf, cCommand: StrictTree | null): DTree { denotation = null; } else if (leaf.label === 'SA') { let toaq: string; - if (leaf.word === 'covert') { + if (leaf.word.covert) { toaq = 'da'; // TODO: covert mรณq } else if (leaf.word.entry === undefined) { throw new Error(`Unrecognized SA: ${leaf.word.text}`); diff --git a/src/serial.ts b/src/serial.ts index 397265d..3dad5a0 100644 --- a/src/serial.ts +++ b/src/serial.ts @@ -2,11 +2,11 @@ import { Branch, Label, Tree } from './tree'; const arityPreservingVerbPrefixes: Label[] = ['buP', 'muP', 'buqP', 'geP']; -const pro: Tree = { label: 'DP', word: 'covert', value: 'PRO' }; +const pro: Tree = { label: 'DP', word: { covert: true, value: 'PRO' } }; export function getFrame(verb: Tree): string { if ('word' in verb) { - if (verb.word === 'covert') throw new Error('covert verb?'); + if (verb.word.covert) throw new Error('covert verb?'); if (verb.word.entry?.type === 'predicate') { return verb.word.entry.frame; } else { @@ -41,7 +41,7 @@ function serialTovP(verbs: Tree[], args: Tree[]): Tree { if (arity === 1) { return { label: '๐˜ทP', - left: { label: '๐˜ท', word: 'covert', value: 'BE' }, + left: { label: '๐˜ท', word: { covert: true, value: 'BE' } }, right: { label: 'VP', left: verbs[0], right: args[0] }, }; } else if (arity === 2) { @@ -50,7 +50,7 @@ function serialTovP(verbs: Tree[], args: Tree[]): Tree { left: args[0], right: { label: "๐˜ท'", - left: { label: '๐˜ท', word: 'covert', value: 'CAUSE' }, + left: { label: '๐˜ท', word: { covert: true, value: 'CAUSE' } }, right: { label: 'VP', left: verbs[0], right: args[1] }, }, }; @@ -60,7 +60,7 @@ function serialTovP(verbs: Tree[], args: Tree[]): Tree { left: args[0], right: { label: "๐˜ท'", - left: { label: '๐˜ท', word: 'covert', value: 'CAUSE' }, + left: { label: '๐˜ท', word: { covert: true, value: 'CAUSE' } }, right: { label: 'VP', left: args[1], @@ -94,7 +94,7 @@ function serialTovP(verbs: Tree[], args: Tree[]): Tree { if (arity === 1) { return { label: '๐˜ทP', - left: { label: '๐˜ท', word: 'covert', value: 'BE' }, + left: { label: '๐˜ท', word: { covert: true, value: 'BE' } }, right: { label: 'VP', left: verbs[0], right: inner }, }; } else if (arity === 2) { @@ -103,7 +103,7 @@ function serialTovP(verbs: Tree[], args: Tree[]): Tree { left: args[0], right: { label: "๐˜ท'", - left: { label: '๐˜ท', word: 'covert', value: 'CAUSE' }, + left: { label: '๐˜ท', word: { covert: true, value: 'CAUSE' } }, right: { label: 'VP', left: verbs[0], right: inner }, }, }; @@ -113,7 +113,7 @@ function serialTovP(verbs: Tree[], args: Tree[]): Tree { left: args[0], right: { label: "๐˜ท'", - left: { label: '๐˜ท', word: 'covert', value: 'CAUSE' }, + left: { label: '๐˜ท', word: { covert: true, value: 'CAUSE' } }, right: { label: 'VP', left: args[1], @@ -135,20 +135,19 @@ function attachAdjective(VP: Tree, vP: Tree): Tree { label: 'aP', left: { label: 'a', - word: 'covert', // TODO ki - value: 'โˆ…', + word: { covert: true, value: 'โˆ…' }, // TODO ki }, right: { // TODO: oh god, adjectives can have T and Asp? // needs rework in nearley grammar label: 'CPrel', - left: { label: 'C', word: 'covert', value: 'โˆ…' }, + left: { label: 'C', word: { covert: true, value: 'โˆ…' } }, right: { label: 'TP', - left: { label: 'T', word: 'covert', value: 'โˆ…' }, + left: { label: 'T', word: { covert: true, value: 'โˆ…' } }, right: { label: 'AspP', - left: { label: 'Asp', word: 'covert', value: 'โˆ…' }, + left: { label: 'Asp', word: { covert: true, value: 'โˆ…' } }, right: vP, }, }, diff --git a/src/textual-tree.ts b/src/textual-tree.ts index ab82ec8..76d1932 100644 --- a/src/textual-tree.ts +++ b/src/textual-tree.ts @@ -2,8 +2,7 @@ import { Tree } from './tree'; function ttree_converted(data: Tree): { label: string; branches: any } { if ('word' in data) { - const b = - data.word === 'covert' ? data.value : data.word.text.toLowerCase(); + const b = data.word.covert ? data.word.value : data.word.text.toLowerCase(); return { label: data.label, branches: [b] }; } else if ('left' in data) { return { diff --git a/src/tree.ts b/src/tree.ts index 3f7aab8..de8885c 100644 --- a/src/tree.ts +++ b/src/tree.ts @@ -4,6 +4,7 @@ import { bare, clean, ToaqToken, tone } from './tokenize'; import { Tone } from './types'; export interface Word { + covert: false; index: number | undefined; text: string; bare: string; @@ -11,6 +12,13 @@ export interface Word { entry: Entry | undefined; } +type CovertValue = 'โˆ…' | 'BE' | 'CAUSE' | 'PRO'; + +export interface CovertWord { + covert: true; + value: CovertValue; +} + export type Label = | '*Serial' | '*๐˜ทP' @@ -86,7 +94,7 @@ export function containsWords( stopLabels: Label[], ): boolean { if ('word' in tree) { - return tree.word !== 'covert' && words.includes(clean(tree.word.text)); + return !tree.word.covert && words.includes(clean(tree.word.text)); } else if ('left' in tree) { return ( (!stopLabels.includes(tree.left.label) && @@ -111,25 +119,13 @@ export function isQuestion(tree: Tree): boolean { ); } -export interface OvertLeaf { +export interface Leaf { label: Label; id?: string; movedTo?: string; - word: Word; + word: Word | CovertWord; } -type CovertValue = 'โˆ…' | 'BE' | 'CAUSE' | 'PRO'; - -export interface CovertLeaf { - label: Label; - id?: string; - movedTo?: string; - word: 'covert'; - value: CovertValue; -} - -export type Leaf = OvertLeaf | CovertLeaf; - export interface Branch { label: Label; left: T; @@ -154,6 +150,7 @@ export function makeWord([token]: [ToaqToken]): Word { const lemmaForm = token.value.toLowerCase().normalize(); const bareWord = bare(token.value); return { + covert: false, index: token.index, text: token.value, bare: bareWord, @@ -182,7 +179,7 @@ export function makeLeaf(label: Label) { export function makeCovertLeaf(label: Label) { return () => ({ label, - word: 'covert', + word: { covert: true, value: 'โˆ…' }, }); } @@ -200,7 +197,7 @@ export function makeBranchCovertLeft(label: Label, covertLabel: Label) { return ([right]: [Tree, Tree]) => { return { label, - left: { label: covertLabel, word: 'covert' }, + left: { label: covertLabel, word: { covert: true, value: 'โˆ…' } }, right, }; }; @@ -245,7 +242,7 @@ export function makeSingleChild(label: Label) { export function makeOptLeaf(label: Label) { return ([leaf]: [Leaf | undefined]) => { - return leaf ?? { label, word: 'covert' }; + return leaf ?? { label, word: { covert: true, value: 'โˆ…' } }; }; } @@ -302,7 +299,7 @@ export function makevPdet([serial]: [Tree], location: number, reject: Object) { } return { label: '*๐˜ทP', - children: [serial, { label: 'DP', word: 'covert' }], + children: [serial, { label: 'DP', word: { covert: true, value: 'โˆ…' } }], }; } @@ -356,14 +353,14 @@ export function makeT1ModalvP([modal, tp]: [Tree, Tree]) { left: modal, right: { label: 'CP', - word: 'covert', + word: { covert: true, value: 'โˆ…' }, }, }, right: { label: "๐˜ท'", left: { label: '๐˜ท', - word: 'covert', + word: { covert: true, value: 'BE' }, }, right: tp, }, @@ -396,13 +393,17 @@ export function makePrefixP([prefix, verb]: [Tree, Tree]) { export function makeRetroactiveCleft([tp, vgo, clause]: [Tree, Tree, Tree]) { return { label: '๐˜ทP', - left: { label: 'CP', left: { label: 'C', word: 'covert' }, right: tp }, + left: { + label: 'CP', + left: { label: 'C', word: { covert: true, value: 'โˆ…' } }, + right: tp, + }, right: { label: "๐˜ท'", left: vgo, right: { label: 'CPrel', - left: { label: 'C', word: 'covert' }, + left: { label: 'C', word: { covert: true, value: 'โˆ…' } }, right: clause, }, }, From 8769d4436770f5ca83db51a04b47732fc08ed76a Mon Sep 17 00:00:00 2001 From: Lynn Date: Tue, 5 Sep 2023 22:16:44 +0200 Subject: [PATCH 3/6] Split denoteLittleV --- src/semantics/denote.ts | 19 ++++++++++++------- src/tree.ts | 2 +- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/semantics/denote.ts b/src/semantics/denote.ts index 76fea1e..3c7278a 100644 --- a/src/semantics/denote.ts +++ b/src/semantics/denote.ts @@ -1,5 +1,5 @@ import { VerbEntry } from '../dictionary'; -import { Branch, Leaf, StrictTree, Word } from '../tree'; +import { Branch, CovertValue, Leaf, StrictTree, Word } from '../tree'; import { after, afterNear, @@ -351,12 +351,19 @@ const littleVAgent = ฮป('e', ['s'], c => // ฮป๐˜—. ๐˜— const na = ฮป(['e', 't'], [], c => v(0, c)); -function denoteLittleV(toaq: string | null): Expr | null { - switch (toaq) { +function denoteCovertLittleV(value: CovertValue): Expr | null { + switch (value) { case 'CAUSE': return littleVAgent; case 'BE': return null; + default: + throw new Error(`Unrecognized ๐˜ท: ${value}`); + } +} + +function denoteOvertLittleV(toaq: string | null): Expr | null { + switch (toaq) { case 'nรค': return na; default: @@ -517,15 +524,13 @@ function denoteLeaf(leaf: Leaf, cCommand: StrictTree | null): DTree { covertResumptive: binding, }; } else if (leaf.label === '๐˜ท') { - let toaq: string | null; if (leaf.word.covert) { - toaq = leaf.word.value; + denotation = denoteCovertLittleV(leaf.word.value); } else if (leaf.word.entry === undefined) { throw new Error(`Unrecognized ๐˜ท: ${leaf.word.text}`); } else { - toaq = leaf.word.entry.toaq; + denotation = denoteOvertLittleV(leaf.word.entry.toaq); } - denotation = denoteLittleV(toaq); } else if (leaf.label === 'Asp') { let toaq: string; if (leaf.word.covert) { diff --git a/src/tree.ts b/src/tree.ts index de8885c..5e532cd 100644 --- a/src/tree.ts +++ b/src/tree.ts @@ -12,7 +12,7 @@ export interface Word { entry: Entry | undefined; } -type CovertValue = 'โˆ…' | 'BE' | 'CAUSE' | 'PRO'; +export type CovertValue = 'โˆ…' | 'BE' | 'CAUSE' | 'PRO'; export interface CovertWord { covert: true; From d31ed619c1f44ce54e8fa2c126b41569dfe5790e Mon Sep 17 00:00:00 2001 From: Robin Date: Tue, 5 Sep 2023 16:20:40 -0400 Subject: [PATCH 4/6] Use narrower type for denoteOvertLittleV --- src/semantics/denote.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/semantics/denote.ts b/src/semantics/denote.ts index 3c7278a..6ece0d1 100644 --- a/src/semantics/denote.ts +++ b/src/semantics/denote.ts @@ -362,7 +362,7 @@ function denoteCovertLittleV(value: CovertValue): Expr | null { } } -function denoteOvertLittleV(toaq: string | null): Expr | null { +function denoteOvertLittleV(toaq: string): Expr | null { switch (toaq) { case 'nรค': return na; From 49e36c6a1d26220b15c54fbed1d758a206d76a54 Mon Sep 17 00:00:00 2001 From: Lynn Date: Tue, 5 Sep 2023 22:22:28 +0200 Subject: [PATCH 5/6] Helper function for making null leaves --- src/serial.ts | 13 +++++-------- src/tree.ts | 27 ++++++++++++++------------- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/serial.ts b/src/serial.ts index 3dad5a0..4f656c3 100644 --- a/src/serial.ts +++ b/src/serial.ts @@ -1,4 +1,4 @@ -import { Branch, Label, Tree } from './tree'; +import { Branch, Label, Tree, makeNull } from './tree'; const arityPreservingVerbPrefixes: Label[] = ['buP', 'muP', 'buqP', 'geP']; @@ -133,21 +133,18 @@ function attachAdjective(VP: Tree, vP: Tree): Tree { left: VP, right: { label: 'aP', - left: { - label: 'a', - word: { covert: true, value: 'โˆ…' }, // TODO ki - }, + left: makeNull('a'), // TODO ki- right: { // TODO: oh god, adjectives can have T and Asp? // needs rework in nearley grammar label: 'CPrel', - left: { label: 'C', word: { covert: true, value: 'โˆ…' } }, + left: makeNull('C'), right: { label: 'TP', - left: { label: 'T', word: { covert: true, value: 'โˆ…' } }, + left: makeNull('T'), right: { label: 'AspP', - left: { label: 'Asp', word: { covert: true, value: 'โˆ…' } }, + left: makeNull('Asp'), right: vP, }, }, diff --git a/src/tree.ts b/src/tree.ts index 5e532cd..e028be4 100644 --- a/src/tree.ts +++ b/src/tree.ts @@ -19,6 +19,13 @@ export interface CovertWord { value: CovertValue; } +/** + * Make a null leaf with the given label. + */ +export function makeNull(label: Label): Leaf { + return { label, word: { covert: true, value: 'โˆ…' } }; +} + export type Label = | '*Serial' | '*๐˜ทP' @@ -177,10 +184,7 @@ export function makeLeaf(label: Label) { } export function makeCovertLeaf(label: Label) { - return () => ({ - label, - word: { covert: true, value: 'โˆ…' }, - }); + return () => makeNull(label); } export function makeBranch(label: Label) { @@ -197,7 +201,7 @@ export function makeBranchCovertLeft(label: Label, covertLabel: Label) { return ([right]: [Tree, Tree]) => { return { label, - left: { label: covertLabel, word: { covert: true, value: 'โˆ…' } }, + left: makeNull(covertLabel), right, }; }; @@ -242,7 +246,7 @@ export function makeSingleChild(label: Label) { export function makeOptLeaf(label: Label) { return ([leaf]: [Leaf | undefined]) => { - return leaf ?? { label, word: { covert: true, value: 'โˆ…' } }; + return leaf ?? makeNull(label); }; } @@ -299,7 +303,7 @@ export function makevPdet([serial]: [Tree], location: number, reject: Object) { } return { label: '*๐˜ทP', - children: [serial, { label: 'DP', word: { covert: true, value: 'โˆ…' } }], + children: [serial, { label: 'DP', word: { covert: true, value: 'PRO' } }], }; } @@ -351,10 +355,7 @@ export function makeT1ModalvP([modal, tp]: [Tree, Tree]) { left: { label: 'ModalP', left: modal, - right: { - label: 'CP', - word: { covert: true, value: 'โˆ…' }, - }, + right: makeNull('CP'), }, right: { label: "๐˜ท'", @@ -395,7 +396,7 @@ export function makeRetroactiveCleft([tp, vgo, clause]: [Tree, Tree, Tree]) { label: '๐˜ทP', left: { label: 'CP', - left: { label: 'C', word: { covert: true, value: 'โˆ…' } }, + left: makeNull('C'), right: tp, }, right: { @@ -403,7 +404,7 @@ export function makeRetroactiveCleft([tp, vgo, clause]: [Tree, Tree, Tree]) { left: vgo, right: { label: 'CPrel', - left: { label: 'C', word: { covert: true, value: 'โˆ…' } }, + left: makeNull('C'), right: clause, }, }, From ecf1e5c01b5522696513686607c39ed611e1cae8 Mon Sep 17 00:00:00 2001 From: Lynn Date: Tue, 5 Sep 2023 22:22:53 +0200 Subject: [PATCH 6/6] Oh, we can narrow the return type too --- src/semantics/denote.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/semantics/denote.ts b/src/semantics/denote.ts index 6ece0d1..2526ec7 100644 --- a/src/semantics/denote.ts +++ b/src/semantics/denote.ts @@ -362,7 +362,7 @@ function denoteCovertLittleV(value: CovertValue): Expr | null { } } -function denoteOvertLittleV(toaq: string): Expr | null { +function denoteOvertLittleV(toaq: string): Expr { switch (toaq) { case 'nรค': return na;