Files
SubMiner/vendor/yomitan/js/language/en/english-transforms.js

293 lines
11 KiB
JavaScript

/*
* Copyright (C) 2024-2025 Yomitan Authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {prefixInflection, suffixInflection} from '../language-transforms.js';
/** @typedef {keyof typeof conditions} Condition */
/**
* @param {string} consonants
* @param {string} suffix
* @param {Condition[]} conditionsIn
* @param {Condition[]} conditionsOut
* @returns {import('language-transformer').SuffixRule<Condition>[]}
*/
function doubledConsonantInflection(consonants, suffix, conditionsIn, conditionsOut) {
const inflections = [];
for (const consonant of consonants) {
inflections.push(suffixInflection(`${consonant}${consonant}${suffix}`, consonant, conditionsIn, conditionsOut));
}
return inflections;
}
const pastSuffixInflections = [
suffixInflection('ed', '', ['v'], ['v']), // 'walked'
suffixInflection('ed', 'e', ['v'], ['v']), // 'hoped'
suffixInflection('ied', 'y', ['v'], ['v']), // 'tried'
suffixInflection('cked', 'c', ['v'], ['v']), // 'frolicked'
...doubledConsonantInflection('bdgklmnprstz', 'ed', ['v'], ['v']),
suffixInflection('laid', 'lay', ['v'], ['v']),
suffixInflection('paid', 'pay', ['v'], ['v']),
suffixInflection('said', 'say', ['v'], ['v']),
];
const ingSuffixInflections = [
suffixInflection('ing', '', ['v'], ['v']), // 'walking'
suffixInflection('ing', 'e', ['v'], ['v']), // 'driving'
suffixInflection('ying', 'ie', ['v'], ['v']), // 'lying'
suffixInflection('cking', 'c', ['v'], ['v']), // 'panicking'
...doubledConsonantInflection('bdgklmnprstz', 'ing', ['v'], ['v']),
];
const thirdPersonSgPresentSuffixInflections = [
suffixInflection('s', '', ['v'], ['v']), // 'walks'
suffixInflection('es', '', ['v'], ['v']), // 'teaches'
suffixInflection('ies', 'y', ['v'], ['v']), // 'tries'
];
const phrasalVerbParticles = ['aboard', 'about', 'above', 'across', 'ahead', 'alongside', 'apart', 'around', 'aside', 'astray', 'away', 'back', 'before', 'behind', 'below', 'beneath', 'besides', 'between', 'beyond', 'by', 'close', 'down', 'east', 'west', 'north', 'south', 'eastward', 'westward', 'northward', 'southward', 'forward', 'backward', 'backwards', 'forwards', 'home', 'in', 'inside', 'instead', 'near', 'off', 'on', 'opposite', 'out', 'outside', 'over', 'overhead', 'past', 'round', 'since', 'through', 'throughout', 'together', 'under', 'underneath', 'up', 'within', 'without'];
const phrasalVerbPrepositions = ['aback', 'about', 'above', 'across', 'after', 'against', 'ahead', 'along', 'among', 'apart', 'around', 'as', 'aside', 'at', 'away', 'back', 'before', 'behind', 'below', 'between', 'beyond', 'by', 'down', 'even', 'for', 'forth', 'forward', 'from', 'in', 'into', 'of', 'off', 'on', 'onto', 'open', 'out', 'over', 'past', 'round', 'through', 'to', 'together', 'toward', 'towards', 'under', 'up', 'upon', 'way', 'with', 'without'];
const particlesDisjunction = phrasalVerbParticles.join('|');
const phrasalVerbWordSet = new Set([...phrasalVerbParticles, ...phrasalVerbPrepositions]);
const phrasalVerbWordDisjunction = [...phrasalVerbWordSet].join('|');
/**
* @type {import('language-transformer').Rule<Condition>}
*/
const phrasalVerbInterposedObjectRule = {
type: 'other',
isInflected: new RegExp(`^\\w* (?:(?!\\b(${phrasalVerbWordDisjunction})\\b).)+ (?:${particlesDisjunction})`),
deinflect: (term) => {
return term.replace(new RegExp(`(?<=\\w) (?:(?!\\b(${phrasalVerbWordDisjunction})\\b).)+ (?=(?:${particlesDisjunction}))`), ' ');
},
conditionsIn: [],
conditionsOut: ['v_phr'],
};
/**
* @param {string} inflected
* @param {string} deinflected
* @returns {import('language-transformer').Rule<Condition>}
*/
function createPhrasalVerbInflection(inflected, deinflected) {
return {
type: 'other',
isInflected: new RegExp(`^\\w*${inflected} (?:${phrasalVerbWordDisjunction})`),
deinflect: (term) => {
return term.replace(new RegExp(`(?<=)${inflected}(?= (?:${phrasalVerbWordDisjunction}))`), deinflected);
},
conditionsIn: ['v'],
conditionsOut: ['v_phr'],
};
}
/**
* @param {import('language-transformer').SuffixRule<Condition>[]} sourceRules
* @returns {import('language-transformer').Rule<Condition>[]}
*/
function createPhrasalVerbInflectionsFromSuffixInflections(sourceRules) {
return sourceRules.flatMap(({isInflected, deinflected}) => {
if (typeof deinflected === 'undefined') { return []; }
const inflectedSuffix = isInflected.source.replace('$', '');
const deinflectedSuffix = deinflected;
return [createPhrasalVerbInflection(inflectedSuffix, deinflectedSuffix)];
});
}
const conditions = {
v: {
name: 'Verb',
isDictionaryForm: true,
subConditions: ['v_phr'],
},
v_phr: {
name: 'Phrasal verb',
isDictionaryForm: true,
},
n: {
name: 'Noun',
isDictionaryForm: true,
subConditions: ['np', 'ns'],
},
np: {
name: 'Noun plural',
isDictionaryForm: true,
},
ns: {
name: 'Noun singular',
isDictionaryForm: true,
},
adj: {
name: 'Adjective',
isDictionaryForm: true,
},
adv: {
name: 'Adverb',
isDictionaryForm: true,
},
};
/** @type {import('language-transformer').LanguageTransformDescriptor<Condition>} */
export const englishTransforms = {
language: 'en',
conditions,
transforms: {
'plural': {
name: 'plural',
description: 'Plural form of a noun',
rules: [
suffixInflection('s', '', ['np'], ['ns']),
suffixInflection('es', '', ['np'], ['ns']),
suffixInflection('ies', 'y', ['np'], ['ns']),
suffixInflection('ves', 'fe', ['np'], ['ns']),
suffixInflection('ves', 'f', ['np'], ['ns']),
],
},
'possessive': {
name: 'possessive',
description: 'Possessive form of a noun',
rules: [
suffixInflection('\'s', '', ['n'], ['n']),
suffixInflection('s\'', 's', ['n'], ['n']),
],
},
'past': {
name: 'past',
description: 'Simple past tense of a verb',
rules: [
...pastSuffixInflections,
...createPhrasalVerbInflectionsFromSuffixInflections(pastSuffixInflections),
],
},
'ing': {
name: 'ing',
description: 'Present participle of a verb',
rules: [
...ingSuffixInflections,
...createPhrasalVerbInflectionsFromSuffixInflections(ingSuffixInflections),
],
},
'3rd pers. sing. pres': {
name: '3rd pers. sing. pres',
description: 'Third person singular present tense of a verb',
rules: [
...thirdPersonSgPresentSuffixInflections,
...createPhrasalVerbInflectionsFromSuffixInflections(thirdPersonSgPresentSuffixInflections),
],
},
'interposed object': {
name: 'interposed object',
description: 'Phrasal verb with interposed object',
rules: [
phrasalVerbInterposedObjectRule,
],
},
'archaic': {
name: 'archaic',
description: 'Archaic form of a word',
rules: [
suffixInflection('\'d', 'ed', ['v'], ['v']),
],
},
'adverb': {
name: 'adverb',
description: 'Adverb form of an adjective',
rules: [
suffixInflection('ly', '', ['adv'], ['adj']), // 'quickly'
suffixInflection('ily', 'y', ['adv'], ['adj']), // 'happily'
suffixInflection('ly', 'le', ['adv'], ['adj']), // 'humbly'
],
},
'comparative': {
name: 'comparative',
description: 'Comparative form of an adjective',
rules: [
suffixInflection('er', '', ['adj'], ['adj']), // 'faster'
suffixInflection('er', 'e', ['adj'], ['adj']), // 'nicer'
suffixInflection('ier', 'y', ['adj'], ['adj']), // 'happier'
...doubledConsonantInflection('bdgmnt', 'er', ['adj'], ['adj']),
],
},
'superlative': {
name: 'superlative',
description: 'Superlative form of an adjective',
rules: [
suffixInflection('est', '', ['adj'], ['adj']), // 'fastest'
suffixInflection('est', 'e', ['adj'], ['adj']), // 'nicest'
suffixInflection('iest', 'y', ['adj'], ['adj']), // 'happiest'
...doubledConsonantInflection('bdgmnt', 'est', ['adj'], ['adj']),
],
},
'dropped g': {
name: 'dropped g',
description: 'Dropped g in -ing form of a verb',
rules: [
suffixInflection('in\'', 'ing', ['v'], ['v']),
],
},
'-y': {
name: '-y',
description: 'Adjective formed from a verb or noun',
rules: [
suffixInflection('y', '', ['adj'], ['n', 'v']), // 'dirty', 'pushy'
suffixInflection('y', 'e', ['adj'], ['n', 'v']), // 'hazy'
...doubledConsonantInflection('glmnprst', 'y', [], ['n', 'v']), // 'baggy', 'saggy'
],
},
'un-': {
name: 'un-',
description: 'Negative form of an adjective, adverb, or verb',
rules: [
prefixInflection('un', '', ['adj', 'adv', 'v'], ['adj', 'adv', 'v']),
],
},
'going-to future': {
name: 'going-to future',
description: 'Going-to future tense of a verb',
rules: [
prefixInflection('going to ', '', ['v'], ['v']),
],
},
'will future': {
name: 'will future',
description: 'Will-future tense of a verb',
rules: [
prefixInflection('will ', '', ['v'], ['v']),
],
},
'imperative negative': {
name: 'imperative negative',
description: 'Negative imperative form of a verb',
rules: [
prefixInflection('don\'t ', '', ['v'], ['v']),
prefixInflection('do not ', '', ['v'], ['v']),
],
},
'-able': {
name: '-able',
description: 'Adjective formed from a verb',
rules: [
suffixInflection('able', '', ['v'], ['adj']),
suffixInflection('able', 'e', ['v'], ['adj']),
suffixInflection('iable', 'y', ['v'], ['adj']),
...doubledConsonantInflection('bdgklmnprstz', 'able', ['v'], ['adj']),
],
},
},
};