add support for word end and phoneme deletion

This commit is contained in:
Sorrel Bri 2020-02-19 18:33:00 -08:00
parent a19102f82e
commit 07be982b51
3 changed files with 63 additions and 16 deletions

View file

@ -5,15 +5,15 @@ export type initAction = {
type: "INIT" type: "INIT"
} }
export const initState = (changesArgument: number = -1): stateType => { export const initState = (changesArgument: number): stateType => {
const state = { const state = {
epochs: [ epochs: [
{ {
name: 'epoch 1', name: 'epoch 1',
changes: [ changes: [
'[+ occlusive - nasal]>[+ occlusive + nasal]/n_.', '[+ occlusive - nasal]>[+ occlusive + nasal]/n_.',
// 'at>ta/._#', 'a>ɯ/._#',
// '[+ sonorant - low rounded high back]>0/._.', '[+ sonorant - low rounded high back]>0/._.',
// 'nn>nun/._.', // 'nn>nun/._.',
// '[+ nasal][+ obstruent]>[+ nasal obstruent aspirated ]/#_.', // '[+ nasal][+ obstruent]>[+ nasal obstruent aspirated ]/#_.',
// '[+ sonorant rounded]>[+ sonorant - rounded]/._#' // '[+ sonorant rounded]>[+ sonorant - rounded]/._#'
@ -43,7 +43,7 @@ export const initState = (changesArgument: number = -1): stateType => {
}, },
t: { t: {
grapheme: 't', features: { grapheme: 't', features: {
occlusive: true, coronal: true, obstruent: true occlusive: true, coronal: true, obstruent: true, nasal: false
}, },
ʰ: { ʰ: {
grapheme: 'tʰ', features: { grapheme: 'tʰ', features: {
@ -86,7 +86,7 @@ export const initState = (changesArgument: number = -1): stateType => {
{lexeme: 'ənta', epoch: state.epochs[0]} {lexeme: 'ənta', epoch: state.epochs[0]}
] ]
if(changesArgument > -1) state.epochs[0].changes = state.epochs[0].changes.splice(changesArgument, 1) if(changesArgument > -1) state.epochs[0].changes = state.epochs[0].changes.splice(0, changesArgument)
return state; return state;
} }

View file

@ -43,6 +43,7 @@ const findFeaturesFromLexeme = (phones: {}, lexeme:string): [] => {
}) })
return featureBundle; return featureBundle;
} }
const findFeaturesFromGrapheme = (phones: {}, lexeme:string): [] => { const findFeaturesFromGrapheme = (phones: {}, lexeme:string): [] => {
let featureBundle = [] let featureBundle = []
let lastIndex = lexeme.length - 1; let lastIndex = lexeme.length - 1;
@ -94,6 +95,8 @@ const mapToPositiveAndNegativeFeatures = phoneme => (
const mapStringToFeatures = (ruleString, phones) => { const mapStringToFeatures = (ruleString, phones) => {
if (ruleString) { if (ruleString) {
if (ruleString === '.') return []; if (ruleString === '.') return [];
if (ruleString === '#') return ['#']
if (ruleString === '0') return [];
const ruleBrackets = ruleString.match(/\[.*\]/) const ruleBrackets = ruleString.match(/\[.*\]/)
if (ruleBrackets) { if (ruleBrackets) {
return ruleString return ruleString
@ -129,6 +132,7 @@ const isPhonemeBoundByRule = phonemeFeatures => (ruleFeature, index) => {
const phoneme = phonemeFeatures[index].features; const phoneme = phonemeFeatures[index].features;
return Object.entries(ruleFeature).reduce((bool, [feature, value]) => { return Object.entries(ruleFeature).reduce((bool, [feature, value]) => {
if (!bool) return false; if (!bool) return false;
if (!phoneme.hasOwnProperty(feature)) return false;
if (!phoneme[feature] && !value) return true; if (!phoneme[feature] && !value) return true;
if (phoneme[feature] !== value) return false; if (phoneme[feature] !== value) return false;
return true; return true;
@ -141,9 +145,8 @@ const isEnvironmentBoundByRule = (phonemeFeatures, ruleFeatures) => {
? true : false; ? true : false;
} }
const swapPhoneme = (phoneme, newFeatures, features) => { const swapPhoneme = (phoneme, newFeatures, features) => {
if (!newFeatures) return {}
const newPhonemeFeatures = Object.entries(newFeatures) const newPhonemeFeatures = Object.entries(newFeatures)
.reduce((newPhoneme, [newFeature, newValue]) => ({ ...newPhoneme, [newFeature]: newValue }) .reduce((newPhoneme, [newFeature, newValue]) => ({ ...newPhoneme, [newFeature]: newValue })
, {...phoneme.features}); , {...phoneme.features});
@ -154,12 +157,30 @@ const swapPhoneme = (phoneme, newFeatures, features) => {
, newPhonemeCandidates[newPhonemeCandidates.length - 1])[0]; , newPhonemeCandidates[newPhonemeCandidates.length - 1])[0];
} }
const transformLexemeInitial = (newLexeme, pre, post, position, phoneme, index, lexemeBundle, newFeatures, features) => {
if (index !== pre.length - 1) return [...newLexeme, phoneme];
if (!isEnvironmentBoundByRule([phoneme], position)) return [...newLexeme, phoneme];
if (!isEnvironmentBoundByRule(lexemeBundle.slice(index, index + post.length), post)) return [...newLexeme, phoneme];
const newPhoneme = swapPhoneme(phoneme, newFeatures[0], features);
return [...newLexeme, newPhoneme];
}
const transformLexemeCoda = (newLexeme, pre, post, position, phoneme, index, lexemeBundle, newFeatures, features) => {
if (index + post.length !== lexemeBundle.length) return [...newLexeme, phoneme];
if (!isEnvironmentBoundByRule(lexemeBundle.slice(index - pre.length, index), pre)) return [...newLexeme, phoneme];
if (!isEnvironmentBoundByRule([phoneme], position)) return [...newLexeme, phoneme];
const newPhoneme = swapPhoneme(phoneme, newFeatures[0], features);
return [...newLexeme, newPhoneme];
}
export const transformLexeme = (lexemeBundle, rule, features) => { export const transformLexeme = (lexemeBundle, rule, features) => {
const {pre, post, position} = rule.environment; const {pre, post, position} = rule.environment;
const newLexeme = lexemeBundle.reduce((newLexeme, phoneme, index) => { const newLexeme = lexemeBundle.reduce((newLexeme, phoneme, index) => {
if (pre.find(val => val === '#')) return transformLexemeInitial(newLexeme, pre, post, position, phoneme, index, lexemeBundle, rule.newFeatures, features);
if (post.find(val => val === '#')) return transformLexemeCoda(newLexeme, pre, post, position, phoneme, index, lexemeBundle, rule.newFeatures, features);
if ( index < pre.length || index >= lexemeBundle.length - post.length ) return [...newLexeme, phoneme]; if ( index < pre.length || index >= lexemeBundle.length - post.length ) return [...newLexeme, phoneme];
if (!isEnvironmentBoundByRule(lexemeBundle.slice(index - pre.length, index), pre)) return [...newLexeme, phoneme]; if (!isEnvironmentBoundByRule(lexemeBundle.slice(index - pre.length, index), pre)) return [...newLexeme, phoneme];
if (!isEnvironmentBoundByRule([phoneme], rule.environment.position)) return [...newLexeme, phoneme]; if (!isEnvironmentBoundByRule([phoneme], position)) return [...newLexeme, phoneme];
if (!isEnvironmentBoundByRule(lexemeBundle.slice(index, index + post.length), post)) return [...newLexeme, phoneme]; if (!isEnvironmentBoundByRule(lexemeBundle.slice(index, index + post.length), post)) return [...newLexeme, phoneme];
const newPhoneme = swapPhoneme(phoneme, rule.newFeatures[0], features); const newPhoneme = swapPhoneme(phoneme, rule.newFeatures[0], features);
return [...newLexeme, newPhoneme]; return [...newLexeme, newPhoneme];
@ -173,7 +194,7 @@ const transformLexicon = lexiconBundle =>
ruleBundle => ruleBundle =>
features => features =>
lexiconBundle.map(lexemeBundle => ruleBundle.reduce( lexiconBundle.map(lexemeBundle => ruleBundle.reduce(
(lexeme, rule) => transformLexeme(lexeme, rule, features) (lexeme, rule, i) => transformLexeme(lexeme, rule, features)
, lexemeBundle , lexemeBundle
)) ))

View file

@ -55,7 +55,7 @@ describe('Results', () => {
}, },
{ {
grapheme: 't', grapheme: 't',
features: { occlusive: true, coronal: true, obstruent: true } features: { occlusive: true, coronal: true, obstruent: true, nasal: false }
}, },
{ {
grapheme: 'a', grapheme: 'a',
@ -88,7 +88,7 @@ describe('Results', () => {
it('results returned from first sound change rule', () => { it('results returned from first sound change rule', () => {
const action = {type: 'RUN'}; const action = {type: 'RUN'};
state = initState(0) state = initState(1)
expect(stateReducer(state, action).results).toEqual([ expect(stateReducer(state, action).results).toEqual([
{ {
pass: 'epoch 1', pass: 'epoch 1',
@ -99,18 +99,44 @@ describe('Results', () => {
]); ]);
}); });
if('results returned from sound change suite', () => { it('results returned through second sound change rule', () => {
const action = {type: 'RUN'}; const action = {type: 'RUN'};
state = initState() state = initState(2)
console.log(stateReducer(state, action).results)
expect(stateReducer(state, action).results).toEqual([ expect(stateReducer(state, action).results).toEqual([
{ {
pass: 'epoch 1', pass: 'epoch 1',
lexicon: [ lexicon: [
'anna', 'anat', 'anət', 'anna', 'tan', 'ənna' 'annɯ', 'anat', 'anət', 'annɯ', 'tan', 'ənnɯ'
] ]
} }
]); ]);
}); });
it('results returned through third sound change rule', () => {
const action = {type: 'RUN'};
state = initState(3)
expect(stateReducer(state, action).results).toEqual([
{
pass: 'epoch 1',
lexicon: [
'annɯ', 'anat', 'ant', 'annɯ', 'tan', 'nnɯ'
]
}
]);
});
// if('results returned from sound change suite', () => {
// const action = {type: 'RUN'};
// state = initState()
// console.log(stateReducer(state, action).results)
// expect(stateReducer(state, action).results).toEqual([
// {
// pass: 'epoch 1',
// lexicon: [
// 'anna', 'anta', 'anət', 'anna', 'tan', 'ənna'
// ]
// }
// ]);
// });
}); });