patch decomposeRules in results to process phoneme sequences

This commit is contained in:
Sorrel Bri 2020-02-13 23:40:34 -08:00
parent bcf79aa28c
commit 1b51405f02
3 changed files with 63 additions and 29 deletions

View file

@ -11,12 +11,12 @@ export const initState = (changesArgument: number = -1): stateType => {
{ {
name: 'epoch 1', name: 'epoch 1',
changes: [ changes: [
'[+ occlusive - nasal]>[+ occlusive nasal]/n_', '[+ occlusive - nasal]>[+ occlusive nasal]/n_.',
'at>ta/_#', 'at>ta/._#',
'[+ sonorant - low rounded high back]>_/_', '[+ 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]/._#'
] ]
} }
], ],

View file

@ -16,6 +16,15 @@ export type decomposedRulesType = [
} }
] ]
type ruleBundle = {
environment: {
pre: string,
position: string,
post: string
},
newFeatures: string
}
const findFeaturesFromLexeme = (phones: {}, lexeme:string): [] => { const findFeaturesFromLexeme = (phones: {}, lexeme:string): [] => {
let featureBundle = [] let featureBundle = []
let lastIndex = lexeme.length - 1; let lastIndex = lexeme.length - 1;
@ -54,10 +63,10 @@ const findFeaturesFromGrapheme = (phones: {}, lexeme:string): [] => {
return featureBundle; return featureBundle;
} }
const decomposeRule = (rule: string) => { const decomposeRule = (rule: string): ruleBundle => {
let decomposedChange = rule.split('>'); // splits rule at '>' '/' and '_' substrings resulting in array of length 4
decomposedChange = [decomposedChange[0], ...decomposedChange[1].split('/')] const decomposedChange = rule.split(/>|\/|_/g);
decomposedChange = [decomposedChange[0], decomposedChange[1], ...decomposedChange[2].split('_')];
const ruleBundle = { const ruleBundle = {
environment: { environment: {
pre: decomposedChange[2], pre: decomposedChange[2],
@ -71,16 +80,29 @@ const decomposeRule = (rule: string) => {
const mapStringToFeatures = (ruleString, phones) => { const mapStringToFeatures = (ruleString, phones) => {
if (ruleString) { if (ruleString) {
if (ruleString === '.') return [];
const ruleBrackets = ruleString.match(/\[.*\]/) const ruleBrackets = ruleString.match(/\[.*\]/)
if (ruleBrackets) { if (ruleBrackets) {
const ruleFeatures = ruleString.match(/(?!\[).*(?<!\])/)[0] const ruleFeatures = ruleString
const plusIndex = ruleFeatures.indexOf('+'); .split('[')
const minusIndex = ruleFeatures.indexOf('-'); // filter out empty strings
const positiveFeatures = ruleFeatures.slice(plusIndex + 1, minusIndex).trim().split(' '); .filter(v => v)
const positiveFeaturesMap = positiveFeatures.map(feature => ({[feature]: true})) .map((phoneme) => {
const negativeFeatures = ruleFeatures.slice(minusIndex +1).trim().split(' '); const positiveFeatures = phoneme.match(/(?=\+.).*(?<=\-)|(?=\+.).*(?!\-).*(?<=\])/g)
const negativeFeaturesMap = negativeFeatures.map(feature => ({[feature]: false})) const positiveFeaturesMap = positiveFeatures ? positiveFeatures[0]
.trim().match(/\w+/g)
.reduce((map, feature) => ({...map, [feature]: true}), {})
: {}
const negativeFeatures = phoneme.match(/(?=\-.).*(?<=\+)|(?=\-.).*(?!\+).*(?<=\])/g)
const negativeFeaturesMap = negativeFeatures ? negativeFeatures[0]
.trim().match(/\w+/g)
.reduce((map, feature) => ({...map, [feature]: false}), {})
: {}
return {...positiveFeaturesMap, ...negativeFeaturesMap} return {...positiveFeaturesMap, ...negativeFeaturesMap}
})
return ruleFeatures;
} }
const grapheme = ruleString; const grapheme = ruleString;
return findFeaturesFromGrapheme(phones, grapheme); return findFeaturesFromGrapheme(phones, grapheme);
@ -89,17 +111,12 @@ const mapStringToFeatures = (ruleString, phones) => {
} }
const mapRuleBundleToFeatureBundle = (ruleBundle, phones) => { const mapRuleBundleToFeatureBundle = (ruleBundle, phones) => {
// ! for each object in ruleBundle, map values to array of objects with feature-boolean key-value pairs // for each object in ruleBundle, map values to array of objects with feature-boolean key-value pairs
const featureBundle = {...ruleBundle}; const featureBundle = {...ruleBundle};
console.log(featureBundle)
featureBundle.environment.pre = mapStringToFeatures(featureBundle.environment.pre, phones); featureBundle.environment.pre = mapStringToFeatures(featureBundle.environment.pre, phones);
console.log(featureBundle.environment.pre)
featureBundle.environment.position = mapStringToFeatures(featureBundle.environment.position, phones); featureBundle.environment.position = mapStringToFeatures(featureBundle.environment.position, phones);
console.log(featureBundle.environment.position)
featureBundle.environment.post = mapStringToFeatures(featureBundle.environment.post, phones); featureBundle.environment.post = mapStringToFeatures(featureBundle.environment.post, phones);
console.log(featureBundle.environment.post)
featureBundle.newFeatures = mapStringToFeatures(featureBundle.newFeatures, phones); featureBundle.newFeatures = mapStringToFeatures(featureBundle.newFeatures, phones);
console.log(featureBundle.newFeatures)
return featureBundle; return featureBundle;
} }
@ -111,10 +128,27 @@ export const decomposeRules = (epoch: epochType, phones: {[key: string]: phoneTy
} }
export const run = (state: stateType, action: resultsAction): stateType => { export const run = (state: stateType, action: resultsAction): stateType => {
// ! one epoch only
// rule 0 '[+ occlusive - nasal]>[+ occlusive nasal]/n_' // for each epoch
// TODO iterate through each epoch
let ruleBundle = state.epochs[0].changes; let ruleBundle = state.epochs[0].changes;
// for each rule in epoch
ruleBundle = ruleBundle.map(rule => decomposeRule(rule)) ruleBundle = ruleBundle.map(rule => decomposeRule(rule))
// parse rule into feature bundles for
// environment
// pre-target
// post-target
// target
// mutation
// for each item in lexicon
// match targets in environments
// mutate target
// temporarily store lexical item
// store lexical items in resulting epoch
ruleBundle.map(rule => { ruleBundle.map(rule => {
rule.forEach(position => { rule.forEach(position => {

View file

@ -31,10 +31,10 @@ describe('Results', () => {
], ],
post: [], post: [],
}, },
newFeatures: {occlusive: true, nasal: true} newFeatures: [{occlusive: true, nasal: true}]
} }
]; ];
expect(decomposeRules(epoch, phones)).toBe(result); expect(decomposeRules(epoch, phones)).toStrictEqual(result);
}) })
// it('results returned from first sound change rule', () => { // it('results returned from first sound change rule', () => {