Skip to content
Permalink
 
 
Cannot retrieve contributors at this time
2863 lines (2565 sloc) 109 KB
import { Token } from '../token'
import { toUd } from './tagset'
import { UdMiRelation } from './syntagset'
import { mu } from '../../mu'
import { GraphNode, walkDepth, walkDepthNoSelf } from '../../graph'
import { MorphInterp } from '../morph_interp'
import { last, arrayed, wiith, wiithNonempty } from '../../lang'
import { uEq, uEqSome } from './utils'
import { startsWithCapital } from '../../string'
import { MorphAnalyzer } from '../morph_analyzer/morph_analyzer'
import { PREDICATES, isNumericModifier, isGoverning, EnhancedArrow, EnhancedNode } from './uk_grammar'
import { ValencyDict } from '../valency_dictionary/valency_dictionary'
import { SimpleGrouping } from '../../grouping'
import { compareAscending } from '../../algo'
import { MultitokenDescriptor } from '../utils'
import * as f from '../morph_features'
import * as g from './uk_grammar'
import { groupBy } from 'lodash'
//------------------------------------------------------------------------------
const SIMPLE_RULES: Array<[string, string, SentencePredicate2, string, SentencePredicate2]> = [
[`discourse`,
undefined,
undefined,
${g.DISCOURSE_DESTANATIONS.join('|')} чи fixed`,
(t, s, i) => g.DISCOURSE_DESTANATIONS.includes(toUd(t.interp).pos) || s[i + 1] && s[i + 1].rel === 'fixed'],
[`cop`,
`з недієслівного`,
(t, s, i) => !t.interp.isVerb() && !t.interp.isConverb() /* && !isActualParticiple(t, s, i) */,
${g.COPULA_LEMMAS.join(' ')}`,
t => g.COPULA_LEMMAS.includes(t.interp.lemma)],
[`expl`,
`з присудка`,
(t, s, i) => canBePredicateOld(t, s, i),
${g.EXPL_FORMS.join('|')} — іменники`,
t => g.EXPL_FORMS.includes(t.form.toLowerCase()) && t.interp.isNounish()],
[`flat:name`, `з іменника`, t => t.interp.isNounish(), ``, t => t],
]
//------------------------------------------------------------------------------
const TREED_SIMPLE_RULES: Array<[string | Array<string>, string, TreedSentencePredicateParent, string, TreedSentencePredicate]> = [
// cc не в сурядний is a separate rule
[`advcl:`,
`з дієслова/прикметника/прислівника`, t => g.isFeasibleAdvclHead(t),
`в присудок`, t => g.hasPredication(t)],
[`advcl:sp`,
`з присудка`,
t => canBePredicate(t),
`в називний/орудний іменник/прикметник`,
t => (t.node.interp.isNominative() || t.node.interp.isInstrumental())
&& (t.node.interp.isNoun() || t.node.interp.isAdjective())
],
[`amod`, `з іменника`, t => canActAsNoun(t), `в прикметник без предикації`, t => t.node.interp.isAdjective() && !g.hasPredication(t)],
[`nummod`, `з іменника`, t => canActAsNoun(t), `в незайменниковий числівник`, t => t.node.interp.isCardinalNumeral() && !t.node.interp.isPronominal()],
[`det:numgov`, `з іменника`, t => canActAsNoun(t), `в займенниковий числівник`, t => t.node.interp.isCardinalNumeral() && t.node.interp.isPronominal()],
[`advmod:`,
`див. "неочікуваний advmod"`, t => t,
`в прислівник`, t => t.node.interp.isAdverb() || g.isAdvmodParticle(t) || uEq(t.node.rel, 'fixed')
],
[`advmod:amtgov`,
`з родового`, t => t.node.interp.isGenitive(),
`в числівниковий прислівник`, t => t.node.interp.isAdverb() && g.QAUNTITATIVE_ADVERBS.includes(t.node.interp.lemma)
],
[`advmod:det`,
`з прикметника"`, t => t.node.interp.isAdjective(),
`в DET _такий_/_якийсь_`, t => toUd(t.node.interp).pos === 'DET'
&& ['такий', 'такенький', 'якийсь', 'який'].includes(t.node.interp.lemma)
],
[`det:`,
`з іменника`,
t => canActAsNounForObj(t) || t.node.hasTag('adjdet'),
`в нечислівниковий DET`,
t => toUd(t.node.interp).pos === 'DET' && !t.node.interp.isCardinalNumeral()],
[`case`,
`з іменника`,
t => canActAsNounForObj(t)
|| t.isRoot() //&& todo: more than 1 root
|| t.node.interp.isAdjective() && t.node.interp.isRelative() // todo: generalize
|| t.node.interp.isCardinalNumeral() // todo
|| t.node.interp.isInfinitive() && t.node.hasTag('inf_prep')
|| t.node.interp.isAdjective() && !uEq(t.node.rel, 'amod') // temp
|| t.node.interp.isAdverb() && ['тоді', 'нікуди'].includes(t.node.interp.lemma)
// && g.PREPS_HEADABLE_BY_NUMS.includes(
// t.children.find(x => x.node.rel === 'case').node.interp.lemma)
,
`в прийменник`,
t => t.node.interp.isPreposition() || t.children.some(t2 => uEq(t2.node.rel, 'fixed'))],
[`mark`,
``, t => t,
`в підрядний сполучник`,
t => t.node.interp.isSubordinative()
|| t.children.length && t.children.every(x => uEq(x.node.rel, 'fixed'))],
[`nsubj:`,
`з присудка`,
t => canBePredicate(t),
`в іменникове`,
t => canActAsNounForObj(t)
],
[`nsubj:x`,
`з чистого xcomp’а`,
t => t.node.rel === 'xcomp',
`в іменникове`,
t => canActAsNounForObj(t)
],
[`nsubj:sp`,
`з :sp’а`,
t => ['xcomp:sp', 'advcl:sp'].includes(t.node.rel),
`в іменникове`,
t => canActAsNounForObj(t)
],
[`csubj`,
`з присудка чи валентного прикметника`,
t => canBePredicate(t) || g.isValencyHavingAdjective(t.node),
`в присудок`, t => canBePredicate(t)],
[`obj`,
`з присудка чи валентного прикметника`,
t => t.node.interp.isVerbial() || g.isValencyHavingAdjective(t.node),
`в іменникове`,
t => canActAsNounForObj(t) /* || canTheoreticallyActAsNoun(t) */],
[`iobj`,
`з присудка чи валентного прикметника`,
t => canBePredicate(t) || g.isDativeValencyAdjective(t.node),
`в іменникове`,
t => canActAsNounForObj(t) /* || canTheoreticallyActAsNoun(t) */],
[`obl`,
`з дієслова / прикм. / присл. / недієсл. присудка`,
t => t.node.interp.isVerbial2()
|| t.node.interp.isAdverb()
|| (t.node.interp.isAdjective() && !t.node.interp.isPronominal())
|| g.isNonverbialPredicate(t)
,
`в іменник / DET`,
t => canActAsNounForObj(t)
// || t.node.interp.lemma === 'який' && (
// g.findRelativeClauseRoot(t) || t.parent.node.rel === 'flat:sibl'
// )
|| t.node.interp.isAdjective() && t.node.interp.isPronominal()
// && g.hasChild(t, 'flat:abs')
|| 1 // temp, todo
,
],
[`nmod`, `з іменника`, t => canActAsNoun(t) || g.isDenUDen(t) /* temp */,
`в іменник`,
t => canActAsNounForObj(t)
|| t.node.interp.lemma === 'який' && g.findRelativeClauseRoot(t)
|| g.isDenUDen(t.parent) // temp
|| canTheoreticallyActAsNoun(t)
],
[`aux`,
`з дієслівного`, t => t.node.interp.isVerbial2()
|| t.node.interp.isAdverb() && t.children.some(x => g.SUBJECTS.some(subj => uEq(x.node.rel, subj))),
${g.AUX_LEMMAS.join('|')}`,
t => g.AUX_LEMMAS.includes(t.node.interp.lemma)],
[`acl`, `з іменника`, t => canActAsNoun(t)
|| (!uEq(t.node.rel, 'det')
&& [
f.PronominalType.demonstrative,
f.PronominalType.general,
f.PronominalType.indefinite
].includes(t.node.interp.getFeature(f.PronominalType))),
`в присудок/інфінітив/:relless/:adv`, t =>
g.hasPredication(t)
|| t.node.interp.isInfinitive()
|| t.node.rel === 'acl:relless' // todo: comprehend
|| t.node.rel === 'acl:adv'
],
[`acl:adv`, `з іменника`, t => canActAsNoun(t)
|| (!uEq(t.node.rel, 'det')
&& [
f.PronominalType.demonstrative,
f.PronominalType.general,
f.PronominalType.indefinite,
].includes(t.node.interp.getFeature(f.PronominalType))),
`в одинокий (діє)прислівник`, t =>
(t.node.interp.isAdverb() || t.node.interp.isConverb())
&& !t.hasChildren()
],
[`punct`,
`зі слова`,
t => !t
|| !t.node.interp.isPunctuation()
|| t.node.hasTag('nestedpunct')
|| g.isPunctInParenthes(t),
// t => !t /*temp*/ /*|| isContentWord(t)*/ || t.tags.includes('nestedpunct'),
`в PUNCT`,
t => t.node.interp.isPunctuation()],
[`flat:foreign`,
`з :foreign`, t => t.node.interp.isForeign(),
`у :foreign`, t => t.node.interp.isForeign()],
[`xcomp:`,
`з присудка / валентного прикметника`,
t => canBePredicate(t) || g.isInfValencyAdjective(t.node),
`в інфінітив - присудок`,
t => (g.isInfinitiveAnalytically(t) || g.hasInfinitiveCop(t)) && canBePredicate(t)
],
[`ccomp`,
`з присудка / валентного прикметника`,
t => canBePredicate(t)
|| g.isInfinitiveAnalytically(t) && g.isInfValencyAdjective(t.node)
|| g.isValencyHavingAdjective(t.node),
`в присудок (тест: фінітний)`,
t => canBePredicate(t)
],
[`xcomp:sp`,
`з присудка`,
t => canBePredicate(t),
`в називний/орудний іменник/прикметник чи в „як щось“`,
t => ((t.node.interp.isNominative() || t.node.interp.isInstrumental())
&& (t.node.interp.isNoun() || t.node.interp.isAdjective()))
|| g.canBeAsSomethingForXcomp2(t)
|| t.node.isGraft
],
[`vocative:`,
`з присудка`,
t => canBePredicate(t),
`в кличний іменник`,
t => t.node.interp.isXForeign()
|| t.node.interp.isForeign()
|| canActAsNoun(t) && (t.node.interp.isVocative()
|| t.node.hasTag('nomvoc')
)
],
[`vocative:cl`,
`з присудка`,
t => canBePredicate(t),
`в присудок`,
t => canBePredicate(t),
],
[`appos:`, `з іменника`, t => canActAsNoun(t), `в іменник`, t => canActAsNoun(t)],
[`dislocated`, `~з присудка`, t => canBePredicate(t), ``, t => t],
]
//------------------------------------------------------------------------------
interface ReoprtIf2Arg {
n: GraphNode<Token> // tree node
t: Token // token
i: MorphInterp // interp
l: string // lemma
r: string // relation
c: Array<GraphNode<Token>> // children
p: GraphNode<Token>
pt: Token
pi: MorphInterp
pl: string
pr: string
}
//------------------------------------------------------------------------------
type SentencePredicate = (x: Token, i?: number) => any
type SentencePredicate2 = (t: Token, s: Array<Token>, i: number/*, node: GraphNode<Token>*/) => any
type TreedSentencePredicate = (t: GraphNode<Token>) => any
type EnhancedArrowPredicate = (arrow: EnhancedArrow) => any
type TreedSentencePredicateParent = (parent: GraphNode<Token>, child?: GraphNode<Token>) => any
type TreedSentencePredicate2 = (a: ReoprtIf2Arg) => any
////////////////////////////////////////////////////////////////////////////////
export interface Problem {
message: string
indexes: Array<number>
}
////////////////////////////////////////////////////////////////////////////////
export function validateSentenceSyntax(
nodes: Array<GraphNode<Token>>,
multitokens: Array<MultitokenDescriptor>,
enhancedOnlyNodes: Array<EnhancedNode>,
enhancedNodes: Array<EnhancedNode>,
analyzer: MorphAnalyzer,
corefClusterization: SimpleGrouping<Token>,
valencyDict?: ValencyDict,
) {
let problems = new Array<Problem>()
let tokens = nodes.map(x => x.node)
let roots = nodes.filter(x => x.isRoot())
let basicRoots = roots.filter(x => !x.node.isElided())
let sentenceHasOneRoot = roots.length === 1
let node2index = new Map(nodes.map((x, i) => [x, i] as [GraphNode<Token>, number]))
const oldReportIf = (message: string, fn: SentencePredicate) => {
problems.push(...mu(tokens).findAllIndexes(fn).map(index => ({ message, indexes: [index] })))
}
const reportIf = (message: string, fn: TreedSentencePredicate) => {
problems.push(...mu(nodes).findAllIndexes(fn).map(index => ({ message, indexes: [index] })))
}
const ereportIf = (message: string, fn: EnhancedArrowPredicate) => {
problems.push(...mu(enhancedNodes)
.findAllIndexes(enode => enode.incomingArrows.some(fn))
.map(index => ({ message, indexes: [index] }))
)
}
const reportIf2 = (message: string, fn: TreedSentencePredicate2) => {
problems.push(...mu(nodes).map(x => ({
n: x,
t: x.node,
r: x.node.rel,
i: x.node.interp,
l: x.node.interp.lemma,
c: x.children,
p: x.parent,
pi: x.parent && x.parent.node.interp,
pt: x.parent && x.parent.node,
pl: x.parent && x.parent.node.interp.lemma,
pr: x.parent && x.parent.node.rel
})).findAllIndexes(fn).map(index => ({ message, indexes: [index] })))
}
const xreportIf = (message: string, fn: TreedSentencePredicate) => undefined
const xreportIf2 = (message: string, fn: TreedSentencePredicate2) => undefined
const xoldReportIf = (message: string, fn: SentencePredicate) => undefined
const tmpxreportIf = (message: string, fn: TreedSentencePredicate) => undefined
const tmpxreportIf2 = (message: string, fn: TreedSentencePredicate2) => undefined
const hasDependantWhich = (i: number, fn: SentencePredicate) =>
tokens.some((xx, ii) => xx.headIndex === i && fn(xx, ii))
// ~~~~~~~ rules ~~~~~~~~
// invalid roots
if (sentenceHasOneRoot && !roots[0].node.hasTag('ok-root')) {
let udPos = toUd(roots[0].node.interp).pos
if (g.POSES_NEVER_ROOT.includes(udPos)) {
problems.push({ indexes: [node2index.get(roots[0])], message: `${udPos} як корінь` })
}
}
if (0) {
let interesting = tokens.filter(x =>
(['один', 'другий'].includes(x.interp.lemma))
&& x.rel !== 'flat:abs'
)
if (interesting.length > 1) {
problems.push({ indexes: interesting.map(x => x.index), message: `flat:abs?` })
}
}
// invalid AUX
reportIf(`AUX без cop/aux`, PREDICATES.isAuxWithNoCopAux)
// simple rules
for (let [rel, messageFrom, predicateFrom, messageTo, predicateTo] of SIMPLE_RULES) {
let relMatcher = rel.endsWith(':')
? (x: string) => x === rel.slice(0, -1)
: (x: string) => x === rel || x && x.startsWith(`${rel}:`)
let relName = rel.endsWith(':') ? `${rel.slice(0, -1)}` : rel
if (messageFrom && predicateFrom) {
oldReportIf(`${relName} не ${messageFrom}`,
t => relMatcher(t.rel)
&& !tokens[t.headIndex].interp0().isXForeign()
&& !predicateFrom(tokens[t.headIndex], tokens, t.headIndex))
}
if (messageTo && predicateTo) {
oldReportIf(`${relName} не ${messageTo}`,
(t, i) => relMatcher(t.rel)
&& !t.interp0().isXForeign()
&& !predicateTo(t, tokens, i))
}
}
// treed simple rules
for (let [rels, messageFrom, predicateFrom, messageTo, predicateTo] of TREED_SIMPLE_RULES) {
rels = arrayed(rels)
for (let rel of rels) {
let relMatcher = rel[0].endsWith(':')
? (x: string) => x === rel.slice(0, -1)
: (x: string) => x === rel || x && x.startsWith(`${rel}:`)
let relName = rel.endsWith(':') ? `${rel.slice(0, -1)}` : rel
if (messageFrom && predicateFrom) {
reportIf(`${relName} не ${messageFrom}`,
t => relMatcher(t.node.rel)
&& !predicateFrom(t.parent))
}
if (messageTo && predicateTo) {
reportIf(`${relName} не ${messageTo}`,
t => relMatcher(t.node.rel)
&& !predicateTo(t))
}
}
}
// ~~~~~~~~~~~~~~~~~~~~~~ TESTS ~~~~~~~~~~~~~~~~~~~~~~
xreportIf2(`_тест: числівники`,
({ t, i }) => t.index < tokens.length - 1
&& i.isCardinalNumerish()
&& (t.index === 0
|| !tokens[t.index - 1].interp.isCardinalNumerish())
&& (tokens[t.index + 1].interp.isCardinalNumerish()
|| t.interp.isNounNumeral())
)
xreportIf2(`_тест: складений порядковий`,
({ t, i }) => t.index > 0
&& i.isOrdinalNumeral()
&& tokens[t.index - 1].interp.isCardinalNumerish()
// && (t.indexInSentence === 0
// || !sentence[t.indexInSentence - 1].interp.isCardinalNumerish())
// && (sentence[t.indexInSentence + 1].interp.isCardinalNumerish()
// || t.interp.isNounNumeral())
)
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
reportIf(`декілька підметів (${g.SUBJECTS.join('|')})`,
t => t.children.filter(x => uEqSome(x.node.rel, g.SUBJECTS)
&& !x.node.isElided()).length > 1
)
reportIf(`декілька прямих додатків`,
t => t.children.filter(x => !x.node.isElided()
&& uEqSome(x.node.rel, g.CORE_COMPLEMENTS)
// || uEq(x.node.rel, 'xcomp') && x.node.rel !== 'xcomp:sp'
).length > 1
)
reportIf(`декілька непрямих додатків`,
t => t.children.filter(x => uEq(x.node.rel, 'iobj')).length > 1
)
reportIf(`декілька числівників`,
t => t.children.filter(x => isNumericModifier(x.node.rel)).length > 1
)
reportIf(`декілька gov-реляцій`,
t => t.children.filter(x => isGoverning(x.node.rel)).length > 1
)
reportIf(`декілька cc`,
t => !t.node.hasTag('mult-cc') && t.children.filter(x => uEq(x.node.rel, 'cc')).length > 1
)
reportIf(`декілька mark’ів`,
t => t.children.filter(x => uEq(x.node.rel, 'mark')).length > 1
)
reportIf(`декілька xcomp’ів`,
t => t.children.filter(x => uEq(x.node.rel, 'xcomp')
&& x.node.rel !== 'xcomp:sp').length > 1
)
reportIf(`декілька xcomp:sp`,
t => t.children.filter(x => x.node.rel === 'xcomp:sp').length > 1
)
reportIf(`декілька cop’ів`,
t => t.children.filter(x => uEq(x.node.rel, 'cop')).length > 1
)
reportIf(`декілька прийменників`,
t => !t.node.isGraft
&& t.children.filter(x => uEq(x.node.rel, 'case')).length > 1
)
oldReportIf(`токен позначено error’ом`, t => t.hasTag('error'))
reportIf('більше однієї стрілки в токен',
t => mu(t.node.deps)
.filter(x => !uEq(x.relation, 'punct')
&& !g.HELPER_RELATIONS.has(x.relation)
&& !tokens[x.headIndex].isElided() // todo
).count() > 1)
g.RIGHT_POINTED_RELATIONS.forEach(rel => reportIf2(`${rel} ліворуч`,
({ r, t }) => uEq(r, rel) && t.headIndex > t.index))
g.LEFT_POINTED_RELATIONS.forEach(rel => reportIf2(`${rel} праворуч`,
({ r, t }) => uEq(r, rel) && t.headIndex < t.index))
oldReportIf(`case праворуч`, (t, i) => uEq(t.rel, 'case')
&& t.headIndex < i
&& !(tokens[i + 1] && tokens[i + 1].interp.isNumeric())
)
oldReportIf('незнана реляція',
t => t.rel && !g.ALLOWED_RELATIONS.includes(t.rel as UdMiRelation))
reportIf(`cc не в сурядний`,
t => uEq(t.node.rel, 'cc')
&& !t.node.interp.isCoordinating()
&& !g.hasChild(t, 'fixed')
)
reportIf(`punct в двокрапку зліва`,
t => t.node.index !== tokens.length - 1 // not last in sentence
&& t.node.form === ':'
&& t.node.interp.isPunctuation()
&& t.node.headIndex < t.node.index
&& !(t.parent
&& (uEqSome(t.parent.node.rel, ['discourse'])
|| t.parent.node.rel === 'parataxis:discourse')
)
)
xoldReportIf(`у залежника ccomp немає підмета`,
(t, i) => t.rel === 'ccomp'
&& !tokens.some(xx => g.SUBJECTS.includes(xx.rel) && xx.headIndex === i))
reportIf(`у залежника xcomp є підмет`,
t => uEq(t.node.rel, 'xcomp')
&& !t.node.isGraft
&& t.children.some(x => uEqSome(x.node.rel, g.SUBJECTS))
)
oldReportIf('не discourse до частки',
t => t.rel
&& !['б', 'би', 'не'].includes(t.form.toLowerCase())
&& t.interp.isParticle()
&& !['discourse', 'fixed'])
reportIf('не aux у б(и)',
t => !t.isRoot()
&& g.CONDITIONAL_AUX_LEMMAS.includes(t.node.form.toLowerCase())
&& t.node.interp.isParticle()
&& !uEqSome(t.node.rel, [/* 'fixed', */ 'aux', 'goeswith'])
)
reportIf('не advmod в не',
t => t.node.interp.isParticle()
&& !g.hasChild(t, 'fixed')
&& ['не', /*'ні', 'лише'*/].includes(t.node.form.toLowerCase())
&& !['advmod', undefined].includes(t.node.rel))
oldReportIf('не cc в сурядий на початку речення',
(t, i) => t.rel && i === 0 && t.interp.isCoordinating() && !['cc'].includes(t.rel))
for (let leafrel of g.LEAF_RELATIONS) {
reportIf(`${leafrel} має залежників`,
t => uEq(t.node.rel, leafrel)
&& !t.children.every(x => x.node.interp.isPunctuation())
)
}
reportIf(`сполучник виділено розділовим знаком`,
t => t.node.interp.isConjunction()
&& t.children.some(ch => ch.node.rel === 'punct')
&& !t.isRoot()
&& !uEq(t.node.rel, 'conj')
&& !t.node.hasTag('commed_conj')
)
reportIf(`підмет не в називному`,
t => uEq(t.node.rel, 'nsubj')
&& !t.node.isGraft
&& !t.node.hasTag('ok-nonnom-subj')
&& ![f.Case.nominative, undefined].includes(g.thisOrGovernedCase(t))
&& !t.node.interp.isForeign()
&& !g.isQuantificationalNsubj(t)
&& !g.isQuantitativeAdverbModified(t)
&& !(t.children.some(x => g.isNumericModifier(x.node.rel)
&& x.children.some(xx => xx.node.interp.isPreposition()
&& ['близько', 'до', 'понад'].includes(xx.node.interp.lemma)
))
)
)
reportIf(`день у день`, t => g.isDenUDen(t))
tmpxreportIf(`займенник :&noun`, t =>
t.node.interp.isAdjectiveAsNoun()
&& t.node.interp.isPronominal()
)
reportIf(`додаток в називному`,
t => uEqSome(t.node.rel, ['obj', 'iobj', 'obl'])
&& g.thisOrGovernedCase(t) === f.Case.nominative
&& !t.node.interp.isXForeign()
&& !t.node.isGraft
&& t.parent.node.interp.isReversive()
&& !t.children.some(x => x.node.rel === 'flat:abs')
&& !(uEqSome(t.node.rel, ['obl']) && ['сам'].includes(t.node.interp.lemma))
)
reportIf(`місцевий без прийменника`,
t => {
if (!t.node.rel
|| uEq(t.node.rel, 'fixed')
|| !t.node.interp.isLocative()
|| !canActAsNoun(t)
) {
return
}
let p = t
while (p && !hasChildrenOfUrel(p, 'case')) {
if (!uEqSome(p.node.rel, ['appos', 'conj', 'flat'])) {
return true
} else {
p = p.parent
}
}
}
)
reportIf(`підрядне означальне відкриває що-іменник`,
t => uEq(t.node.rel, 'acl')
&& t.children.some(x => x.node.form.toLowerCase() === 'що'
&& uEqSome(x.node.rel, ['nsubj'])
)
)
reportIf(`cc без conj`,
t => uEq(t.node.rel, 'cc')
&& !t.parent.isRoot()
&& !uEqSome(t.parent.node.rel, ['conj', 'flat:title', 'flat:repeat', 'parataxis:newsent'])
&& !t.parent.children.some(x => uEq(x.node.rel, 'conj'))
)
// todo
xreportIf(`підрядне без сполучника`,
t => uEqSome(t.node.rel, g.SUBORDINATE_CLAUSES)
&& !uEq(t.node.rel, 'xcomp')
// && !t.parent.children[0].node.interp.isConsequential()
&& !t.children.some(x => uEq(x.node.rel, 'mark'))
&& !g.hasOwnRelative(t)
// && !t.children.some(x => x.node.interp.isRelative())
// && !g.isInfinitive(t)
&& !(uEq(t.node.rel, 'acl') && t.node.interp.isParticiple())
&& !(uEq(t.node.rel, 'advcl') && t.node.interp.isConverb())
&& !t.node.rel.endsWith(':sp')
)
xreportIf(`зворотне має два додатки`,
t => t.node.interp.isReversive()
&& t.children.filter(x => uEqSome(x.node.rel, ['obj', 'iobj', 'ccomp'])
&& !x.node.isElided()).length > 1
)
reportIf(`неузгодження відмінків прийменника`, // todo: додати conj
t => uEq(t.node.rel, 'case')
&& (t.node.interp.features.requiredCase as number) !== g.thisOrGovernedCase(t.parent)
&& !t.parent.node.interp.isXForeign()
&& !t.parent.node.interp.isForeign() // todo
&& !t.parent.node.isGraft
// &&!t.children.some(x => uEq(x.node.rel, 'case')
// && x.node.interp.getFeature(f.RequiredCase)===
// )
&& !g.hasChild(t.parent, 'fixed')
&& !(t.node.interp.lemma === 'замість'
&& t.parent.node.interp.isVerb()
&& t.parent.node.interp.isInfinitive()
)
&& !(t.parent.node.interp.isAdverb()
&& ['нікуди'].includes(t.parent.node.interp.lemma)
)
)
reportIf(`неособове має підмет`,
t => (t.node.interp.isImpersonal() || g.isInfinitive(t))
&& t.children.some(x => uEqSome(x.node.rel, g.SUBJECTS))
)
reportIf(`знахідний без прийменника від недієслова`,
t => canActAsNounForObj(t)
&& !t.isRoot()
&& t.node.interp.isAccusative()
&& !t.parent.node.interp.isAccusative()
&& !t.parent.node.isGraft
&& !t.children.some(x => x.node.interp.isPreposition())
&& !t.parent.node.interp.isVerbial2()
&& !uEqSome(t.node.rel, ['conj', 'flat', 'appos', 'orphan', 'fixed']) // todo
// && !thisOrTravelUp(t, tt =>
// tt.parent.node.interp.isVerbial()
// && tt.children.some(x => x.node.interp.isPreposition())
// )
// && !t.parent.node.interp.isVerbial()
)
if (roots.length === 1) {
xreportIf(`інфінітив — корінь`,
t => t.isRoot()
&& g.isInfinitive(t)
)
}
reportIf2(`aux-інфінітив з дієслова-інфінітива`,
({ r, i, pi }) => uEq(r, 'aux')
&& i.isInfinitive()
&& pi.isInfinitive()
)
xreportIf(`неузгодження в часі`,
t => uEq(t.node.rel, 'aux')
&& t.node.interp.isVerb()
&& (t.node.interp.hasFeature(f.Tense) || t.parent.node.interp.hasFeature(f.Tense))
&& !t.parent.node.interp.isInfinitive()
&& t.node.interp.getFeature(f.Tense) !== t.parent.node.interp.getFeature(f.Tense)
&& !t.parent.node.interp.isImpersonal()
)
xreportIf(`ні допоміжне, ані повнозначне дієслово не має часу`,
t => uEq(t.node.rel, 'aux')
&& t.node.interp.isVerb()
&& (t.node.interp.isInfinitive() || !t.node.interp.hasFeature(f.Tense))
&& (t.parent.node.interp.isInfinitive() || !t.parent.node.interp.getFeature(f.Tense))
)
reportIf(`неузгодження підмет — прикметник-присудок`,
t => uEq(t.node.rel, 'nsubj')
&& t.parent.node.interp.isAdjective()
&& !t.parent.node.isPromoted
&& !g.nounAdjectiveAgreed(t, t.parent)
&& !(t.parent.node.interp.isInstrumental() && g.hasCopula(t.parent))
)
xreportIf(`неочікуваний відмінок іменника-присудка`,
t => uEq(t.node.rel, 'nsubj')
&& t.parent.node.interp.isNounish()
// && !g.nounNounAgreed(t.node.interp, t.parent.node.interp)
&& !t.parent.node.interp.isNominative()
&& !g.hasChild(t.parent, 'case')
&& !(t.parent.node.interp.isInstrumental() && g.hasCopula(t.parent))
// && !['це'].some(x => t.node.interp.lemma === x)
)
xreportIf(`неузгодження прикладки`, // todo: mark explicitly in tb
t => uEq(t.node.rel, 'appos')
&& t.node.interp.isNounish()
&& t.parent.node.interp.isNounish()
&& !t.node.interp.isXForeign()
&& g.thisOrGovernedCase(t) !== g.thisOrGovernedCase(t.parent)
// && !g.nounNounAgreed(t.node.interp, t.parent.node.interp)
// && !t.node.interp.equalsByFeatures(t.parent.node.interp, [f.Case/* , f.MorphNumber */])
// && ![[t, t.parent], [t.parent, t]].some(([a, b]) =>
// g.hasChild(a, 'conj')
// && a.node.interp.isSingular()
// && b.node.interp.isPlural()
// )
&& !g.hasChild(t, 'mark')
&& !t.children.some(x => x.node.interp.lemma === '(' && x.node.interp.isPunctuation())
// && !(t.children.length
// && t.children[0].node.interp.lemma === '('
// && !t.children[0].node.interp.isPunctuation())
// (
)
reportIf(`неузгодження відмінків однорідних іменників`,
t => uEq(t.node.rel, 'conj')
&& !t.node.interp.equalsByFeatures(t.parent.node.interp, [f.Case/* , f.MorphNumber */])
&& t.node.rel !== 'conj:parataxis'
&& !uEqSome(t.parent.node.rel, ['obl'])
&& t.node.interp.isNounish()
&& t.parent.node.interp.isNounish()
&& !t.node.interp.isXForeign()
&& g.thisOrGovernedCase(t) !== g.thisOrGovernedCase(t.parent)
&& !g.isQuantitativeAdverbModified(t)
// && !g.isQuantitativeAdverbModified(t.parent)
&& !(uEqSome(t.parent.node.rel, ['nmod'])
&& g.hasChild(t, 'case'))
)
reportIf(`неузгодження однорідних прикметників`,
t => uEq(t.node.rel, 'conj')
&& t.node.rel !== 'conj:parataxis'
// && !uEqSome(t.parent.node.rel, ['obl'])
&& t.node.interp.isAdjective()
&& t.parent.node.interp.isAdjective()
&& !t.parent.node.interp.equalsByFeatures(t.node.interp, [f.Case/* , f.MorphNumber */])
)
xreportIf(`неузгодження однорідних дієслів`,
t => uEq(t.node.rel, 'conj')
&& t.node.rel !== 'conj:parataxis'
// && !uEqSome(t.parent.node.rel, ['obl'])
&& t.node.interp.isVerbial()
&& t.parent.node.interp.isVerbial()
&& !t.parent.node.interp.equalsByFeatures(t.node.interp, [
f.Tense, f.Person, f.MorphNumber])
&& !g.hasChild(t, 'nsubj')
)
reportIf(`неузгодження підмет — присудок-дієслово`, t =>
uEq(t.node.rel, 'nsubj')
&& t.parent.node.interp.isVerb()
&& !g.nsubjAgreesWithPredicate(t, t.parent)
)
xreportIf(`неузгодження підмет-присудок`,
t => {
if (t.isRoot()
|| t.node.hasTag('graft')
|| !uEq(t.node.rel, 'nsubj')
|| !t.parent.node.interp.isVerbial2()
|| t.parent.node.interp.isImpersonal()
|| t.node.interp.isXForeign()
) {
return false
}
let interp = t.node.interp
let subjFeats = t.node.interp.features
let verbInterp = t.parent.node.interp
if (verbInterp.isInfinitive()) {
let aux = t.parent.children.find(x => uEqSome(x.node.rel, ['aux']))
if (aux) {
verbInterp = aux.node.interp
} else {
}
}
if (verbInterp.hasPerson()
// todo: losen
&& !(interp.isPronominal() && !interp.isPersonal() && !interp.hasFeature(f.Person))
) {
let subjPerson = subjFeats.person || f.Person.third
if (subjPerson !== verbInterp.features.person) {
return true
}
}
if (verbInterp.hasGender()
&& !(interp.isForeign() && !interp.hasGender())
&& !t.node.hasTag('gendisagr')
&& !interp.isPlural()
// && !(t.node.interp.isPronoun()
// && subjFeats.person === Person.first || subjFeats.person === Person.second)
&& !(interp.isPronominal() && g.GENDERLESS_PRONOUNS.includes(interp.lemma))
&& verbInterp.getFeature(f.Gender) !== interp.getFeature(f.Gender)
&& !g.isNegativeExistentialPseudosubject(t)
&& (!interp.isNoun() && interp.lemma === 'це')
) {
// return true
}
if (!t.children.some(x => uEq(x.node.rel, 'conj'))
&& !g.hasNmodConj(t)
&& !t.node.hasTag('numdisagr')
&& !(t.node.interp.isPronominal() && !t.node.interp.hasNumber())
&& verbInterp.getFeature(f.MorphNumber) !== interp.getFeature(f.MorphNumber)
&& !(g.isNumeralModified(t)/* && interp.isGenitive() */)
&& !verbInterp.isInstant()
) {
return true
}
}
)
reportIf(`неузгодження іменник-прикметник`,
t => {
if (t.isRoot()) {
return
}
let interp = t.node.interp
let nounInterp = t.parent.node.interp
let ret = uEqSome(t.node.rel, ['amod', 'det'])
|| uEqSome(t.node.rel, ['acl']) && nounInterp.isParticiple()
ret = ret
&& interp.isAdjective()
&& !interp.isMock()
&& !t.parent.node.isGraft
&& !nounInterp.isXForeign()
&& (
(interp.hasGender()
&& interp.features.gender !== nounInterp.features.gender
// && !t.parent.node.isPromoted
&& !g.GENDERLESS_PRONOUNS.includes(nounInterp.lemma)
&& !(interp.isOrdinalNumeral() && nounInterp.lemma === 'рр.')
)
|| (interp.features.case !== nounInterp.features.case
&& interp.features.case !== g.thisOrGovernedCase(t.parent)
)
)
// виділяють три основних елементи
&& !(interp.isGenitive()
&& [f.Case.accusative, f.Case.nominative].includes(t.parent.node.interp.getFeature(f.Case))
&& t.parent.children.some(x => x.node.rel === 'nummod')
)
return ret
}
)
reportIf2(`неузгодження родів іменника-числівника`,
({ r, i, pi }) => uEq(r, 'nummod')
&& i.hasFeature(f.Gender)
&& i.getFeature(f.Gender) !== pi.getFeature(f.Gender)
&& !pi.isXForeign()
)
reportIf(`неузгодження істотовості`,
t => uEqSome(t.node.rel, ['amod', 'det', 'nummod'])
&& t.node.interp.hasFeature(f.RequiredAnimacy)
&& t.parent.node.interp.hasFeature(f.Animacy)
&& t.node.interp.features.requiredAnimacy as number !== t.parent.node.interp.features.animacy
&& t.node.interp.features.requiredAnimacy as number !== t.parent.node.interp.features.grammaticalAnimacy
// todo: or ranim for promoted adj
)
reportIf(`неузгодження flat:name`,
t => t.node.rel === 'flat:name'
&& !g.nounNounAgreed(t.parent.node.interp, t.node.interp)
)
reportIf(`неузгодження flat:title`,
t => t.node.rel === 'flat:title'
// && !g.nounNounAgreed(t.parent.node.interp, t.node.interp)
&& !t.parent.node.interp.equalsByFeatures(t.node.interp, [/* f.MorphNumber, */ /* f.Gender, */ f.Case])
&& g.thisOrGovernedCase(t) !== f.Case.nominative
&& !t.node.interp.isForeign()
&& !t.node.interp.isSymbol()
&& !t.node.isGraft
&& !isEncolsedInQuotes(t)
)
xreportIf(`неузгодження однорідних`,
t => {
if (!uEq(t.node.rel, 'conj')
|| t.node.rel === 'conj:parataxis'
) {
return
}
if (t.node.interp.isNounish()
&& !t.parent.node.interp.equalsByFeatures(t.node.interp, [f.Case])
) {
// return true
}
if (t.node.interp.isVerb()
&& !t.parent.node.interp.equalsByFeatures(t.node.interp, [f.VerbAuxilarity,
f.VerbType, f.Gender])
) {
// return true
}
if (t.node.interp.isAdjective()
&& !t.parent.node.interp.equalsByFeatures(t.node.interp, [
f.Case, f.Gender])
) {
return true
}
}
)
reportIf(`gov-реляція між однаковими відмінками`,
t => isGoverning(t.node.rel)
&& t.node.interp.features.case === t.parent.node.interp.features.case
)
reportIf(`не gov-реляція між різними відмінками`,
t => !isGoverning(t.node.rel)
&& ['nummod', 'det:nummod'].some(rel => uEq(t.node.rel, rel))
&& !t.parent.node.interp.isXForeign()
&& t.node.interp.features.case !== t.parent.node.interp.features.case
&& !g.canBeDecimalFraction(t) // todo
)
reportIf(`керівний числівник не в називному/знахідному`,
t => isGoverning(t.node.rel)
&& t.node.interp.features.case !== t.parent.node.interp.features.case
&& ![f.Case.nominative, f.Case.accusative].includes(t.node.interp.features.case)
)
reportIf(`множинний числівник керує одниною`,
t => uEqSome(t.node.rel, ['nummod', 'det:nummod', 'det:numgov'])
&& !t.parent.node.interp.isPlural()
&& !t.node.interp.lemma.endsWith('1')
&& !['один', 'півтора', 'пів'].includes(t.node.interp.lemma)
&& !g.canBeDecimalFraction(t)
&& !t.parent.node.interp.isXForeign()
)
reportIf(`кероване числівником не в родовому`,
t => {
let governer = t.children.find(x => isGoverning(x.node.rel))
if (!governer) {
return
}
return t.node.interp.features.case !== governer.node.interp.features.case
&& !t.node.interp.isGenitive()
}
)
reportIf(`mark не з кореня підрядного`,
t => uEq(t.node.rel, 'mark')
// && !t.parent.isRoot()
&& (sentenceHasOneRoot && !t.parent.node.rel
|| t.parent.node.rel
&& !uEqSome(t.parent.node.rel, g.MARK_ROOT_RELS)
&& !(uEq(t.parent.node.rel, 'conj')
&& g.SUBORDINATE_CLAUSES.some(x => uEq(t.parent.parent.node.rel, x))
)
)
&& !(t.parent.isRoot() && t.node.index === nodes.findIndex(x =>
!x.node.interp.isPunctuation() && !mu(x.walkThisAndUp0()).some(
xx => uEqSome(xx.node.rel, ['discourse'])))
)
// використання як енергетичної сировини
&& !(t.parent.node.rel === 'nmod:xcompsp'
&& ['як'].includes(t.node.interp.lemma)
)
)
reportIf(`parataxis під’єднано сполучником`,
t => uEq(t.node.rel, 'parataxis')
&& t.node.rel !== 'parataxis:discourse'
&& t.node.rel !== 'parataxis:thatis'
&& t.node.rel !== 'parataxis:rel'
&& t.node.rel !== 'parataxis:newsent'
&& t.children.some(x => uEqSome(x.node.rel, ['cc', 'mark']))
&& !t.children.some(x => x.node.interp.isQuote() && x.node.interp.isOpening())
)
reportIf(`parataxis має відносний`,
t => uEq(t.node.rel, 'parataxis')
&& t.node.rel !== 'parataxis:rel'
&& t.node.rel !== 'parataxis:discourse'
&& g.hasOwnRelative(t)
)
reportIf(`parataxis:rel не має відносного`,
t => t.node.rel === 'parataxis:rel'
&& !g.hasOwnRelative(t)
)
reportIf(`xcomp зі сполучником`,
t => uEq(t.node.rel, 'xcomp')
// && t.node.rel !== 'parataxis:discourse'
&& t.children.some(x => uEqSome(x.node.rel, [/* 'cc', */'mark']))
&& !g.canBeAsSomethingForXcomp2(t)
&& !t.node.hasTag('xcomp_mark')
)
reportIf(`flat:name не для імені`,
t => (t.node.rel === 'flat:name' || t.children.some(x => x.node.rel === 'flat:name'))
&& !t.node.interp.isName()
)
reportIf(`підрядне речення з _то_`,
t => t.node.interp.lemma === 'то'
&& t.parent
&& uEqSome(t.parent.node.rel, g.SUBORDINATE_CLAUSES)
&& !t.node.interp.isNoun()
// todo: fasten
&& !t.parent.children.some(x => uEqSome(x.node.rel, ['advcl']/* g.SUBORDINATE_CLAUSES */))
)
reportIf(`заперечення під’єднане не до cop/aux`,
t => {
if (!uEq(t.node.rel, 'advmod')
|| !t.node.interp.isNegative()
|| t.parent.node.interp.isAuxillary()) {
return
}
let aux = t.parent.children.find(x => x.node.interp.isAuxillary())
if (!aux) {
return
}
return node2index.get(t) < node2index.get(aux) && node2index.get(aux) < node2index.get(t.parent)
}
)
reportIf(`parataxis:discourse в одне слово-недієслово`,
t => t.node.rel === 'parataxis:discourse'
&& !t.children.length
&& !t.node.interp.isVerb()
)
xreportIf(`discourse у фразу`,
t => uEq(t.node.rel, 'discourse')
&& t.children.filter(x => !uEqSome(x.node.rel, ['fixed', 'punct'])).length
)
reportIf(`кількісний прислівник модифікує множину`,
t => t.node.rel === 'advmod:amtgov'
&& t.parent.node.interp.isPlural()
&& !t.parent.node.interp.isNoSingular()
&& !t.parent.node.interp.hasNonpositiveDegree()
&& !['чимало', 'трохи'].includes(t.node.interp.lemma)
)
if (basicRoots.length === 1) {
xreportIf(`non-projective`, g.isNonprojective)
}
// continuity/projectivity
for (let token of nodes) {
if (uEqSome(token.node.rel, g.CONTINUOUS_REL)) {
let rootFromHere = token.root()
let indexes = mu(walkDepth(token))
.map(x => node2index.get(x))
.toArray()
.sort(compareAscending)
let holes = findHoles(indexes)
.filter(i => nodes[i].root() === rootFromHere)
.map(x => nodes[x])
.filter(x => !mu(x.walkThisAndUp0()).some(xx => xx.node.hasTag('legal_alien'))
&& !x.node.isElided()
)
.map(x => node2index.get(x))
if (holes.length) {
if (token.parent.node.interp.isAdverb() && token.node.interp.isInfinitive()) {
continue
}
// console.error(sentence.map(x => x.form).join(' '))
// console.error(indexes)
// console.error(holes)
continue
problems.push({ indexes: [...holes], message: `чужі токени всередині ${token.node.rel}` })
}
}
}
{
let lastToken = last(nodes)
if (lastToken.node.rel
&& !/[!?]|\.{3}|…/.test(lastToken.node.form) // todo: add stricter condition
&& lastToken.node.interp.isPunctuation()
&& !lastToken.parents.some(x => x.isRoot())
&& !lastToken.parents.some(x => x.node.interp.isAbbreviation()
|| uEq(x.node.rel, 'parataxis')
|| x.node.rel.endsWith(':parataxis')
)
&& !lastToken.node.interp.isQuote()
&& !(lastToken.node.interp.isForeign() && lastToken.parent.node.form.length === 1)
&& !lastToken.parent.node.isGraft
&& !(lastToken.node.interp.isClosing()
&& lastToken.parent.children.some(x => x.node.interp.isOpening())
)
&& !(lastToken.node.interp.isQuote()
&& mu(lastToken.parent.children)
.filter(x => x.node.interp.isQuote())
.longerThan(1)
)
) {
problems.push({
indexes: [nodes.length - 1],
message: `останній розділовий не з кореня`,
})
}
}
{
// modal ADVs, espacially with copula
// disableable
let interests = nodes.filter(t =>
!t.isRoot()
&& uEq(t.node.rel, 'advmod')
&& t.node.interp.isAdverb()
&& g.isInfinitive(t.parent)
// && t.parent.isRoot()
// || !['acl', 'xcomp', 'c'].some(x => uEq(t.parent.node.rel, x)))
&& g.SOME_MODAL_ADVS.some(form => t.node.interp.lemma === form)
)
if (0 && interests.length) {
problems.push({
indexes: interests.map(x => node2index.get(x)),
message: `модальний прислівник не підкорінь`,
})
}
}
// todo
xreportIf(`залежники голови складеного присудка`,
t => t.children.some(x => x.node.interp.isInfinitive()
&& uEqSome(x.node.rel, ['xcomp', 'csubj', 'ccomp'])
)
&& t.children.some(x => uEqSome(x.node.rel, ['obl'])) // туду
)
reportIf(`cop без підмета`,
t => uEq(t.node.rel, 'cop')
&& !t.parent.children.some(x => uEqSome(x.node.rel, g.SUBJECTS))
&& !t.parent.node.interp.isAdverb()
&& !t.parent.node.interp.isAdjective()
&& !t.parent.node.interp.isInstrumental()
&& !uEq(t.parent.node.rel, 'xcomp')
)
reportIf(`conj без сполучника чи коми`,
t => g.isConjWithoutCcOrPunct(t)
&& t.node.rel !== 'conj:svc'
)
reportIf(`conj без розділового чи сполучника (може conj:svc?)`,
t => g.isConjWithoutCcOrPunct(t)
&& t.node.rel !== 'conj:svc'
&& [f.VerbType.indicative, f.VerbType.infinitive, f.VerbType.imperative]
.includes(t.node.interp.getFeature(f.VerbType))
)
reportIf(`advcl без сполучування (може advcl:svc?)`,
t => uEq(t.node.rel, 'advcl')
&& t.node.rel !== 'advcl:sp'
&& t.node.rel !== 'advcl:svc'
&& [f.VerbType.indicative, f.VerbType.infinitive, f.VerbType.imperative, f.VerbType]
.includes(t.node.interp.getFeature(f.VerbType))
&& !t.children.some(x => uEqSome(x.node.rel, ['mark'])
|| x.node.interp.isRelative()
|| x.node.interp.isPreposition() // замість просто зробити
)
)
xreportIf(`ccomp:svc-test`,
t => t.node.rel === 'ccomp'
&& [f.VerbType.indicative, f.VerbType.infinitive, f.VerbType.imperative]
.includes(t.node.interp.getFeature(f.VerbType))
&& !t.children.some(x => uEqSome(x.node.rel, ['mark'])
|| x.node.interp.isRelative()
|| x.node.interp.isPreposition() // замість просто зробити
)
)
xreportIf(`xcomp:svc-test`,
t => t.node.rel === 'xcomp'
&& !t.parent.node.interp.isReversive()
&& [f.VerbType.indicative, f.VerbType.infinitive, f.VerbType.imperative]
.includes(t.node.interp.getFeature(f.VerbType))
&& !t.children.some(x => uEqSome(x.node.rel, ['mark'])
|| x.node.interp.isRelative()
|| x.node.interp.isPreposition() // замість просто зробити
)
&& !g.SOME_FREQUENT_TRANSITIVE_VERBS.includes(t.parent.node.interp.lemma)
&& !t.parent.node.interp.isAdjective()
)
reportIf(`compound:svc неочікуваний`,
t => t.node.rel === 'compound:svc'
&& !g.isCompounSvcCandidate(t)
)
reportIf(`кандидат на compound:svc`,
t => g.isCompounSvcCandidate(t)
&& t.node.rel !== 'compound:svc'
)
xreportIf(`не csubj з модального прислівника `,
t => !t.isRoot()
&& t.parent.node.interp.isAdverb()
&& t.node.interp.isInfinitive()
&& !uEqSome(t.node.rel, ['csubj', 'conj'])
&& !t.children.some(x => uEqSome(x.node.rel, ['mark']))
)
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
reportIf(`неочікувана реляція в прийменник`,
t => t.node.rel
&& t.node.interp.isPreposition()
&& !uEqSome(t.node.rel, ['case', 'conj', 'fixed'])
&& !t.children.some(x => uEqSome(x.node.rel, ['fixed']))
)
reportIf(`неочікувана реляція в частку`,
t => t.node.rel
&& t.node.interp.isParticle()
&& !uEqSome(t.node.rel, ['discourse', 'advmod', 'fixed', 'flat:repeat', 'goeswith'])
&& !(uEqSome(t.node.rel, ['aux']) && g.CONDITIONAL_AUX_LEMMAS.includes(t.node.interp.lemma))
// && !t.children.some(x => uEqSome(x.node.rel, ['fixed']))
)
reportIf(`неочікувана реляція в вигук`,
t => t.node.rel
&& !t.node.isGraft
&& t.node.interp.isInterjection()
&& !uEqSome(t.node.rel, ['discourse', 'flat:repeat'])
)
xreportIf(`неочікувана реляція в символ`,
t => t.node.rel
&& t.node.interp.isSymbol()
&& !uEqSome(t.node.rel, ['discourse'])
)
reportIf(`неочікувана реляція в :beforeadj`,
t => t.node.rel
&& t.node.interp.isBeforeadj()
&& (t.node.rel !== 'compound'
|| t.parent.node.index < t.node.index
|| !t.parent.node.interp.isAdjective()
)
)
reportIf(`:beforeadj не має дефіса-залежника`,
t => t.node.interp.isBeforeadj()
&& !t.isRoot()
&& !t.children.some(x => /^[\-\–\—]$/.test(x.node.interp.lemma)
&& x.node.index > t.node.index
)
&& !t.node.hasTag('no_dash')
)
reportIf(`неочікувана реляція в PUNCT`,
t => t.node.rel
&& t.node.interp.isPunctuation()
&& !uEqSome(t.node.rel, ['punct'])
)
reportIf(`неочікувана реляція в дієприслівник`,
t => t.node.rel
&& t.node.interp.isConverb()
&& !uEqSome(t.node.rel, ['advcl', 'conj', 'parataxis:discourse'])
&& !g.isAdverbialAcl(t)
&& !(uEq(t.node.rel, 'cop') && g.COPULA_LEMMAS.includes(t.node.interp.lemma))
)
reportIf(`неочікувана реляція в AUX`,
t => t.node.rel
&& t.node.interp.isAuxillary()
&& !uEqSome(t.node.rel, ['aux', 'cop'])
// && !(uEq(t.node.rel, 'aux') && CONDITIONSL_BY_LEMMAS.includes(t.node.interp.lemma))
// && !t.children.some(x => uEqSome(x.node.rel, ['fixed']))
)
reportIf(`неочікувана реляція в сурядний`,
t => t.node.rel
&& t.node.interp.isCoordinating()
&& !uEqSome(t.node.rel, ['cc', 'fixed'])
)
reportIf(`неочікувана реляція в SCONJ`,
t => t.node.rel
&& t.node.interp.isSubordinative()
&& !uEqSome(t.node.rel, ['mark', 'fixed'])
)
xreportIf(`неочікувана реляція в іменник`,
t => t.node.rel
&& t.node.interp.isNoun()
&& !uEqSome(t.node.rel, ['nsubj', 'nmod', 'appos', 'conj', 'obj', 'iobj', 'obl',
'flat:title', 'flat:name', 'xcomp:sp', 'flat:repeat', 'parataxis:discourse'])
&& !(uEqSome(t.node.rel, ['advcl']) && t.children.some(x => uEqSome(x.node.rel, ['mark'])))
&& !uEqSome(t.node.rel, [...g.CLAUSAL_MODIFIERS]) // todo
)
reportIf(`неочікувана реляція в дієслово`,
t => t.node.rel
&& !t.node.isGraft
&& t.node.interp.isVerb()
&& !t.node.interp.isAuxillary()
&& !uEqSome(t.node.rel, [...g.CLAUSE_RELS, 'conj'])
&& !['compound:svc', 'orphan', 'flat:repeat', 'flat:sibl'].includes(t.node.rel)
&& !(uEq(t.node.rel, 'appos') /* && t.node.interp.isInfinitive() */)
&& !(uEq(t.node.rel, 'obl') && t.node.hasTag('inf_prep'))
)
reportIf(`неочікувана реляція в DET`,
t => t.node.rel
// && !t.node.isPromoted
&& toUd(t.node.interp).pos === 'DET' // todo: .isDet()
&& !uEqSome(t.node.rel, ['det', 'conj', 'fixed', 'xcomp:sp', 'advcl:sp'])
&& !uEqSome(t.node.rel, ['nsubj', 'obj', 'iobj', 'obl', 'nmod'])
&& !uEqSome(t.node.rel, ['advmod:det', 'flat:abs'])
&& !g.findRelativeClauseRoot(t)
)
// todo
xreportIf(`неочікувана реляція в кількісний числівник`,
t => t.node.rel
&& t.node.interp.isCardinalNumeral()
&& !t.node.isPromoted
&& !uEqSome(t.node.rel, ['nummod', 'conj', 'flat:title'])
&& !(toUd(t.node.interp).pos === 'DET'
&& uEqSome(t.node.rel, ['det:nummod', 'det:numgov', 'conj']))
)
reportIf(`неочікувана реляція в кличний іменник`,
t => t.node.rel
&& t.node.interp.isVocative()
&& t.node.interp.isNounish()
&& !uEqSome(t.node.rel, ['vocative', 'flat:name', 'conj', 'flat:title',
'flat:repeat', 'parataxis', 'appos'])
)
reportIf(`неочікувана реляція в називний іменник`,
t => t.node.rel
&& t.node.interp.isNominative()
&& t.node.interp.isNounish()
&& uEqSome(t.node.rel, ['nmod', 'orphan'])
// && !uEqSome(t.node.rel, ['nsubj', 'flat:title', 'flat:name',
// 'flat:repeat', 'parataxis', 'conj', 'appos', 'expl',
// ])
// todo
)
reportIf(`неочікувана реляція в :stem`,
t => t.node.rel
&& t.node.interp.isStem()
&& !uEqSome(t.node.rel, ['compound'])
)
reportIf(`неочікувана реляція в прислівник з іменника`,
t => !t.isRoot()
&& t.node.interp.isAdverb()
&& t.parent.node.interp.isNounish()
&& t.node.rel !== 'acl:adv'
&& t.node.rel !== 'advmod:gerund' // ліміт на пости туди
&& !t.node.interp.isAdjectiveAsNoun() // цілком нове
&& !g.thisOrConjHead(t, x => uEqSome(x.node.rel, ['obl']))
&& !uEqSome(t.node.rel, ['discourse', 'parataxis', 'orphan'])
&& !uEqSome(t.parent.node.rel, ['orphan'])
&& !t.parent.children.some(x => uEqSome(x.node.rel, ['nsubj', 'cop']))
&& !(['не'].includes(t.node.interp.lemma) && t.node.interp.isNegative())
&& !g.isQuantitativeAdverbModifier(t)
&& !g.isModalAdv(t)
&& !g.NOUN_MODIFIABLE_ADVS.includes(t.node.interp.lemma)
&& !(uEqSome(t.node.rel, g.CLAUSAL_MODIFIERS) && g.hasPredication(t))
// [росте] ліщина колючого горіха, ялини , де-не-де берізки, берестина
&& !(uEqSome(t.node.rel, ['conj']) && g.hasChild(t, 'flat:sibl'))
)
xreportIf(`неочікувана реляція в прислівник`,
t => t.node.rel
&& t.node.interp.isAdverb()
&& !t.parent.node.interp.isNounish()
&& !uEqSome(t.node.rel, ['advmod', 'discourse', 'conj', 'fixed'])
&& !g.isModalAdv(t)
)
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tmpxreportIf(`означення при займеннику`,
t => uEqSome(t.node.rel, ['amod', 'det'])
&& !g.isNumericModifier(t.node.rel)
&& t.parent.node.interp.isNoun()
&& t.parent.node.interp.isPronominal()
&& !t.parent.node.interp.isIndefinite()
&& !t.parent.node.interp.isGeneral()
// && ![
// ['весь', 'це'],
// ].some(([adjLemma, pronLemma]) => t.node.interp.lemma === adjLemma
// && t.parent.node.interp.lemma === pronLemma
// )
)
reportIf(`nummod праворуч`,
t => isNumericModifier(t.node.rel)
&& node2index.get(t) > node2index.get(t.parent)
&& !(t.parent.node.interp.isGenitive()
&& t.parent.node.interp.isPlural()
&& t.node.interp.isAccusative()
)
&& !g.CURRENCY_SYMBOLS.includes(t.parent.node.interp.lemma)
&& !t.node.hasTag('right-nummod')
)
xreportIf(`підрядне наслідку — головне`,
t => uEqSome(t.node.rel, ['advcl'])
// todo: generalize
&& t.children.some(x => x.node.interp.lemma === 'тому'
&& x.node.interp.isDemonstrative())
)
reportIf(`порядковий праворуч`,
t => /^\d+$/.test(t.node.form)
&& uEqSome(t.node.rel, ['amod'])
&& t.node.interp.isOrdinalNumeral()
&& t.node.index > t.parent.node.index
)
reportIf(`неочікуваний відмінок nmod`,
t => uEqSome(t.node.rel, ['nmod'])
&& t.node.interp.isAccusative()
&& !g.hasChild(t, 'case')
&& !t.children.some(x => x.node.interp.lemma === '/'
&& x.node.index < t.node.index)
&& !(t.parent.node.interp.isParticiple()
&& t.parent.node.interp.isActive())
)
xreportIf(`неочікуваний орудний nmod`,
t => uEqSome(t.node.rel, ['nmod'])
&& t.node.interp.isInstrumental()
&& !g.hasChild(t, 'case')
// && !g.SOME_DATIVE_VALENCY_NOUNS.has(t.parent.node.interp.lemma)
)
reportIf(`неочікуваний давальний nmod`,
t => uEqSome(t.node.rel, ['nmod'])
&& t.node.interp.isDative()
&& !g.SOME_DATIVE_VALENCY_NOUNS.has(t.parent.node.interp.lemma)
)
reportIf(`неочікуваний відмінок прикметника-присудка`,
t => g.hasChild(t, 'nsubj')
&& t.node.interp.isAdjective()
&& !t.node.isPromoted
&& !t.node.interp.isNominative()
&& !t.node.interp.isDative() // слава Україні
&& !(t.node.interp.isInstrumental() && g.hasCopula(t))
)
reportIf(`родовий прямий додаток без заперечення`,
t => uEqSome(t.node.rel, ['obj'])
&& g.thisOrGovernedCase(t) === f.Case.genitive
&& t.parent.node.interp.isVerbial()
&& !g.isNegated(t.parent)
&& !t.parent.node.interp.isReversive() // злякався кабана, стосується жителя
&& !g.isQuantitativeAdverbModified(t) // багато дощу
&& !(t.parent.node.interp.isInfinitive()
&& t.parent.parent
&& t.parent.parent.children.some(x => x.node.interp.isNegative())
)
// пішло до 10 штук
&& !t.children.some(x => uEq(x.node.rel, 'nummod') && g.hasChild(x, 'case'))
// same form in acc exists
&& analyzer.tag(t.node.form).some(x => x.isAccusative()
&& !x.isGrammaticallyAnimate()
&& x.equalsByLemmaAndFeatures(
t.node.interp, [f.Pos, f.MorphNumber, f.Gender, f.Animacy])
)
)
xreportIf(`омонімічний родовому знахідний прямий додаток без заперечення`, t =>
uEqSome(t.node.rel, ['obj'])
&& g.thisOrGovernedCase(t) === f.Case.accusative
&& !g.isNegated(t.parent)
// same form in gen exists
&& analyzer.tag(t.node.getForm()).some(x => x.isGenitive()
&& x.equalsByLemmaAndFeatures(t.node.interp, [f.Pos, f.Animacy, f.Gender, f.MorphNumber]))
// && t.node.interp.isAnimate()
)
xreportIf(`омонімічний родовому знахідний прямий додаток із запереченням`, t =>
uEqSome(t.node.rel, ['obj'])
&& g.thisOrGovernedCase(t) === f.Case.accusative
&& g.isNegated(t.parent)
&& !t.node.interp.isPersonal() // temp
&& !['ніхто', 'ніщо'].includes(t.node.interp.lemma) // temp
// same form in gen exists
&& analyzer.tag(t.node.getForm()).some(x => x.isGenitive()
&& x.equalsByLemmaAndFeatures(t.node.interp, [f.Pos, f.Animacy, f.Gender, f.MorphNumber]))
// && t.node.interp.isAnimate()
)
reportIf2(`:animish із запереченням`,
({ i, p }) => p
&& i.isGrammaticallyAnimate()
&& g.isNegated(p)
)
xreportIf(`вказують як синонім`,
t => (t.node.interp.isNounish() || t.node.interp.isAdjective())
&& (t.node.interp.isNominative() || t.node.interp.isAccusative())
&& t.children.some(x => x.node.interp.lemma === 'як')
)
reportIf(`„більш/менш ніж“ не fixed`,
t => g.COMPARATIVE_SCONJS.includes(t.node.form)
&& tokens[t.node.index - 1]
&& g.COMPARATIVE_ADVS.includes(tokens[t.node.index - 1].form)
&& !uEq(t.node.rel, 'fixed')
)
reportIf(`advcl під’єднане до порівняльного прислівника`,
t => !t.isRoot()
&& (t.parent.node.interp.isComparable() || t.parent.node.interp.isAdjective())
&& g.hasChild(t, 'advcl')
&& t.node.interp.isAdverb()
&& t.node.interp.isComparative()
)
// reportIf2(`advcl під’єднане до порівняльного прислівника`,
// ({ n, pi, i }) => !n.isRoot()
// && pi.isAdjective()
// && g.hasChild(n, 'advcl')
// && i.isAdverb()
// && i.isComparative()
// )
reportIf(`питальний займенник без „?“`,
t => !t.isRoot()
&& t.node.interp.isInterrogative()
&& !g.thisOrConjHead(t, x => x.children.some(xx => xx.node.interp.lemma.includes('?')))
&& !g.thisOrConjHead(t.parent, x => x.children.some(xx => xx.node.interp.lemma.includes('?')))
&& !mu(t.walkThisAndUp0())
// .some(x => x.children.some(xx => xx.node.interp.lemma.includes('?')))
&& !t.node.hasTag('no_qmark')
)
reportIf(`непитальний займенник з „?“`,
t => !t.isRoot()
&& (t.node.interp.isRelative() || t.node.interp.isIndefinite())
// && !t.node.interp.isInterrogative()
&& g.thisOrConjHead(t, x => x.children.some(xx => xx.node.interp.lemma.includes('?')))
// && mu(t.walkThisAndUp0())
// .some(x => x.children.some(xx => xx.node.interp.lemma.includes('?')))
// && !t.node.hasTag('no_qmark')
)
reportIf(`неочікуваний advmod`,
t => uEq(t.node.rel, 'advmod')
&& t.node.rel !== 'advmod:amtgov'
&& !g.isFeasibleAdvmod(t.parent, t)
)
// reportIf(`неочікуване advcl`,
// t => uEq(t.node.rel, 'advcl')
// // && t.node.rel !== 'advmod:amtgov'
// && !g.isFeasibleAdvcl(t.parent, t)
// )
xreportIf(`не flat:title в „№“`,
t => t.node.interp.lemma.includes('№')
&& !t.isRoot()
&& !uEqSome(t.node.rel, ['flat:title', 'conj'])
)
reportIf(`не flat:title з „№“ в числівник`,
t => !t.isRoot()
&& t.parent.node.interp.lemma.includes('№')
&& t.node.interp.isCardinalNumeral()
&& !uEqSome(t.node.rel, ['flat:title'])
)
reportIf(`еліпс наперед`,
t => t.node.comment
&& /еліпс.* наперед/.test(t.node.comment.toLowerCase())
)
reportIf2(`невказівне _тому_ вжите як вказівне`,
({ n, l, pr, i }) => l === 'тому'
&& !i.isDemonstrative()
&& !n.isRoot()
&& uEqSome(pr, g.SUBORDINATE_CLAUSES)
&& !uEqSome(pr, ['ccomp'])
&& !g.hasChild(n, 'obl')
)
xreportIf2(`вказівне _тому_ вжите як часове`,
({ t, pr, n, l }) => l === 'тому'
&& t.interp.isDemonstrative()
&& (uEq(pr, 'obl') || g.hasChild(n, 'obl'))
)
// symmetrical to English
reportIf2(`N часу тому — _тому_ не голова`,
({ t, pr }) => t.interp.lemma === 'тому'
&& !t.interp.isDemonstrative()
&& uEq(pr, 'obl')
)
reportIf2(`порядковий числівник при місяці`,
({ r, t, i, pl }) => uEq(r, 'amod')
&& i.isOrdinalNumeral()
&& g.MONTHS.includes(pl)
)
reportIf2(`неочікуване морфо числа при місяці`,
({ r, pi, l }) => uEq(r, 'nmod')
&& g.MONTHS.includes(l)
&& !(pi.isOrdinalNumeral() && pi.isNeuter())
)
// яке, що
xreportIf2(`неузгодження acl`,
({ r, c }) => uEq(r, 'acl')
&& c.some(x => x.node.interp.lemma === 'який')
// &&
)
reportIf(`flat:sibl не з conj / не з присудка`, t =>
t.node.rel === 'flat:sibl'
&& !uEq(t.parent.node.rel, 'conj')
&& !t.parent.children.some(x => uEqSome(x.node.rel, ['conj', 'nsubj']))
)
xreportIf2(`іменник-числівник має неочікувані залежники`,
({ i, c }) => i.isNounNumeral()
&& (c.length > 1 || c.length && c[0].node.rel !== 'nmod')
)
reportIf2(`прислівник _може_ не discourse`,
({ n, i, r }) => i.lemma === 'може'
&& i.isAdverb()
&& !uEq(r, 'discourse')
&& !n.isRoot()
)
reportIf(`більше ніж один тип імені в пучку`,
t => !t.node.hasTag('multi_names')
&& Object.values(
groupBy(
t.children.filter(x => x.node.rel === 'flat:name'),
x => x.node.interp.getFeature(f.NameType)))
.some(x => x.length > 1)
)
xreportIf2(`тест: наказовий має підмет`,
({ pi, r }) => uEqSome(r, g.SUBJECTS)
&& pi.isImperative()
)
// ************ obj/iobj vs obl ************** //
reportIf('obj/iobj має прийменник',
t => uEqSome(t.node.rel, ['obj', 'iobj'])
&& g.hasChild(t, 'case')
)
// disablable
// only temporals allowed
xreportIf(`неорудний obl без прийменника`,
t => uEq(t.node.rel, 'obl')
&& !t.node.hasTag('prepless_obl')
&& !t.node.isPromoted
&& !hasChildrenOfUrel(t, 'case')
&& !t.node.interp.isInstrumental()
&& !(
(t.node.interp.isAccusative() || t.node.interp.isGenitive())
&& g.TEMPORAL_ACCUSATIVES.includes(t.node.interp.lemma)
)
)
xreportIf(`орудний obl без прийменника`,
t => uEq(t.node.rel, 'obl')
&& !t.node.hasTag('prepless_obl')
&& !hasChildrenOfUrel(t, 'case')
&& t.node.interp.isInstrumental()
)
reportIf(`неочікуваний відмінок obj`,
t => uEqSome(t.node.rel, ['obj'])
&& !t.node.isGraft
&& !(t.node.interp.isForeign() && !t.node.interp.hasCase())
&& g.thisOrGovernedCase(t) !== f.Case.accusative
&& g.thisOrGovernedCase(t) !== f.Case.genitive
&& !(g.thisOrGovernedCase(t) === f.Case.instrumental
&& g.INS_VALENCY_VERBS.includes(t.parent.node.interp.lemma) // ~
)
// legacy
&& !(t.node.interp.isDative()
&& !t.parent.children.some(x => uEq(x.node.rel, 'iobj'))
)
&& !t.children.some(x => uEqSome(x.node.rel, ['flat:abs']))
// && !t.parent.node.interp.isReversive() // todo
)
reportIf(`орудний obl в орудному дієслові`,
t => uEqSome(t.node.rel, ['obl'])
&& g.thisOrGovernedCase(t) === f.Case.instrumental
&& g.INS_VALENCY_VERBS.includes(t.parent.node.interp.lemma)
)
reportIf(`неочікуваний відмінок iobj`,
t => uEq(t.node.rel, 'iobj')
&& !t.node.isGraft
&& g.thisOrGovernedCase(t) !== f.Case.dative
&& !(t.node.interp.isForeign() && !t.node.interp.hasCase())
&& !(
t.parent.children.some(x => uEq(x.node.rel, 'obj')
&& g.thisOrGovernedCase(x) === f.Case.genitive
)
&& g.thisOrGovernedCase(t) === f.Case.accusative
)
&& !g.hasSiblink(t, 'ccomp')
&& !(t.node.interp.isNominative()
&& g.hasChild(t, 'flat:abs')
)
)
reportIf(`неочікуваний відмінок obl`,
t => uEq(t.node.rel, 'obl')
&& !t.node.isGraft
&& !(t.node.interp.isForeign() && !t.node.interp.hasCase())
&& (g.thisOrGovernedCase(t) === f.Case.nominative
|| g.thisOrGovernedCase(t) === f.Case.vocative
)
&& !g.isDenUDen(t)
&& !(t.node.interp.isNominative() && t.children.some(x => uEqSome(x.node.rel, ['flat:abs'])))
&& !(t.node.interp.isNominative() && ['сам'].includes(t.node.interp.lemma))
)
reportIf(`cop/aux в наказовому`,
t => uEqSome(t.node.rel, ['cop', 'aux'])
&& t.node.interp.isImperative()
&& !t.node.hasTag('ok-imp-cop')
)
reportIf(`наказовий має cop/aux`,
t => t.node.interp.isImperative()
&& t.children.some(x => uEqSome(x.node.rel, ['cop', 'aux']))
)
xreportIf2(`велика літера не власна`,
({ t, i }) => t.index > 0
&& startsWithCapital(t.getForm())
&& !i.isProper()
&& !i.isAbbreviation()
)
reportIf2(`не родовий однини після десяткового`,
({ r, n, pi }) => uEq(r, 'nummod')
&& g.canBeDecimalFraction(n)
&& (pi.isPlural() || pi.getFeature(f.Case) !== f.Case.genitive)
)
reportIf2(`неочікуваний залежник nummod’ду`, // todo
({ r, pr, i, n, pi }) => pr
&& g.isNumericModifier(pr)
&& !uEqSome(r, ['compound', 'conj', 'discourse', 'punct'])
&& r !== 'flat:range'
&& !(uEq(r, 'case')
&& ['від', 'до', 'близько', 'понад', 'коло'].includes(i.lemma)
)
&& !(uEq(r, 'advmod')
&& ['не', 'ні', /* <- todo */ 'майже', '~',
'щонайменше', 'приблизно', 'принаймні'].includes(i.lemma)
)
&& !g.hasChild(n, 'fixed') // todo
&& !(pi.isPronominal() && i.isAdverb() && ['так', 'дуже'].includes(i.lemma))
)
xreportIf2(`xcomp не має явного підмета`,
({ n, r, p }) => uEq(r, 'xcomp') && !g.findXcompSubject(n)
)
reportIf2(`потенційне _що її_ без кореференції чи #not-shchojiji`,
({ n, t }) => {
if (t.hasTag('not-shchojiji')) {
return false
}
let antecedent = g.findShchojijiAntecedent(n)
if (!antecedent) {
return false
}
return !corefClusterization.areSameGroup(antecedent.node, t)
}
)
if (valencyDict) {
reportIf(`неперехідне дієслово має додаток`,
t => uEqSome(t.node.rel, ['obj'/* , 'iobj' */])
&& t.parent.node.interp.isVerb()
&& valencyDict.isIntransitiveOnlyVerb(t.parent.node.interp.lemma)
&& !(uEq(t.node.rel, 'obj') && t.node.interp.isDative())
&& !t.node.interp.isGenitive()
&& !(g.thisOrGovernedCase(t) === f.Case.instrumental
&& g.INS_VALENCY_VERBS.includes(t.parent.node.interp.lemma)
)
&& !(g.thisOrGovernedCase(t) === f.Case.accusative
&& g.SOME_WORDS_WITH_ACC_VALENCY.has(t.parent.node.interp.lemma)
)
&& !(t.parent.node.interp.isNeuter()
&& t.parent.node.interp.isReversive()
&& (valencyDict.isAmbigiousVerb(t.parent.node.interp.lemma.slice(0, -2))
|| g.SOME_WORDS_WITH_ACC_VALENCY.has(t.parent.node.interp.lemma.slice(0, -2))
)
)
)
xreportIf(`перехідне дієслово не має додатка`,
t => t.node.interp.isVerb()
&& valencyDict.isAccusativeOnlyVerb(t.node.interp.lemma)
&& !thisOrConj(t, tt => tt.children.length
&& (tt.children.some(x => uEqSome(x.node.rel, g.CORE_COMPLEMENTS_XCOMP))
|| tt.children.some(x => uEq(x.node.rel, 'iobj')
&& x.node.interp.isDative()
)
)
)
)
const johojiji = ['його', 'її', 'їх']
const johojijiStr = ['його', 'її', 'їх'].join('/')
xreportIf(`${johojijiStr}-прикметник замість іменника`,
t => johojiji.includes(t.node.form.toLowerCase())
&& t.node.interp.isAdjective()
&& t.parent
&& t.parent.node.interp.isNoun()
&& valencyDict.isTransitiveOnlyGerund(t.parent.node.interp.lemma)
)
xreportIf(`${johojijiStr}-прикметник замість іменника (потенційно)`,
t => johojiji.includes(t.node.form.toLowerCase())
&& t.node.interp.isAdjective()
&& t.parent
&& t.parent.node.interp.isNoun()
&& valencyDict.isAmbigiousGerund(t.parent.node.interp.lemma)
)
xreportIf(`${johojijiStr}-прикметник замість іменника (-ння)`,
t => johojiji.includes(t.node.form.toLowerCase())
&& t.node.interp.isAdjective()
&& t.parent
&& t.parent.node.interp.isNoun()
&& t.parent.node.interp.lemma.endsWith('ння')
&& !valencyDict.hasGerund(t.parent.node.interp.lemma)
)
xreportIf(`${johojijiStr}-іменник замість прикметника`,
t => johojiji.includes(t.node.form.toLowerCase())
&& t.node.interp.isNoun()
&& t.parent
&& t.parent.node.interp.isNoun()
&& valencyDict.isIntransitiveOnlyGerund(t.parent.node.interp.lemma)
)
xreportIf(`${johojijiStr}-іменник замість прикметника (потенційно)`,
t => johojiji.includes(t.node.form.toLowerCase())
&& t.node.interp.isNoun()
&& t.parent
&& t.parent.node.interp.isNoun()
&& valencyDict.isAmbigiousGerund(t.parent.node.interp.lemma)
)
xreportIf(`${johojijiStr}-іменник замість прикметника (-ння)`,
t => johojiji.includes(t.node.form.toLowerCase())
&& t.node.interp.isNoun()
&& t.parent
&& t.parent.node.interp.isNoun()
&& t.parent.node.interp.lemma.endsWith('ння')
&& !valencyDict.hasGerund(t.parent.node.interp.lemma)
)
reportIf2(`в звороті типу _вчити дитину математики_ переплутані patient з addressee`,
({ r, i, p }) => uEq(r, 'iobj')
&& i.isGenitive()
&& p.children.some(x => uEq(x.node.rel, 'obj')
&& x.node.interp.isAccusative()
)
)
tmpxreportIf2(`чистий flat`,
({ r }) => r === 'flat'
)
reportIf2(`голова orphan’а не під’єднана до реконструкції пропуска`,
({ n, r }) => uEq(r, 'orphan')
&& !n.parent.parents.some(x => x.node.isElided())
)
reportIf2(`orphan не під’єднаний до реконструкції пропуска`,
({ n, r }) => uEq(r, 'orphan')
&& !n.parents.some(x => x.node.isElided())
)
reportIf2(`orphan в пропуск`,
({ r, t }) => uEq(r, 'orphan')
&& t.isElided()
)
reportIf2(`orphan з пропуска`,
({ pt, r }) => uEq(r, 'orphan')
&& pt.isElided()
)
reportIf2(`непід’єднаний пропуск`,
({ n, t }) => t.isElided() && n.isRoot() && !n.hasChildren()
)
// todo
xreportIf(`ADV має іменникові інтерпретації`,
t => t.node.interp.isAdverb()
&& analyzer.tag(t.node.form).some(x => x.isNoun() && !x.isVocative())
&& !g.VALID_ADVS_AMBIG_TO_NOUN.has(t.node.form.toLowerCase())
&& !t.node.interp.isAbbreviation()
)
/* reportIf(`wrong promotion precedence`,
t => {
if (!t.node.hasUDep('orphan')) {
return
}
let basicParent = t.parents.find(x => uEq(x.node.rel, 'orphan') && !x.node.isElided())
if (!basicParent) {
return
}
}
) */
tmpxreportIf2(`Promoted не прикметник`,
({ n, t, i }) => t.isPromoted
&& !i.isAdjectivish()
&& !i.isCardinalNumeral()
&& !n.parents.some(x => x.node.isElided())
&& !t.hasTag('promoted-not-adj')
&& !t.hasTag('orphanless-elision')
&& !t.hasTag('nominal-ellipsis')
)
reportIf2(`токен позначено “ожеледиця”`,
({ t }) => t.comment
&& t.comment.toLowerCase().includes('ожеледиця')
&& !t.comment.toLowerCase().includes('лжеожеледиця')
)
reportIf(`недієслівна предикація праворуч`, t =>
uEqSome(t.node.rel, ['nsubj'/* , 'csubj' */])
&& t.node.index > t.parent.node.index
&& !t.parent.node.interp.isVerbial()
&& !t.parent.node.interp.isAdjective() // ~
&& !t.parent.node.interp.isAdverb()
&& !t.parent.node.interp.isInstrumental()
&& !t.parent.node.interp.isInterrogative()
&& !g.hasChild(t.parent, 'expl')
&& !t.node.hasTag('pred-right')
)
xreportIf(`присудок є залежником`, t =>
uEqSome(t.node.rel, ['nsubj', 'csubj', 'cop'])
&& t.parent.parent
&& !uEqSome(t.parent.node.rel, [...g.CLAUSE_RELS, 'conj'])
&& !t.parent.node.isGraft
&& !['compound:svc', 'orphan'].includes(t.parent.node.rel)
)
if (sentenceHasOneRoot) {
let sentenceWithoutPunct = tokens.filter(x => !x.interp.isPunctuation())
let skip = sentenceWithoutPunct.length === 1
// && [
// f.Pos.noun,
// f.Pos.particle,
// f.Pos.interjection,
// f.Pos.cardinalNumeral,
// f.Pos.sym,
// ].includes(sentenceWithoutPunct[0].interp.getFeature(f.Pos))
if (!skip) {
tmpxreportIf(`корінь без предикації`, t =>
t.isRoot()
&& !g.hasPredication(t)
)
}
}
xreportIf(`давальний з інфінітива`, t =>
uEqSome(t.node.rel, ['obj', 'iobj'])
&& t.node.interp.isDative()
&& g.isInfinitive(t.parent)
&& !uEqSome(t.parent.node.rel, g.SUBORDINATE_CLAUSES)
)
// disablable
xreportIf(`такий xxx не advmod:det`, t =>
g.ADVMOD_DETS.has(t.node.interp.lemma)
&& t.node.interp.isAdjective()
&& (t.parent || sentenceHasOneRoot)
&& tokens[t.node.index + 1]
&& !(t.parent === nodes[t.node.index + 1] && t.node.rel === 'advmod:det')
&& tokens[t.node.index + 1].interp.equalsByFeatures(
t.node.interp, [f.Pos, f.Case, f.Gender])
)
xreportIf(`advmod:det в непорівнюване`, t =>
t.node.rel === 'advmod:det'
&& !t.parent.node.interp.isComparable()
)
xreportIf(`advcl під’єднане напряму до вказівного`, t =>
uEq(t.node.rel, 'advmod')
&& t.node.interp.isDemonstrative()
&& t.children.some(x => uEq(x.node.rel, 'advcl'))
)
tmpxreportIf(`advcl: під’єднане не напряму до вказівного`, t =>
uEq(t.node.rel, 'advmod')
&& t.node.interp.isDemonstrative()
&& t.parent.children.some(x => uEq(x.node.rel, 'advcl')
&& x.node.rel !== 'advcl:cmp'
)
&& !g.hasChild(t, 'advcl')
// todo: ~тому, тоді навпаки
// коли наш лікнеп зробить своє діло серед нашого пролетаріату ,
// тоді те пролетарське мистецтво , що про нього ми зараз будемо говорити ,
// воістину буде творити чудеса
)
tmpxreportIf(`advcl:cmp під’єднане не напряму до вказівного`, t =>
uEq(t.node.rel, 'advmod')
&& t.node.interp.isDemonstrative()
&& t.parent.children.some(x => uEq(x.node.rel, 'advcl')
&& x.node.rel === 'advcl:cmp'
)
)
reportIf(`неочікуваний клей між цим і наступним словом`, t =>
t.node.index < tokens.length - 1
&& t.node.gluedNext
&& !g.areOkToBeGlued(t, nodes[t.node.index + 1])
&& !t.node.hasTag('ok-glued-next')
)
reportIf(`дискурсивне слово не discourse`, t =>
!t.isRoot()
&& !uEqSome(t.node.rel, ['discourse'])
&& ['наприклад'].includes(t.node.interp.lemma)
)
xreportIf(`особовий в :irrel з _що_`, t =>
t.node.interp.isPersonal()
&& wiith(mu(t.walkThisAndUp0()).find(x => x.node.rel === 'acl:irrel'), acl =>
acl
&& acl.children.some(x => uEq(x.node.rel, 'mark') && x.node.interp.lemma === 'що')
)
)
xreportIf(`нерозрізнений acl зі сполучником _що_`, t =>
uEq(t.node.rel, 'acl')
&& t.children.some(x => uEq(x.node.rel, 'mark') && x.node.interp.lemma === 'що')
// && !g.isRelativeSpecificAcl(t.node.rel)
)
xreportIf(`нерозрізнений acl зі сполучником іншим від _що_`, t =>
uEq(t.node.rel, 'acl')
&& t.children.some(x => uEq(x.node.rel, 'mark') && x.node.interp.lemma !== 'що')
// && !g.isRelativeSpecificAcl(t.node.rel)
)
xreportIf(`нерозрізнений acl без сполучника`, t =>
uEq(t.node.rel, 'acl')
&& !t.children.some(x => uEq(x.node.rel, 'mark'))
// && !g.isRelativeSpecificAcl(t.node.rel)
&& !['acl:adv'].includes(t.node.rel)
)
xreportIf(`нерозрізнений acl з відносним ADV`, t =>
t.node.interp.isRelative()
&& t.node.interp.isAdverb()
&& wiithNonempty(g.findRelativeClauseRoot(t), relclRoot =>
// relclRoot.node.rel === 'acl'
g.isRelclByRef(enhancedNodes[relclRoot.node.index]
.incomingArrows.find(x => uEq(x.attrib, 'acl'))
)
)
)
// reportIf(``, t =>
// t.node.interp.isRelative()
// && t.node.interp.isAdverb()
// && wiithNonempty(g.findRelativeClauseRoot(t), relclRoot =>
// // relclRoot.node.rel === 'acl'
// g.isRelclByRef(enhancedNodes[relclRoot.node.index]
// .incomingArrows.find(x => uEq(x.attrib, 'acl'))
// )
// )
// )
ereportIf(`acl без ref’а з відносним прислівником`, a =>
uEq(a.attrib, 'acl')
&& !g.isRelclByRef(a)
&& a.end.walkForwardWidth({ cutAndFilter: (x) => uEq(last(x).attrib, 'acl') })
.some(x => x.end.node.interp.isAdverb() && x.end.node.interp.isRelative())
)
// ereportIf(`відносний ADV в acl’і без ref`, a =>
// // uEq(a.attrib, 'acl')
// a.end.node.interp.isAdverb()
// && a.end.node.interp.isRelative()
// && !a.end.walkBackWidth()
// .filter(x => uEq(x.attrib, 'acl'))
// .some(x => x.start.outgoingArrows.some(xx => xx.attrib === 'rel' && xx.end === a.end))
// )
xreportIf(`відносний _що_ у acl:relfull`, t =>
t.node.form === 'що'
&& !uEqSome(t.node.rel, ['obl'])
&& t.node.interp.isRelative()
&& wiith(g.findRelativeClauseRoot(t), relclRoot =>
relclRoot && relclRoot.node.rel === 'acl:relfull'
)
)
reportIf(`acl:relless не має назаднього nsubj/obj`, t =>
t.node.rel === 'acl:relless'
&& !enhancedOnlyNodes[t.node.index].outgoingArrows.some(x =>
x.end.node.index === t.parent.node.index
&& uEqSome(x.attrib, ['obj', 'nsubj']))
)
reportIf(`acl:relpers без ref`, t =>
t.node.rel === 'acl:relpers'
&& !enhancedOnlyNodes[t.parent.node.index].outgoingArrows.some(x => x.attrib === 'ref')
)
reportIf(`відносний в нерозрізненому acl’і`, t =>
t.node.interp.isRelative()
&& !t.node.interp.isAdverb()
&& wiith(g.findRelativeClauseRoot(t), relclRoot =>
relclRoot && relclRoot.node.rel === 'acl'
)
)
reportIf(`відносний в acl:irrel`, t =>
wiith(g.findRelativeClauseRoot(t), relclRoot =>
relclRoot && relclRoot.node.rel === 'acl:irrel'
)
)
if (0) {
let relRoots = nodes.filter(x => x.node.interp.isRelative())
.map(x => g.findRelativeClauseRoot(x))
relRoots.filter((x, i) => relRoots.find((xx, ii) => ii !== i && xx === x))
.forEach(x => problems.push({
indexes: [x.node.index],
message: `не єдиний відносний`,
}))
}