diff --git a/src/grammar.ts b/src/grammar.ts index dbb35e7..2356881 100644 --- a/src/grammar.ts +++ b/src/grammar.ts @@ -173,27 +173,33 @@ const grammar: Grammar = { {"name": "AspP_main", "symbols": ["Aspcon", "vP_main"], "postprocess": makeBranch('AspP')}, {"name": "AspP_sub", "symbols": ["Aspcon", "vP_sub"], "postprocess": makeBranch('AspP')}, {"name": "AspPdet", "symbols": ["Aspcon", "vPdet"], "postprocess": makeBranch('AspP')}, - {"name": "vP_main$ebnf$1", "symbols": []}, - {"name": "vP_main$ebnf$1", "symbols": ["vP_main$ebnf$1", "AdjunctPcon"], "postprocess": (d) => d[0].concat([d[1]])}, - {"name": "vP_main$ebnf$2$subexpression$1$ebnf$1", "symbols": ["VocArgument"]}, - {"name": "vP_main$ebnf$2$subexpression$1$ebnf$1", "symbols": ["vP_main$ebnf$2$subexpression$1$ebnf$1", "VocArgument"], "postprocess": (d) => d[0].concat([d[1]])}, - {"name": "vP_main$ebnf$2$subexpression$1$ebnf$2", "symbols": []}, - {"name": "vP_main$ebnf$2$subexpression$1$ebnf$2", "symbols": ["vP_main$ebnf$2$subexpression$1$ebnf$2", "AdjunctPcon"], "postprocess": (d) => d[0].concat([d[1]])}, - {"name": "vP_main$ebnf$2$subexpression$1", "symbols": ["vP_main$ebnf$2$subexpression$1$ebnf$1", "vP_main$ebnf$2$subexpression$1$ebnf$2"]}, - {"name": "vP_main$ebnf$2", "symbols": ["vP_main$ebnf$2$subexpression$1"], "postprocess": id}, - {"name": "vP_main$ebnf$2", "symbols": [], "postprocess": () => null}, - {"name": "vP_main", "symbols": ["Serial", "vP_main$ebnf$1", "vP_main$ebnf$2"], "postprocess": makevP_main}, - {"name": "vP_sub$ebnf$1", "symbols": []}, - {"name": "vP_sub$ebnf$1", "symbols": ["vP_sub$ebnf$1", "AdjunctPcon"], "postprocess": (d) => d[0].concat([d[1]])}, - {"name": "vP_sub$ebnf$2$subexpression$1$ebnf$1", "symbols": ["VocArgument"]}, - {"name": "vP_sub$ebnf$2$subexpression$1$ebnf$1", "symbols": ["vP_sub$ebnf$2$subexpression$1$ebnf$1", "VocArgument"], "postprocess": (d) => d[0].concat([d[1]])}, - {"name": "vP_sub$ebnf$2$subexpression$1$ebnf$2", "symbols": []}, - {"name": "vP_sub$ebnf$2$subexpression$1$ebnf$2", "symbols": ["vP_sub$ebnf$2$subexpression$1$ebnf$2", "AdjunctPcon"], "postprocess": (d) => d[0].concat([d[1]])}, - {"name": "vP_sub$ebnf$2$subexpression$1", "symbols": ["vP_sub$ebnf$2$subexpression$1$ebnf$1", "vP_sub$ebnf$2$subexpression$1$ebnf$2"]}, - {"name": "vP_sub$ebnf$2", "symbols": ["vP_sub$ebnf$2$subexpression$1"], "postprocess": id}, - {"name": "vP_sub$ebnf$2", "symbols": [], "postprocess": () => null}, - {"name": "vP_sub", "symbols": ["Serial", "vP_sub$ebnf$1", "vP_sub$ebnf$2"], "postprocess": makevP_sub}, - {"name": "vPdet", "symbols": ["Serialdet"], "postprocess": makevPdet}, + {"name": "vP_main$ebnf$1", "symbols": ["Argincorp"], "postprocess": id}, + {"name": "vP_main$ebnf$1", "symbols": [], "postprocess": () => null}, + {"name": "vP_main$ebnf$2", "symbols": []}, + {"name": "vP_main$ebnf$2", "symbols": ["vP_main$ebnf$2", "AdjunctPcon"], "postprocess": (d) => d[0].concat([d[1]])}, + {"name": "vP_main$ebnf$3$subexpression$1$ebnf$1", "symbols": ["VocArgument"]}, + {"name": "vP_main$ebnf$3$subexpression$1$ebnf$1", "symbols": ["vP_main$ebnf$3$subexpression$1$ebnf$1", "VocArgument"], "postprocess": (d) => d[0].concat([d[1]])}, + {"name": "vP_main$ebnf$3$subexpression$1$ebnf$2", "symbols": []}, + {"name": "vP_main$ebnf$3$subexpression$1$ebnf$2", "symbols": ["vP_main$ebnf$3$subexpression$1$ebnf$2", "AdjunctPcon"], "postprocess": (d) => d[0].concat([d[1]])}, + {"name": "vP_main$ebnf$3$subexpression$1", "symbols": ["vP_main$ebnf$3$subexpression$1$ebnf$1", "vP_main$ebnf$3$subexpression$1$ebnf$2"]}, + {"name": "vP_main$ebnf$3", "symbols": ["vP_main$ebnf$3$subexpression$1"], "postprocess": id}, + {"name": "vP_main$ebnf$3", "symbols": [], "postprocess": () => null}, + {"name": "vP_main", "symbols": ["Serial", "vP_main$ebnf$1", "vP_main$ebnf$2", "vP_main$ebnf$3"], "postprocess": makevP_main}, + {"name": "vP_sub$ebnf$1", "symbols": ["Argincorp"], "postprocess": id}, + {"name": "vP_sub$ebnf$1", "symbols": [], "postprocess": () => null}, + {"name": "vP_sub$ebnf$2", "symbols": []}, + {"name": "vP_sub$ebnf$2", "symbols": ["vP_sub$ebnf$2", "AdjunctPcon"], "postprocess": (d) => d[0].concat([d[1]])}, + {"name": "vP_sub$ebnf$3$subexpression$1$ebnf$1", "symbols": ["VocArgument"]}, + {"name": "vP_sub$ebnf$3$subexpression$1$ebnf$1", "symbols": ["vP_sub$ebnf$3$subexpression$1$ebnf$1", "VocArgument"], "postprocess": (d) => d[0].concat([d[1]])}, + {"name": "vP_sub$ebnf$3$subexpression$1$ebnf$2", "symbols": []}, + {"name": "vP_sub$ebnf$3$subexpression$1$ebnf$2", "symbols": ["vP_sub$ebnf$3$subexpression$1$ebnf$2", "AdjunctPcon"], "postprocess": (d) => d[0].concat([d[1]])}, + {"name": "vP_sub$ebnf$3$subexpression$1", "symbols": ["vP_sub$ebnf$3$subexpression$1$ebnf$1", "vP_sub$ebnf$3$subexpression$1$ebnf$2"]}, + {"name": "vP_sub$ebnf$3", "symbols": ["vP_sub$ebnf$3$subexpression$1"], "postprocess": id}, + {"name": "vP_sub$ebnf$3", "symbols": [], "postprocess": () => null}, + {"name": "vP_sub", "symbols": ["Serial", "vP_sub$ebnf$1", "vP_sub$ebnf$2", "vP_sub$ebnf$3"], "postprocess": makevP_sub}, + {"name": "vPdet$ebnf$1", "symbols": ["Argincorp"], "postprocess": id}, + {"name": "vPdet$ebnf$1", "symbols": [], "postprocess": () => null}, + {"name": "vPdet", "symbols": ["Serialdet", "vPdet$ebnf$1"], "postprocess": makevPdet}, {"name": "AdjunctP", "symbols": ["Adjunct", "Serial", "Argument"], "postprocess": makeAdjunctPT}, {"name": "AdjunctP", "symbols": ["Adjunct", "Serial"], "postprocess": makeAdjunctPI}, {"name": "Serial$ebnf$1", "symbols": []}, @@ -203,8 +209,6 @@ const grammar: Grammar = { {"name": "V1orKi", "symbols": ["Ki"], "postprocess": id}, {"name": "Serialdet", "symbols": ["Serial"], "postprocess": id}, {"name": "Serialdet", "symbols": [], "postprocess": makeEmptySerial()}, - {"name": "VPincorp", "symbols": ["V", "DPincorp"], "postprocess": makeBranch('VP')}, - {"name": "VPincorp", "symbols": ["V", "CPincorp"], "postprocess": makeBranch('VP')}, {"name": "DPincorp$ebnf$1", "symbols": []}, {"name": "DPincorp$ebnf$1", "symbols": ["DPincorp$ebnf$1", "Free"], "postprocess": (d) => d[0].concat([d[1]])}, {"name": "DPincorp", "symbols": [(lexer.has("incorporated_pronoun") ? {type: "incorporated_pronoun"} : incorporated_pronoun), "DPincorp$ebnf$1"], "postprocess": makeLeaf('DP')}, @@ -213,6 +217,8 @@ const grammar: Grammar = { {"name": "VPoiv", "symbols": ["Voiv", "DPcon"], "postprocess": makeBranch('VP')}, {"name": "Argument", "symbols": ["DPcon"], "postprocess": id}, {"name": "Argument", "symbols": ["CPargcon"], "postprocess": id}, + {"name": "Argincorp", "symbols": ["DPincorp"], "postprocess": id}, + {"name": "Argincorp", "symbols": ["CPincorp"], "postprocess": id}, {"name": "DPcon", "symbols": ["DProi"], "postprocess": id}, {"name": "DPcon", "symbols": ["DProi", "Conjunction", "DPcon"], "postprocess": makeConn}, {"name": "DPcon", "symbols": ["DProi", "ConjunctionT1", "CPargcon"], "postprocess": makeConn}, @@ -242,7 +248,6 @@ const grammar: Grammar = { {"name": "AdjunctPcon", "symbols": ["AdjunctPfoc", "Conjunction", "AdjunctPcon"], "postprocess": makeConn}, {"name": "AdjunctPfoc", "symbols": ["AdjunctP"], "postprocess": id}, {"name": "AdjunctPfoc", "symbols": ["Focus", "AdjunctP"], "postprocess": makeBranch('FocusP')}, - {"name": "Vlast", "symbols": ["VPincorp"], "postprocess": id}, {"name": "Vlast", "symbols": ["VPoiv"], "postprocess": id}, {"name": "Vlast", "symbols": ["Verb", "ConjunctionT1", "Vlast"], "postprocess": makeConn}, {"name": "Vlast", "symbols": ["Verb"], "postprocess": id}, diff --git a/src/semantics/denote.test.ts b/src/semantics/denote.test.ts index 6ffe5c4..c833ac4 100644 --- a/src/semantics/denote.test.ts +++ b/src/semantics/denote.test.ts @@ -2,7 +2,6 @@ import { test, expect } from 'vitest'; import { parse } from '../modes/parse'; import { recover } from '../syntax/recover'; import { denote } from './denote'; -import { Expr } from './model'; import { toPlainText } from './render'; import { Impossible } from '../core/error'; import { freeVariableUsages } from './operations'; @@ -415,3 +414,12 @@ test('subclauses open a new scope', () => { "\"ASSERT(λ𝘸. (∃𝘦. τ(𝘦) ⊆ t'''' ∧ gaı.𝘸(b, a)(𝘦) | (∃𝘦. τ(𝘦) ⊆ t''' ∧ poq.𝘸(b)(𝘦)) ∧ ∀.SING 𝘹 : ∃𝘦. τ(𝘦) ⊆ t' ∧ rua.𝘸(𝘹)(𝘦). (∃𝘦. τ(𝘦) ⊆ t'' ∧ cho.𝘸(b, 𝘹)(𝘦) | inanimate(𝘹)) | ∃𝘦. τ(𝘦) ⊆ t ∧ rua.𝘸(a)(𝘦))) | animate(b) | inanimate(a)\"", ); }); + +test('incorporated object scopes under other arguments', () => { + expect(d('Joe tû raı sía poq')).toMatchInlineSnapshot( + "\"ASSERT(λ𝘸. ¬∃𝘹 : ∃𝘦. τ(𝘦) ⊆ t' ∧ poq.𝘸(𝘹)(𝘦). (∀.SING 𝘺 : ∃𝘦. τ(𝘦) ⊆ t ∧ raı.𝘸(𝘺)(𝘦). ∃𝘦. τ(𝘦) ⊆ t'' ∧ joe.𝘸(𝘹, 𝘺)(𝘦) | animate(𝘹)))\"", + ); + expect(d('Do sâ kue sá poq jí')).toMatchInlineSnapshot( + "\"ASSERT(λ𝘸. ∃𝘹 : ∃𝘦. τ(𝘦) ⊆ t' ∧ poq.𝘸(𝘹)(𝘦). (∃𝘺 : ∃𝘦. τ(𝘦) ⊆ t ∧ kue.𝘸(𝘺)(𝘦). (∃𝘦. τ(𝘦) ⊆ t'' ∧ AGENT(𝘦)(𝘸) = 𝘹 ∧ do.𝘸(jí, 𝘺)(𝘦) | inanimate(𝘺)) | animate(𝘹)))\"", + ); +}); diff --git a/src/syntax/serial.ts b/src/syntax/serial.ts index dc053ed..bfa887e 100644 --- a/src/syntax/serial.ts +++ b/src/syntax/serial.ts @@ -1,5 +1,6 @@ import { Impossible, Ungrammatical, Unimplemented } from '../core/error'; import { splitNonEmpty } from '../core/misc'; +import { Tone } from '../morphology/tone'; import { Branch, Label, @@ -302,6 +303,29 @@ function attachAdjective(VP: Tree, kivP: KivP): Tree { }; } +/** + * Determines whether an argument is an incorporated object. + */ +function isArgIncorp(dp: Tree): boolean { + let head: Leaf; + if ('word' in dp) { + head = dp; + } else { + assertBranch(dp); + assertLeaf(dp.left); + if (dp.left.word.covert) { + const cp = dp.right; + assertBranch(cp); + assertLeaf(cp.left); + head = cp.left; + } else { + head = dp.left; + } + } + + return !head.word.covert && head.word.tone === Tone.T4; +} + /** * Turn the given *Serial and terms into a proper 𝘷P, by: * @@ -348,19 +372,21 @@ export function fixSerial( } if (0 !== end) segments.unshift(children.slice(0, end)); - let earlyAdjuncts = []; - let args = []; - let lateAdjuncts = []; + let earlyAdjuncts: Tree[] = []; + let args: Tree[] = []; + let argIncorp: Tree | null = null; + let lateAdjuncts: Tree[] = []; for (const term of terms) { - const label = effectiveLabel(term); - if (label === 'DP' || label === 'CP') { - args.push(term); - } else if (args.length) { - lateAdjuncts.push(term); + if (term.label === 'DP' && isArgIncorp(term)) { + argIncorp = term; } else { - earlyAdjuncts.push(term); + const label = effectiveLabel(term); + if (label === 'DP') args.push(term); + else if (args.length) lateAdjuncts.push(term); + else earlyAdjuncts.push(term); } } + if (argIncorp !== null) args.push(argIncorp); // Now the first segment is the serial verb and everything after it is serial adjectives. let { ki, vP } = segmentToKivP(segments[0], args, newCoindex); diff --git a/src/toaq.kuna.ne b/src/toaq.kuna.ne index 539dbb9..7869832 100644 --- a/src/toaq.kuna.ne +++ b/src/toaq.kuna.ne @@ -149,10 +149,10 @@ AspP -> Aspcon vP {% makeBranch('AspP') %} AspPdet -> Aspcon vPdet {% makeBranch('AspP') %} # tua hao tî kúe jí súq râo níchaq -vP -> Serial AdjunctPcon:* (VocArgument:+ AdjunctPcon:*):? {% makevP %} +vP -> Serial Argincorp:? AdjunctPcon:* (VocArgument:+ AdjunctPcon:*):? {% makevP %} -# (sá) tua hao -vPdet -> Serialdet {% makevPdet %} +# (sá) leo hamla lô raı +vPdet -> Serialdet Argincorp:? {% makevPdet %} # ^ tı kúe AdjunctP -> Adjunct Serial Argument {% makeAdjunctPT %} @@ -168,10 +168,6 @@ Serialdet -> Serial {% id %} # (sá) ∅ Serialdet -> null {% makeEmptySerial() %} -# hao sâ ... -VPincorp -> V DPincorp {% makeBranch('VP') %} -# hao ꝡâ ... -VPincorp -> V CPincorp {% makeBranch('VP') %} # jî DPincorp -> %incorporated_pronoun Free:* {% makeLeaf('DP') %} # hụ̂ꝡa @@ -183,6 +179,8 @@ VPoiv -> Voiv DPcon {% makeBranch('VP') %} Argument -> DPcon {% id %} Argument -> CPargcon {% id %} +Argincorp -> DPincorp {% id %} +Argincorp -> CPincorp {% id %} DPcon -> DProi {% id %} DPcon -> DProi Conjunction DPcon {% makeConn %} @@ -213,7 +211,6 @@ AdjunctPcon -> AdjunctPfoc {% id %} AdjunctPcon -> AdjunctPfoc Conjunction AdjunctPcon {% makeConn %} AdjunctPfoc -> AdjunctP {% id %} AdjunctPfoc -> Focus AdjunctP {% makeBranch('FocusP') %} -Vlast -> VPincorp {% id %} Vlast -> VPoiv {% id %} Vlast -> Verb ConjunctionT1 Vlast {% makeConn %} Vlast -> Verb {% id %} diff --git a/src/tree/productions.ts b/src/tree/productions.ts index b138f38..abb6db6 100644 --- a/src/tree/productions.ts +++ b/src/tree/productions.ts @@ -166,14 +166,20 @@ export function makeSerial( } export function makevP( - [serial, adjpsL, rest]: [Tree, Tree[], [Tree[], Tree[]] | null], + [serial, argIncorp, adjpsL, rest]: [ + Tree, + Tree | null, + Tree[], + [Tree[], Tree[]] | null, + ], location: number, reject: Object, depth: 'main' | 'sub', ) { - rest ??= [[], []]; - let [args, adjpsR] = rest; - args = args.filter(x => x.label !== 'VocativeP'); + const argsL = argIncorp === null ? [] : [argIncorp]; + let [argsR, adjpsR] = rest ?? [[], []]; + argsR = argsR.filter(x => x.label !== 'VocativeP'); + const args = [...argsL, ...argsR]; const arity = (serial as any).arity; if (arity !== undefined) { @@ -191,20 +197,23 @@ export function makevP( // Disallow adjuncts that could have gone in a subclause: if ( adjpsR.length && - args.length && - endsInClauseBoundary(args[args.length - 1]) + argsR.length && + endsInClauseBoundary(argsR[argsR.length - 1]) ) { return reject; } + if (adjpsL.length && argIncorp !== null && endsInClauseBoundary(argIncorp)) { + return reject; + } return { label: '*𝘷P', - children: [serial, ...adjpsL, ...args, ...adjpsR], + children: [serial, ...argsL, ...adjpsL, ...argsR, ...adjpsR], }; } export function makevP_main( - args: [Tree, Tree[], [Tree[], Tree[]] | null], + args: [Tree, Tree | null, Tree[], [Tree[], Tree[]] | null], location: number, reject: Object, ) { @@ -212,21 +221,28 @@ export function makevP_main( } export function makevP_sub( - args: [Tree, Tree[], [Tree[], Tree[]] | null], + args: [Tree, Tree | null, Tree[], [Tree[], Tree[]] | null], location: number, reject: Object, ) { return makevP(args, location, reject, 'sub'); } -export function makevPdet([serial]: [Tree], location: number, reject: Object) { +export function makevPdet( + [serial, argIncorp]: [Tree, Tree | null], + location: number, + reject: Object, +) { const arity = (serial as any).arity; - if (arity === 0) { - return reject; - } + if (arity < (argIncorp === null ? 1 : 2)) return reject; + return { label: '*𝘷P', - children: [serial, { label: 'DP', word: { covert: true, value: 'PRO' } }], + children: [ + serial, + ...(argIncorp === null ? [] : [argIncorp]), + { label: 'DP', word: { covert: true, value: 'PRO' } }, + ], }; }