patch decomposeRules in results to process phoneme sequences
This commit is contained in:
parent
bcf79aa28c
commit
1b51405f02
3 changed files with 63 additions and 29 deletions
|
@ -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]/._#'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
@ -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 => {
|
||||||
|
|
|
@ -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', () => {
|
||||||
|
|
Loading…
Reference in a new issue